diff --git a/.gitignore b/.gitignore index 24a4b2512..da2a732f7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ bin # Temporary files for code generation tmp + +# application.yaml which contains a list of Application CRs for local testing. +application.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index c94d50451..98481ac3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan ### Added +- [#4](https://github.com/kobsio/kobs/pull/4): Add Custom Resource Definition for Applications. + ### Fixed - [#1](https://github.com/kobsio/kobs/pull/1): Fix mobile layout for the cluster and namespace filter by using a Toolbar instead of FlexItems. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f205ff67f..be1271813 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,6 +54,11 @@ chmod +x /usr/local/bin/protoc-gen-grpc-web go get google.golang.org/protobuf/cmd/protoc-gen-go@v1.25.0 go get google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1.0 go get istio.io/tools/cmd/protoc-gen-deepcopy@v0.0.0-20210206003203-61eabd18b4e0 +``` + +- Install the Kubernetes [code-generator](https://github.com/kubernetes/code-generator) into your `GOPATH`: + +```sh go get k8s.io/code-generator@v0.20.2 ``` diff --git a/Makefile b/Makefile index 2549543c3..7da8248d6 100644 --- a/Makefile +++ b/Makefile @@ -20,19 +20,26 @@ generate: generate-proto generate-crd .PHONY: generate-proto generate-proto: @protoc --proto_path=proto --go_out=pkg/generated/proto --go_opt=paths=source_relative --go-grpc_out=pkg/generated/proto --go-grpc_opt=paths=source_relative --deepcopy_out=pkg/generated/proto --js_out=import_style=commonjs:app/src/generated/proto --plugin=protoc-gen-ts=app/node_modules/.bin/protoc-gen-ts --ts_out=service=grpc-web:app/src/generated/proto --grpc-web_out=import_style=commonjs,mode=grpcwebtext:app/src/generated/proto proto/clusters.proto + @protoc --proto_path=proto --go_out=pkg/generated/proto --go_opt=paths=source_relative --go-grpc_out=pkg/generated/proto --go-grpc_opt=paths=source_relative --deepcopy_out=pkg/generated/proto --js_out=import_style=commonjs:app/src/generated/proto --plugin=protoc-gen-ts=app/node_modules/.bin/protoc-gen-ts --ts_out=service=grpc-web:app/src/generated/proto --grpc-web_out=import_style=commonjs,mode=grpcwebtext:app/src/generated/proto proto/applications.proto @rm -rf ./pkg/generated/proto/clusters_deepcopy.gen.go + @rm -rf ./pkg/generated/proto/applications_deepcopy.gen.go @mv ./pkg/generated/proto/github.com/kobsio/kobs/pkg/generated/proto/clusters_deepcopy.gen.go ./pkg/generated/proto + @mv ./pkg/generated/proto/github.com/kobsio/kobs/pkg/generated/proto/applications_deepcopy.gen.go ./pkg/generated/proto @rm -rf ./pkg/generated/proto/github.com .PHONY: generate-crd generate-crd: - @${GOPATH}/src/k8s.io/code-generator/generate-groups.sh "deepcopy,client,informer,lister" github.com/kobsio/kobs/pkg/generated github.com/kobsio/kobs/pkg/apis application:v1alpha1 --output-base ./tmp - @rm -rf ./pkg/apis/application/v1alpha1/zz_generated.deepcopy.go - @rm -rf ./pkg/generated - @mv ./tmp/github.com/kobsio/kobs/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go ./pkg/apis/application/v1alpha1 - @mv ./tmp/github.com/kobsio/kobs/pkg/generated ./pkg + @${GOPATH}/src/k8s.io/code-generator/generate-groups.sh "deepcopy,client,informer,lister" github.com/kobsio/kobs/pkg/generated github.com/kobsio/kobs/pkg/api/kubernetes/apis application:v1alpha1 --output-base ./tmp + @rm -rf ./pkg/api/kubernetes/apis/application/v1alpha1/zz_generated.deepcopy.go + @rm -rf ./pkg/generated/clientset + @rm -rf ./pkg/generated/informers + @rm -rf ./pkg/generated/listers + @mv ./tmp/github.com/kobsio/kobs/pkg/api/kubernetes/apis/application/v1alpha1/zz_generated.deepcopy.go ./pkg/api/kubernetes/apis/application/v1alpha1 + @mv ./tmp/github.com/kobsio/kobs/pkg/generated/clientset ./pkg/generated/clientset + @mv ./tmp/github.com/kobsio/kobs/pkg/generated/informers ./pkg/generated/informers + @mv ./tmp/github.com/kobsio/kobs/pkg/generated/listers ./pkg/generated/listers @rm -rf ./tmp - -controller-gen "crd:trivialVersions=true" paths="./..." output:crd:artifacts:config=deploy/crds + -controller-gen "crd:trivialVersions=true" paths="./..." output:crd:artifacts:config=deploy/kustomize/crds .PHONY: release-major release-major: diff --git a/app/package.json b/app/package.json index 2ac45697d..f01d32f78 100644 --- a/app/package.json +++ b/app/package.json @@ -32,7 +32,16 @@ "@typescript-eslint/no-explicit-any": "error", "@typescript-eslint/no-non-null-assertion": "error", "@typescript-eslint/no-unused-vars": "error", - "@typescript-eslint/no-use-before-define": "off" + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/naming-convention": [ + "error", + {"format": ["camelCase"], "selector": "default", "leadingUnderscore": "forbid", "trailingUnderscore": "forbid"}, + {"format": ["camelCase", "UPPER_CASE", "PascalCase"], "selector": "variable", "leadingUnderscore": "forbid", "trailingUnderscore": "forbid"}, + {"format": ["camelCase", "UPPER_CASE", "PascalCase"], "selector": "property", "leadingUnderscore": "forbid", "trailingUnderscore": "forbid"}, + {"format": ["PascalCase"], "selector": "interface", "leadingUnderscore": "forbid", "trailingUnderscore": "forbid", "prefix": ["I"]}, + {"format": ["PascalCase"], "selector": "typeAlias", "leadingUnderscore": "forbid", "trailingUnderscore": "forbid"}, + {"format": ["PascalCase"], "selector": "typeParameter", "leadingUnderscore": "forbid", "trailingUnderscore": "forbid"} + ] } }, "prettier": { diff --git a/app/src/App.tsx b/app/src/App.tsx index b4d8ff90b..c6b4985f4 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -6,23 +6,26 @@ import '@patternfly/react-core/dist/styles/base.css'; import '@patternfly/patternfly/patternfly.css'; import '@patternfly/patternfly/patternfly-addons.css'; -import Applications from './components/applications/Applications'; -import Logo from './components/menu/Logo'; -import Overview from './components/overview/Overview'; -import Resources from './components/resources/Resources'; +import Application from 'components/applications/Application'; +import Applications from 'components/applications/Applications'; +import HeaderLogo from 'components/shared/HeaderLogo'; +import Overview from 'components/overview/Overview'; +import Resources from 'components/resources/Resources'; -import './app.css'; +import 'app.css'; +// App is used to set all routes for the react-router and the header for all pages. const App: React.FunctionComponent = () => { - const Header = } />; + const Header = } />; return ( - - - + + + + diff --git a/app/src/app.css b/app/src/app.css index 6700fd827..63e0cfade 100644 --- a/app/src/app.css +++ b/app/src/app.css @@ -25,9 +25,11 @@ padding: 0; } -/* kobs-code - * Set the maximum width to the width of the parend component and the scrolling bahaviour, when we display code. */ -.kobs-code { +/* kobs-drawer-panel-body + * Is used to modify the style of the drawer panel body. For example we have to set the maximum width for tabs used + * within the drawer and apply some margin for the top and bottom of the tabs content. */ +.kobs-drawer-panel-body .pf-c-tab-content { + margin: 16px 0px; max-width: 100%; overflow-x: scroll; } diff --git a/app/src/components/applications/Application.tsx b/app/src/components/applications/Application.tsx new file mode 100644 index 000000000..fd05c717c --- /dev/null +++ b/app/src/components/applications/Application.tsx @@ -0,0 +1,141 @@ +import { + Alert, + AlertActionLink, + AlertVariant, + List, + ListItem, + ListVariant, + PageSection, + PageSectionVariants, + Tab, + TabContent, + TabTitleText, + Tabs, +} from '@patternfly/react-core'; +import { Link, useHistory, useParams } from 'react-router-dom'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; + +import { GetApplicationRequest, GetApplicationResponse } from 'generated/proto/clusters_pb'; +import { Application } from 'generated/proto/applications_pb'; +import { ClustersPromiseClient } from 'generated/proto/clusters_grpc_web_pb'; +import Resources from 'components/applications/details/resources/Resources'; +import Title from 'components/shared/Title'; +import { apiURL } from 'utils/constants'; + +const clustersService = new ClustersPromiseClient(apiURL, null, null); + +interface IApplicationsParams { + cluster: string; + namespace: string; + name: string; +} + +// Applications is the page component to show a single application. The application is determined by the provided page +// params. When the application could not be loaded an error is shown. If the application was successfully loaded, we +// show the same components as in the tabs from the Applications drawer. +const Applications: React.FunctionComponent = () => { + const history = useHistory(); + const params = useParams(); + const [application, setApplication] = useState(undefined); + const [error, setError] = useState(''); + const [activeTabKey, setActiveTabKey] = useState('resources'); + const refResourcesContent = useRef(null); + + const goToOverview = (): void => { + history.push('/'); + }; + + // fetchApplication is used to fetch the application from the gRPC API. This is done every time the page paramertes + // change. When there is an error during the fetch, the user will see the error. + const fetchApplication = useCallback(async () => { + try { + const getApplicationRequest = new GetApplicationRequest(); + getApplicationRequest.setCluster(params.cluster); + getApplicationRequest.setNamespace(params.namespace); + getApplicationRequest.setName(params.name); + + const getApplicationsResponse: GetApplicationResponse = await clustersService.getApplication( + getApplicationRequest, + null, + ); + + setError(''); + setApplication(getApplicationsResponse.getApplication()); + } catch (err) { + setError(err.message); + } + }, [params.cluster, params.namespace, params.name]); + + useEffect(() => { + fetchApplication(); + }, [fetchApplication]); + + if (!application) { + return null; + } + + // If there is an error, we will show it to the user. The user then has the option to retry the failed API call or to + // go to the overview page. + if (error) { + return ( + + + Retry + Overview + + } + > +

{error}

+
+
+ ); + } + + return ( + + + + <List variant={ListVariant.inline}> + {application.getLinksList().map((link, index) => ( + <ListItem key={index}> + <Link target="_blank" to={link.getLink}> + {link.getTitle()} + </Link> + </ListItem> + ))} + </List> + <Tabs + className="pf-u-mt-md" + mountOnEnter={true} + isFilled={true} + activeKey={activeTabKey} + onSelect={(event, tabIndex): void => setActiveTabKey(tabIndex.toString())} + > + <Tab + eventKey="resources" + title={<TabTitleText>Resources</TabTitleText>} + tabContentId="refResources" + tabContentRef={refResourcesContent} + /> + </Tabs> + </PageSection> + + <PageSection variant={PageSectionVariants.default}> + <TabContent eventKey={0} id="refResources" ref={refResourcesContent} aria-label="Resources"> + <Resources application={application} /> + </TabContent> + </PageSection> + </React.Fragment> + ); +}; + +export default Applications; diff --git a/app/src/components/applications/Applications.tsx b/app/src/components/applications/Applications.tsx index 31243d30f..69fa8adc5 100644 --- a/app/src/components/applications/Applications.tsx +++ b/app/src/components/applications/Applications.tsx @@ -1,13 +1,110 @@ -import { Gallery, GalleryItem, PageSection, PageSectionVariants } from '@patternfly/react-core'; -import React from 'react'; +import { + Alert, + AlertVariant, + Drawer, + DrawerContent, + DrawerContentBody, + Gallery, + GalleryItem, + PageSection, + PageSectionVariants, + Title, +} from '@patternfly/react-core'; +import React, { useState } from 'react'; +import { GetApplicationsRequest, GetApplicationsResponse } from 'generated/proto/clusters_pb'; +import { apiURL, applicationsDescription } from 'utils/constants'; +import { Application } from 'generated/proto/applications_pb'; +import Card from 'components/applications/details/Card'; +import { ClustersPromiseClient } from 'generated/proto/clusters_grpc_web_pb'; +import DrawerPanel from 'components/applications/details/DrawerPanel'; +import Filter from 'components/resources/shared/Filter'; + +const clustersService = new ClustersPromiseClient(apiURL, null, null); + +// Applications displays a list of applications (defined via the Application CRD). The applications can be filtered by +// cluster and namespace. +// When a application is selected it is shown in a drawer with some additional details, like resources, metrics, logs +// and traces. const Applications: React.FunctionComponent = () => { + const [applications, setApplications] = useState<Application[]>([]); + const [selectedApplication, setSelectedApplication] = useState<Application | undefined>(undefined); + const [error, setError] = useState<string>(''); + const [isLoading, setIsLoading] = useState<boolean>(false); + + // fetchApplications is the function to fetch all applications for a list of clusters and namespaces from the gRPC + // API. The function is used via the onFilter property of the Filter component. + const fetchApplications = async (clusters: string[], namespaces: string[]): Promise<void> => { + try { + if (clusters.length === 0 || namespaces.length === 0) { + throw new Error('You must select a cluster and a namespace'); + } else { + setIsLoading(true); + + const getApplicationsRequest = new GetApplicationsRequest(); + getApplicationsRequest.setClustersList(clusters); + getApplicationsRequest.setNamespacesList(namespaces); + + const getApplicationsResponse: GetApplicationsResponse = await clustersService.getApplications( + getApplicationsRequest, + null, + ); + + const tmpApplications = getApplicationsResponse.getApplicationsList(); + + if (tmpApplications.length > 0) { + setError(''); + setApplications(tmpApplications); + } else { + setError('No applications were found, adjust the cluster and namespace filter.'); + } + + setIsLoading(false); + } + } catch (err) { + setError(err.message); + setIsLoading(false); + } + }; + return ( - <PageSection variant={PageSectionVariants.default}> - <Gallery hasGutter={true}> - <GalleryItem>Applications</GalleryItem> - </Gallery> - </PageSection> + <React.Fragment> + <PageSection variant={PageSectionVariants.light}> + <Title headingLevel="h6" size="xl"> + Applications + +

{applicationsDescription}

+ +
+ + + setSelectedApplication(undefined)} /> + ) : undefined + } + > + + + {error ? ( + +

{error}

+
+ ) : ( + + {applications.map((application, index) => ( + + + + ))} + + )} +
+
+
+
+
); }; diff --git a/app/src/components/applications/details/Card.tsx b/app/src/components/applications/details/Card.tsx new file mode 100644 index 000000000..3abed08c8 --- /dev/null +++ b/app/src/components/applications/details/Card.tsx @@ -0,0 +1,25 @@ +import { CardBody, CardTitle, Card as PatternflyCard } from '@patternfly/react-core'; +import React from 'react'; + +import { Application } from 'generated/proto/applications_pb'; + +interface ICardProps { + application: Application; + select: (application: Application) => void; +} + +// Card displays a single application within the Applications gallery. The component requires the application and a +// select function as props. The select function is called, when the user clicks on the card. In the applications pages, +// this will then open the drawer with the selected application. +const Card: React.FunctionComponent = ({ application, select }: ICardProps) => { + return ( + select(application)}> + {application.getName()} + + {application.getCluster()} {application.getNamespace()} + + + ); +}; + +export default Card; diff --git a/app/src/components/applications/details/DrawerPanel.tsx b/app/src/components/applications/details/DrawerPanel.tsx new file mode 100644 index 000000000..2e10b60f2 --- /dev/null +++ b/app/src/components/applications/details/DrawerPanel.tsx @@ -0,0 +1,77 @@ +import { + DrawerActions, + DrawerCloseButton, + DrawerHead, + DrawerPanelBody, + DrawerPanelContent, + List, + ListItem, + ListVariant, + Tab, + TabTitleText, + Tabs, +} from '@patternfly/react-core'; +import React, { useState } from 'react'; +import { Link } from 'react-router-dom'; + +import { Application } from 'generated/proto/applications_pb'; +import Resources from 'components/applications/details/resources/Resources'; +import Title from 'components/shared/Title'; + +interface IDrawerPanelProps { + application: Application; + close: () => void; +} + +// DrawerPanel is the drawer panel for an application. It is used to display application details in the applications +// page. The details contains information for resources, metrics, logs and traces. +const DrawerPanel: React.FunctionComponent = ({ application, close }: IDrawerPanelProps) => { + const [activeTabKey, setActiveTabKey] = useState('resources'); + + return ( + + + + <DrawerActions className="kobs-drawer-actions"> + <DrawerCloseButton onClose={close} /> + </DrawerActions> + </DrawerHead> + + <DrawerPanelBody className="kobs-drawer-panel-body"> + <List variant={ListVariant.inline}> + <ListItem> + <Link + to={`/applications/${application.getCluster()}/${application.getNamespace()}/${application.getName()}`} + > + Details + </Link> + </ListItem> + {application.getLinksList().map((link, index) => ( + <ListItem key={index}> + <Link target="_blank" to={link.getLink}> + {link.getTitle()} + </Link> + </ListItem> + ))} + </List> + + <Tabs + mountOnEnter={true} + isFilled={true} + activeKey={activeTabKey} + onSelect={(event, tabIndex): void => setActiveTabKey(tabIndex.toString())} + > + <Tab eventKey="resources" title={<TabTitleText>Resources</TabTitleText>}> + <Resources application={application} /> + </Tab> + </Tabs> + </DrawerPanelBody> + </DrawerPanelContent> + ); +}; + +export default DrawerPanel; diff --git a/app/src/components/applications/details/NotDefined.tsx b/app/src/components/applications/details/NotDefined.tsx new file mode 100644 index 000000000..6e6506695 --- /dev/null +++ b/app/src/components/applications/details/NotDefined.tsx @@ -0,0 +1,34 @@ +import { Button, EmptyState, EmptyStateBody, EmptyStateIcon, Title } from '@patternfly/react-core'; +import React from 'react'; + +interface INotDefinedProps { + title: string; + description: string; + documentation: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + icon: React.ComponentType<any>; +} + +// NotDefined is the component, which is displayed when a component of an application isn't defined. It contains a +// title, description, icon and a link to the corresponding documentation. +const NotDefined: React.FunctionComponent<INotDefinedProps> = ({ + title, + description, + icon, + documentation, +}: INotDefinedProps) => { + return ( + <EmptyState> + <EmptyStateIcon icon={icon} /> + <Title headingLevel="h4" size="lg"> + {title} + + {description} + + + ); +}; + +export default NotDefined; diff --git a/app/src/components/applications/details/resources/Resource.tsx b/app/src/components/applications/details/resources/Resource.tsx new file mode 100644 index 000000000..3b609833a --- /dev/null +++ b/app/src/components/applications/details/resources/Resource.tsx @@ -0,0 +1,72 @@ +import { IRow, Table, TableBody, TableHeader } from '@patternfly/react-table'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; + +import { GetResourcesRequest, GetResourcesResponse } from 'generated/proto/clusters_pb'; +import { emptyState, resources } from 'components/resources/shared/helpers'; +import { ClustersPromiseClient } from 'generated/proto/clusters_grpc_web_pb'; +import { apiURL } from 'utils/constants'; + +const clustersService = new ClustersPromiseClient(apiURL, null, null); + +interface IResourceProps { + cluster: string; + namespace: string; + kind: string; + selector: string; +} + +// Resource loads a list of resources for an application and shows them in a table. If the list of loaded recources is +// zero, we will display an empty state. +const Resource: React.FunctionComponent = ({ cluster, namespace, kind, selector }: IResourceProps) => { + const columns = useMemo( + () => (resources.hasOwnProperty(kind) ? resources[kind].columns : ['Name', 'Namespace', 'Cluster']), + [kind], + ); + const [rows, setRows] = useState(emptyState(columns.length, '')); + + // fetchResources is used to get all resources from the gRPC API for an specific application. For that we have to set + // the cluster, namespace and name of the application. Besides that the CR also defines the kind which should be + // loaded and the labelSelector. + const fetchResources = useCallback(async () => { + try { + const getResourcesRequest = new GetResourcesRequest(); + getResourcesRequest.setClustersList([cluster]); + getResourcesRequest.setNamespacesList([namespace]); + getResourcesRequest.setPath(resources[kind].path); + getResourcesRequest.setResource(resources[kind].resource); + getResourcesRequest.setParamname('labelSelector'); + getResourcesRequest.setParam(selector); + + const getResourcesResponse: GetResourcesResponse = await clustersService.getResources(getResourcesRequest, null); + const tmpRows = resources[kind].rows(getResourcesResponse.getResourcesList()); + + if (tmpRows.length > 0) { + setRows(tmpRows); + } else { + setRows(emptyState(columns.length, '')); + } + } catch (err) { + setRows(emptyState(columns.length, err.message)); + } + }, [cluster, namespace, kind, selector, columns]); + + useEffect(() => { + fetchResources(); + }, [fetchResources]); + + return ( + + + +
+ ); +}; + +export default Resource; diff --git a/app/src/components/applications/details/resources/Resources.tsx b/app/src/components/applications/details/resources/Resources.tsx new file mode 100644 index 000000000..005772dd7 --- /dev/null +++ b/app/src/components/applications/details/resources/Resources.tsx @@ -0,0 +1,75 @@ +import { Accordion, AccordionContent, AccordionItem, AccordionToggle } from '@patternfly/react-core'; +import React, { useState } from 'react'; +import CubesIcon from '@patternfly/react-icons/dist/js/icons/cubes-icon'; + +import { Application } from 'generated/proto/applications_pb'; +import NotDefined from 'components/applications/details/NotDefined'; +import Resource from 'components/applications/details/resources/Resource'; +import { resources } from 'components/resources/shared/helpers'; + +interface IResourcesProps { + application: Application; +} + +// Resources is the component to show all resources, which are associated to the application. The resource are grouped +// by their kind in an accordion view. +const Resources: React.FunctionComponent = ({ application }: IResourcesProps) => { + const [expanded, setExpanded] = useState([]); + + // toogle is used to show / hide a selected kind. When the kind is already present in the expanded state array it will + // be removed. If not it will be added. + const toggle = (id: string): void => { + if (expanded.includes(id)) { + setExpanded(expanded.filter((item) => item !== id)); + } else { + setExpanded([...expanded, id]); + } + }; + + // If the length of the resource list is zero, we will show the NotDefined component, with a link to the documentation + // on how to define resources within the Application CR. + if (application.getResourcesList().length === 0) { + return ( + + ); + } + + return ( + + {application.getResourcesList().map((resource, i) => ( +
+ {resource.getKindsList().map((kind, j) => ( + + toggle(`resources-accordion-${i}-${j}`)} + isExpanded={expanded.includes(`resources-accordion-${i}-${j}`)} + id={`resources-toggle-${i}-${j}`} + > + {resources[kind].title} + + + + + + ))} +
+ ))} +
+ ); +}; + +export default Resources; diff --git a/app/src/components/menu/Logo.tsx b/app/src/components/menu/Logo.tsx deleted file mode 100644 index 18f88fd43..000000000 --- a/app/src/components/menu/Logo.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import { useHistory } from 'react-router-dom'; - -const Logo: React.FunctionComponent = () => { - const history = useHistory(); - - const handleClick = (): void => { - history.push('/'); - }; - - return kobs; -}; - -export default Logo; diff --git a/app/src/components/overview/Overview.tsx b/app/src/components/overview/Overview.tsx index 78dfdeb70..7cb8a0d53 100644 --- a/app/src/components/overview/Overview.tsx +++ b/app/src/components/overview/Overview.tsx @@ -1,12 +1,32 @@ import { Divider, Gallery, GalleryItem, PageSection, PageSectionVariants, Title } from '@patternfly/react-core'; import React from 'react'; -import Item from './Item'; -import { resources } from '../resources/helpers'; +import Item from 'components/overview/gallery/Item'; +import { applicationsDescription } from 'utils/constants'; +import { resources } from 'components/resources/shared/helpers'; +// Overview is the root component of kobs. It is used to render a list of pages, which can be used by the user. The +// items for the resources are generated with the help of all defined resources from the resouces/helpers file. +// The items for the gallery should always use the Item component, this will render a card, which are selectable. By a +// click on the item the user is navigated to the corresponding page. const Overview: React.FunctionComponent = () => { return ( + + + Applications + + + + + + + + + + + + Resources diff --git a/app/src/components/overview/Item.tsx b/app/src/components/overview/gallery/Item.tsx similarity index 63% rename from app/src/components/overview/Item.tsx rename to app/src/components/overview/gallery/Item.tsx index 9663ea1c0..7897e2061 100644 --- a/app/src/components/overview/Item.tsx +++ b/app/src/components/overview/gallery/Item.tsx @@ -2,13 +2,15 @@ import { Card, CardBody, CardTitle } from '@patternfly/react-core'; import React from 'react'; import { useHistory } from 'react-router-dom'; -interface ItemProps { +interface IItemProps { body: string; link: string; title: string; } -const Item: React.FunctionComponent<ItemProps> = ({ body, link, title }: ItemProps) => { +// Item is used to render an item in the overview page. It requires a title, body and a link. When the card is clicked, +// the user is redirected to the provided link. +const Item: React.FunctionComponent<IItemProps> = ({ body, link, title }: IItemProps) => { const history = useHistory(); const handleClick = (): void => { diff --git a/app/src/components/resources/Resources.tsx b/app/src/components/resources/Resources.tsx index 008e633ac..58a39ddbd 100644 --- a/app/src/components/resources/Resources.tsx +++ b/app/src/components/resources/Resources.tsx @@ -13,22 +13,28 @@ import { IRow, Table, TableBody, TableHeader } from '@patternfly/react-table'; import React, { useState } from 'react'; import { useHistory, useParams } from 'react-router-dom'; -import { GetResourcesRequest, GetResourcesResponse } from '../../generated/proto/clusters_pb'; -import { emptyState, resources } from './helpers'; -import { ClustersPromiseClient } from '../../generated/proto/clusters_grpc_web_pb'; -import Filter from './Filter'; -import Resource from './Resource'; -import { apiURL } from '../../utils/constants'; +import { GetResourcesRequest, GetResourcesResponse } from 'generated/proto/clusters_pb'; +import { emptyState, resources } from 'components/resources/shared/helpers'; +import { ClustersPromiseClient } from 'generated/proto/clusters_grpc_web_pb'; +import DrawerPanel from 'components/resources/drawer/DrawerPanel'; +import Filter from 'components/resources/shared/Filter'; +import { apiURL } from 'utils/constants'; const clustersService = new ClustersPromiseClient(apiURL, null, null); -interface ResourcesParams { +interface IResourcesParams { kind: string; } +// Resources is the page to display a table of resources for a list of clusters and namespaces. The resource is +// determined by the kind parameter from the URL. If the kind could not be found in the list of resources, we show the +// user an error. If the kind is valid the user can select a list of clusters and namespaces and gets a table with all +// matching resources as result. +// When the user selects a row with a resource a drawer for this resource is shown. The drawer contains the yaml +// manifest for this resource and a list of events. const Resources: React.FunctionComponent = () => { const history = useHistory(); - const params = useParams<ResourcesParams>(); + const params = useParams<IResourcesParams>(); const columns = resources.hasOwnProperty(params.kind) ? resources[params.kind].columns @@ -41,6 +47,9 @@ const Resources: React.FunctionComponent = () => { history.push('/'); }; + // fetchResources is the function to fetch all resources for a list of clusters and namespaces. The function is passed + // to the Filter component via the onFilter property. The returned items are converted into the IRow interface, which + // is then displayed in the Table component. const fetchResources = async (clusters: string[], namespaces: string[]): Promise<void> => { try { if (clusters.length === 0 || namespaces.length === 0) { @@ -74,6 +83,9 @@ const Resources: React.FunctionComponent = () => { } }; + // When the user doesn't provide a valid resource, we show an Alert. The alert contains a link to the overview page, + // so that the user can select a valid resource. Maybe we can also display a list of the most resources or resources + // which the user might have meant. if (!resources.hasOwnProperty(params.kind)) { return ( <PageSection variant={PageSectionVariants.default}> @@ -105,11 +117,7 @@ const Resources: React.FunctionComponent = () => { <DrawerContent panelContent={ selectedResource ? ( - <Resource - resource={selectedResource} - columns={columns} - close={(): void => setSelectedResource(undefined)} - /> + <DrawerPanel resource={selectedResource} close={(): void => setSelectedResource(undefined)} /> ) : undefined } > diff --git a/app/src/components/resources/Yaml.tsx b/app/src/components/resources/Yaml.tsx deleted file mode 100644 index 2782cfd62..000000000 --- a/app/src/components/resources/Yaml.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React, { useEffect, useRef } from 'react'; -import { highlightBlock, registerLanguage } from 'highlight.js'; -import yaml from 'highlight.js/lib/languages/yaml'; - -import 'highlight.js/styles/nord.css'; - -registerLanguage('yaml', yaml); - -interface ICodeProps { - yaml: string; -} - -const Yaml: React.FunctionComponent<ICodeProps> = ({ yaml }: ICodeProps) => { - const code = useRef<HTMLElement>(null); - - useEffect(() => { - if (code.current) { - highlightBlock(code.current); - } - }); - - return ( - <pre className="pf-u-pt-md pf-u-pb-md kobs-code"> - <code ref={code}>{yaml}</code> - </pre> - ); -}; - -export default Yaml; diff --git a/app/src/components/resources/Resource.tsx b/app/src/components/resources/drawer/DrawerPanel.tsx similarity index 58% rename from app/src/components/resources/Resource.tsx rename to app/src/components/resources/drawer/DrawerPanel.tsx index 6766753cb..7f00fac4c 100644 --- a/app/src/components/resources/Resource.tsx +++ b/app/src/components/resources/drawer/DrawerPanel.tsx @@ -12,34 +12,38 @@ import React, { useState } from 'react'; import { IRow } from '@patternfly/react-table'; import yaml from 'js-yaml'; -import Events from './Events'; -import Yaml from './Yaml'; +import Events from 'components/resources/drawer/Events'; +import Title from 'components/shared/Title'; +import Yaml from 'components/resources/drawer/Yaml'; interface IResourceProps { resource: IRow; - columns: string[]; close: () => void; } -const Resource: React.FunctionComponent<IResourceProps> = ({ resource, columns, close }: IResourceProps) => { +// DrawerPanel is the drawer panel component for the resources page. It is used to display a selected resource. The user +// can choose between different tabs: The "Yaml" tab displayes the yaml manifest for the selected resource and the +// "Events" tab displayes all events for the selected resource. The component also needs a close function, which is used +// to hide the drawer. +const DrawerPanel: React.FunctionComponent<IResourceProps> = ({ resource, close }: IResourceProps) => { const [activeTabKey, setActiveTabKey] = useState<string>('yaml'); return ( <DrawerPanelContent minSize="50%"> <DrawerHead> - <span> - <span className="pf-c-title pf-m-lg">{resource.name.title}</span> - <span className="pf-u-pl-sm pf-u-font-size-sm pf-u-color-200"> - {resource.namespace.title} ({resource.cluster.title}) - </span> - </span> + <Title + title={resource.name.title} + subtitle={`${resource.namespace.title} (${resource.cluster.title})`} + size="lg" + /> <DrawerActions className="kobs-drawer-actions"> - <DrawerCloseButton onClick={close} /> + <DrawerCloseButton onClose={close} /> </DrawerActions> </DrawerHead> <DrawerPanelBody className="kobs-drawer-panel-body"> <Tabs + mountOnEnter={true} isFilled={true} activeKey={activeTabKey} onSelect={(event, tabIndex): void => setActiveTabKey(tabIndex.toString())} @@ -56,4 +60,4 @@ const Resource: React.FunctionComponent<IResourceProps> = ({ resource, columns, ); }; -export default Resource; +export default DrawerPanel; diff --git a/app/src/components/resources/Events.tsx b/app/src/components/resources/drawer/Events.tsx similarity index 73% rename from app/src/components/resources/Events.tsx rename to app/src/components/resources/drawer/Events.tsx index 222aaae10..e00e5e2f2 100644 --- a/app/src/components/resources/Events.tsx +++ b/app/src/components/resources/drawer/Events.tsx @@ -15,14 +15,15 @@ import React, { useCallback, useEffect, useState } from 'react'; import { CoreV1EventList } from '@kubernetes/client-node'; import SearchIcon from '@patternfly/react-icons/dist/js/icons/search-icon'; -import { GetResourcesRequest, GetResourcesResponse } from '../../generated/proto/clusters_pb'; -import { ClustersPromiseClient } from '../../generated/proto/clusters_grpc_web_pb'; -import { apiURL } from '../../utils/constants'; -import { timeDifference } from '../../utils/helpers'; +import { GetResourcesRequest, GetResourcesResponse } from 'generated/proto/clusters_pb'; +import { ClustersPromiseClient } from 'generated/proto/clusters_grpc_web_pb'; +import { apiURL } from 'utils/constants'; +import { timeDifference } from 'utils/helpers'; const clustersService = new ClustersPromiseClient(apiURL, null, null); -const emptyState = [ +// noEventsState is used when the gRPC API call doesn't returned any events for the provided resource. +const noEventsState = [ { cells: [ { @@ -49,10 +50,14 @@ interface IEventsProps { name: string; } +// Events is the component to display the events for a resource. The resource is identified by the cluster, namespace +// and name. The event must contain the involvedObject.name=<NAME> to be listed for a resource. const Events: React.FunctionComponent<IEventsProps> = ({ cluster, namespace, name }: IEventsProps) => { const [error, setError] = useState<string>(''); - const [events, setEvents] = useState<IRow[]>(emptyState); + const [events, setEvents] = useState<IRow[]>(noEventsState); + // fetchEvents is used to fetch all events to the provided resource. When the API returnes a list of resources, this + // list is transformed into a the IRow interface, so we can display the events within the Table component. const fetchEvents = useCallback(async () => { try { const getResourcesRequest = new GetResourcesRequest(); @@ -83,7 +88,7 @@ const Events: React.FunctionComponent<IEventsProps> = ({ cluster, namespace, nam setEvents(tmpEvents); } else { - setEvents(emptyState); + setEvents(noEventsState); } } catch (err) { setError(err.message); @@ -94,9 +99,11 @@ const Events: React.FunctionComponent<IEventsProps> = ({ cluster, namespace, nam fetchEvents(); }, [fetchEvents]); + // When an error occurrs during the API call we show an Alert component, which the error message instead of the table. + // The alert also contains a retry button, so that a user can rerun the API call. if (error) { return ( - <Flex className="pf-u-pt-md pf-u-pb-md " direction={{ default: 'column' }}> + <Flex direction={{ default: 'column' }}> <FlexItem> <Alert variant={AlertVariant.danger} @@ -112,7 +119,7 @@ const Events: React.FunctionComponent<IEventsProps> = ({ cluster, namespace, nam } return ( - <Flex className="pf-u-mt-xl" direction={{ default: 'column' }}> + <Flex direction={{ default: 'column' }}> <FlexItem> <Table aria-label="events" diff --git a/app/src/components/resources/drawer/Yaml.tsx b/app/src/components/resources/drawer/Yaml.tsx new file mode 100644 index 000000000..8392cd83f --- /dev/null +++ b/app/src/components/resources/drawer/Yaml.tsx @@ -0,0 +1,33 @@ +import React, { useEffect, useRef } from 'react'; +import { highlightBlock, registerLanguage } from 'highlight.js'; +import yaml from 'highlight.js/lib/languages/yaml'; + +import 'highlight.js/styles/nord.css'; + +registerLanguage('yaml', yaml); + +interface IYamlProps { + yaml: string; +} + +// Yaml is the component to display the yaml manifest for a resource. For code highlighting we are using +// https://highlightjs.org, so that we have to register the yaml language first and we also have to import a theme. At +// the moment we are using Nord theme (https://www.nordtheme.com) provided by highlight.js, because it's my favorite +// editor theme. Maybe we can provide an option in the future, so that a user can select his own theme. +const Yaml: React.FunctionComponent<IYamlProps> = ({ yaml }: IYamlProps) => { + const code = useRef<HTMLElement>(null); + + useEffect(() => { + if (code.current) { + highlightBlock(code.current); + } + }); + + return ( + <pre className="pf-u-pb-md"> + <code ref={code}>{yaml}</code> + </pre> + ); +}; + +export default Yaml; diff --git a/app/src/components/resources/Filter.tsx b/app/src/components/resources/shared/Filter.tsx similarity index 79% rename from app/src/components/resources/Filter.tsx rename to app/src/components/resources/shared/Filter.tsx index f5208283d..6bbf2e013 100644 --- a/app/src/components/resources/Filter.tsx +++ b/app/src/components/resources/shared/Filter.tsx @@ -23,18 +23,21 @@ import { GetClustersResponse, GetNamespacesRequest, GetNamespacesResponse, -} from '../../generated/proto/clusters_pb'; -import { ClustersPromiseClient } from '../../generated/proto/clusters_grpc_web_pb'; -import { apiURL } from '../../utils/constants'; +} from 'generated/proto/clusters_pb'; +import { ClustersPromiseClient } from 'generated/proto/clusters_grpc_web_pb'; +import { apiURL } from 'utils/constants'; const clustersService = new ClustersPromiseClient(apiURL, null, null); -interface FilterProps { +interface IFilterProps { isLoading: boolean; onFilter: (clusters: string[], namespaces: string[]) => void; } -const Filter: React.FunctionComponent<FilterProps> = ({ isLoading, onFilter }: FilterProps) => { +// Filter is the component to display the cluster and namespace filter. It accepts a onFilter function, which is +// executed, when the user clicks the filter button. Besides this function is also accepts an loading identicator, which +// shows a spinner within the filter button, when it is true. +const Filter: React.FunctionComponent<IFilterProps> = ({ isLoading, onFilter }: IFilterProps) => { const [showClusters, setShowClusters] = useState<boolean>(false); const [showNamespaces, setShowNamespaces] = useState<boolean>(false); const [clusters, setClusters] = useState<string[]>([]); @@ -43,6 +46,8 @@ const Filter: React.FunctionComponent<FilterProps> = ({ isLoading, onFilter }: F const [selectedNamespaces, setSelectedNamespaces] = useState<string[]>([]); const [error, setError] = useState<string>(''); + // onSelectCluster is executed, when a cluster is selected. When the cluster isn't in the list of selected clusters, + // the cluster is added to this list. When the cluster is already in this list, it is removed. const onSelectCluster = (cluster: string): void => { if (selectedClusters.includes(cluster)) { setSelectedClusters(selectedClusters.filter((item) => item !== cluster)); @@ -51,6 +56,8 @@ const Filter: React.FunctionComponent<FilterProps> = ({ isLoading, onFilter }: F } }; + // onSelectNamespace is executed, when a namespace is selected. When the namespace isn't in the list of selected + // namespaces, the namespace is added to this list. When the namespace is already in this list, it is removed. const onSelectNamespace = (namespace: string): void => { if (selectedNamespaces.includes(namespace)) { setSelectedNamespaces(selectedNamespaces.filter((item) => item !== namespace)); @@ -59,6 +66,8 @@ const Filter: React.FunctionComponent<FilterProps> = ({ isLoading, onFilter }: F } }; + // getClusters is executed, when the component is rendered the first time. It is used to retrieve the complete list of + // clusters from the gRPC API. It also sets the first cluster from this list as the selected cluster. const getClusters = useCallback(async () => { try { const getClustersRequest = new GetClustersRequest(); @@ -76,6 +85,8 @@ const Filter: React.FunctionComponent<FilterProps> = ({ isLoading, onFilter }: F } }, []); + // getNamespaces is executed, when the list of selected clusters changed, to retrieve all namespaces for the list of + // selected clusters. const getNamespaces = useCallback(async () => { if (selectedClusters.length > 0) { try { @@ -111,6 +122,8 @@ const Filter: React.FunctionComponent<FilterProps> = ({ isLoading, onFilter }: F getNamespaces(); }, [getNamespaces]); + // When an error occured during the API calls, we render an Alert instead of the components for filtering. The alert + // component contains a link to retry the failed API call. if (error) { return ( <Flex className="pf-u-mt-md" direction={{ default: 'column' }}> diff --git a/app/src/components/resources/helpers.tsx b/app/src/components/resources/shared/helpers.tsx similarity index 92% rename from app/src/components/resources/helpers.tsx rename to app/src/components/resources/shared/helpers.tsx index 0b69dc906..2b3bec886 100644 --- a/app/src/components/resources/helpers.tsx +++ b/app/src/components/resources/shared/helpers.tsx @@ -12,14 +12,19 @@ import { IRow } from '@patternfly/react-table'; import React from 'react'; import SearchIcon from '@patternfly/react-icons/dist/js/icons/search-icon'; -import { Resources as ProtoResources } from '../../generated/proto/clusters_pb'; -import { timeDifference } from '../../utils/helpers'; +import { Resources as ProtoResources } from 'generated/proto/clusters_pb'; +import { timeDifference } from 'utils/helpers'; -interface Resources { - [key: string]: Resource; +// The IResources is a list of resources, which is supported by kobs. +interface IResources { + [key: string]: IResource; } -interface Resource { +// IResource is the interface, which must be implemented by each supported resource. Each resource must provid a list of +// columns and rows, which are used to render a table for this resource. It also must contain a title and description, +// which is displayed in the corresponding UI. To get the resources from the Kubernetes API for a cluster the resource +// must contain a path and a resource property. +interface IResource { columns: string[]; description: string; path: string; @@ -28,7 +33,10 @@ interface Resource { title: string; } -export const resources: Resources = { +// resources is the actual list of supported resources. To generate the rows for a resource, we have to pass the result +// from the gRPC API call to the rows function. The returned rows are mostly the same as they are also retunred by +// kubectl. +export const resources: IResources = { cronjobs: { columns: ['Name', 'Namespace', 'Cluster', 'Schedule', 'Suspend', 'Active', 'Last Schedule', 'Age'], description: 'A CronJob creates Jobs on a repeating schedule.', @@ -364,6 +372,8 @@ export const resources: Resources = { }, }; +// emptyState is used to display an empty state in the table for a resource, when the gRPC API call returned an error or +// no results. export const emptyState = (cols: number, error: string): IRow[] => { return [ { diff --git a/app/src/components/shared/HeaderLogo.tsx b/app/src/components/shared/HeaderLogo.tsx new file mode 100644 index 000000000..67fa76813 --- /dev/null +++ b/app/src/components/shared/HeaderLogo.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { useHistory } from 'react-router-dom'; + +// HeaderLogo provides the logo for the PageHeader, which is used within the App.tsx file for the header of kobs. When +// the logo is clicked the user can navigate to the overview page. +const HeaderLogo: React.FunctionComponent = () => { + const history = useHistory(); + + const handleClick = (): void => { + history.push('/'); + }; + + return <img src="/img/header-logo.png" onClick={handleClick} alt="kobs" />; +}; + +export default HeaderLogo; diff --git a/app/src/components/shared/Title.tsx b/app/src/components/shared/Title.tsx new file mode 100644 index 000000000..e49a86df9 --- /dev/null +++ b/app/src/components/shared/Title.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +type TTitleSize = 'lg' | 'xl'; + +interface ITitleProps { + title: string; + subtitle: string; + size: TTitleSize; +} + +// Title is our custom title component, in addition to the Patternfly Title component it also supports a subtitle. This +// is mostly used to display the namespace and cluster besides the name of a resource in the title. +const Title: React.FunctionComponent<ITitleProps> = ({ title, subtitle, size }: ITitleProps) => { + return ( + <span> + <span className={`pf-c-title pf-m-${size}`}>{title}</span> + <span className="pf-u-pl-sm pf-u-font-size-sm pf-u-color-200">{subtitle}</span> + </span> + ); +}; + +export default Title; diff --git a/app/src/generated/proto/applications_grpc_web_pb.js b/app/src/generated/proto/applications_grpc_web_pb.js new file mode 100644 index 000000000..b599064b7 --- /dev/null +++ b/app/src/generated/proto/applications_grpc_web_pb.js @@ -0,0 +1,234 @@ +/** + * @fileoverview gRPC-Web generated client stub for clusters + * @enhanceable + * @public + */ + +// GENERATED CODE -- DO NOT EDIT! + + +/* eslint-disable */ +// @ts-nocheck + + + +const grpc = {}; +grpc.web = require('grpc-web'); + +const proto = {}; +proto.clusters = require('./applications_pb.js'); + +/** + * @param {string} hostname + * @param {?Object} credentials + * @param {?Object} options + * @constructor + * @struct + * @final + */ +proto.clusters.ApplicationsClient = + function(hostname, credentials, options) { + if (!options) options = {}; + options['format'] = 'text'; + + /** + * @private @const {!grpc.web.GrpcWebClientBase} The client + */ + this.client_ = new grpc.web.GrpcWebClientBase(options); + + /** + * @private @const {string} The hostname + */ + this.hostname_ = hostname; + +}; + + +/** + * @param {string} hostname + * @param {?Object} credentials + * @param {?Object} options + * @constructor + * @struct + * @final + */ +proto.clusters.ApplicationsPromiseClient = + function(hostname, credentials, options) { + if (!options) options = {}; + options['format'] = 'text'; + + /** + * @private @const {!grpc.web.GrpcWebClientBase} The client + */ + this.client_ = new grpc.web.GrpcWebClientBase(options); + + /** + * @private @const {string} The hostname + */ + this.hostname_ = hostname; + +}; + + +/** + * @const + * @type {!grpc.web.MethodDescriptor< + * !proto.clusters.GetApplicationsRequest, + * !proto.clusters.GetApplicationsResponse>} + */ +const methodDescriptor_Applications_GetApplications = new grpc.web.MethodDescriptor( + '/clusters.Applications/GetApplications', + grpc.web.MethodType.UNARY, + proto.clusters.GetApplicationsRequest, + proto.clusters.GetApplicationsResponse, + /** + * @param {!proto.clusters.GetApplicationsRequest} request + * @return {!Uint8Array} + */ + function(request) { + return request.serializeBinary(); + }, + proto.clusters.GetApplicationsResponse.deserializeBinary +); + + +/** + * @const + * @type {!grpc.web.AbstractClientBase.MethodInfo< + * !proto.clusters.GetApplicationsRequest, + * !proto.clusters.GetApplicationsResponse>} + */ +const methodInfo_Applications_GetApplications = new grpc.web.AbstractClientBase.MethodInfo( + proto.clusters.GetApplicationsResponse, + /** + * @param {!proto.clusters.GetApplicationsRequest} request + * @return {!Uint8Array} + */ + function(request) { + return request.serializeBinary(); + }, + proto.clusters.GetApplicationsResponse.deserializeBinary +); + + +/** + * @param {!proto.clusters.GetApplicationsRequest} request The + * request proto + * @param {?Object<string, string>} metadata User defined + * call metadata + * @param {function(?grpc.web.Error, ?proto.clusters.GetApplicationsResponse)} + * callback The callback function(error, response) + * @return {!grpc.web.ClientReadableStream<!proto.clusters.GetApplicationsResponse>|undefined} + * The XHR Node Readable Stream + */ +proto.clusters.ApplicationsClient.prototype.getApplications = + function(request, metadata, callback) { + return this.client_.rpcCall(this.hostname_ + + '/clusters.Applications/GetApplications', + request, + metadata || {}, + methodDescriptor_Applications_GetApplications, + callback); +}; + + +/** + * @param {!proto.clusters.GetApplicationsRequest} request The + * request proto + * @param {?Object<string, string>} metadata User defined + * call metadata + * @return {!Promise<!proto.clusters.GetApplicationsResponse>} + * Promise that resolves to the response + */ +proto.clusters.ApplicationsPromiseClient.prototype.getApplications = + function(request, metadata) { + return this.client_.unaryCall(this.hostname_ + + '/clusters.Applications/GetApplications', + request, + metadata || {}, + methodDescriptor_Applications_GetApplications); +}; + + +/** + * @const + * @type {!grpc.web.MethodDescriptor< + * !proto.clusters.GetApplicationRequest, + * !proto.clusters.GetApplicationResponse>} + */ +const methodDescriptor_Applications_GetApplication = new grpc.web.MethodDescriptor( + '/clusters.Applications/GetApplication', + grpc.web.MethodType.UNARY, + proto.clusters.GetApplicationRequest, + proto.clusters.GetApplicationResponse, + /** + * @param {!proto.clusters.GetApplicationRequest} request + * @return {!Uint8Array} + */ + function(request) { + return request.serializeBinary(); + }, + proto.clusters.GetApplicationResponse.deserializeBinary +); + + +/** + * @const + * @type {!grpc.web.AbstractClientBase.MethodInfo< + * !proto.clusters.GetApplicationRequest, + * !proto.clusters.GetApplicationResponse>} + */ +const methodInfo_Applications_GetApplication = new grpc.web.AbstractClientBase.MethodInfo( + proto.clusters.GetApplicationResponse, + /** + * @param {!proto.clusters.GetApplicationRequest} request + * @return {!Uint8Array} + */ + function(request) { + return request.serializeBinary(); + }, + proto.clusters.GetApplicationResponse.deserializeBinary +); + + +/** + * @param {!proto.clusters.GetApplicationRequest} request The + * request proto + * @param {?Object<string, string>} metadata User defined + * call metadata + * @param {function(?grpc.web.Error, ?proto.clusters.GetApplicationResponse)} + * callback The callback function(error, response) + * @return {!grpc.web.ClientReadableStream<!proto.clusters.GetApplicationResponse>|undefined} + * The XHR Node Readable Stream + */ +proto.clusters.ApplicationsClient.prototype.getApplication = + function(request, metadata, callback) { + return this.client_.rpcCall(this.hostname_ + + '/clusters.Applications/GetApplication', + request, + metadata || {}, + methodDescriptor_Applications_GetApplication, + callback); +}; + + +/** + * @param {!proto.clusters.GetApplicationRequest} request The + * request proto + * @param {?Object<string, string>} metadata User defined + * call metadata + * @return {!Promise<!proto.clusters.GetApplicationResponse>} + * Promise that resolves to the response + */ +proto.clusters.ApplicationsPromiseClient.prototype.getApplication = + function(request, metadata) { + return this.client_.unaryCall(this.hostname_ + + '/clusters.Applications/GetApplication', + request, + metadata || {}, + methodDescriptor_Applications_GetApplication); +}; + + +module.exports = proto.clusters; + diff --git a/app/src/generated/proto/applications_pb.d.ts b/app/src/generated/proto/applications_pb.d.ts new file mode 100644 index 000000000..9b9ff420c --- /dev/null +++ b/app/src/generated/proto/applications_pb.d.ts @@ -0,0 +1,95 @@ +// package: clusters +// file: applications.proto + +import * as jspb from "google-protobuf"; + +export class Application extends jspb.Message { + getCluster(): string; + setCluster(value: string): void; + + getNamespace(): string; + setNamespace(value: string): void; + + getName(): string; + setName(value: string): void; + + clearLinksList(): void; + getLinksList(): Array<ApplicationLink>; + setLinksList(value: Array<ApplicationLink>): void; + addLinks(value?: ApplicationLink, index?: number): ApplicationLink; + + clearResourcesList(): void; + getResourcesList(): Array<ApplicationResources>; + setResourcesList(value: Array<ApplicationResources>): void; + addResources(value?: ApplicationResources, index?: number): ApplicationResources; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): Application.AsObject; + static toObject(includeInstance: boolean, msg: Application): Application.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; + static serializeBinaryToWriter(message: Application, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): Application; + static deserializeBinaryFromReader(message: Application, reader: jspb.BinaryReader): Application; +} + +export namespace Application { + export type AsObject = { + cluster: string, + namespace: string, + name: string, + linksList: Array<ApplicationLink.AsObject>, + resourcesList: Array<ApplicationResources.AsObject>, + } +} + +export class ApplicationLink extends jspb.Message { + getTitle(): string; + setTitle(value: string): void; + + getLink(): string; + setLink(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): ApplicationLink.AsObject; + static toObject(includeInstance: boolean, msg: ApplicationLink): ApplicationLink.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; + static serializeBinaryToWriter(message: ApplicationLink, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): ApplicationLink; + static deserializeBinaryFromReader(message: ApplicationLink, reader: jspb.BinaryReader): ApplicationLink; +} + +export namespace ApplicationLink { + export type AsObject = { + title: string, + link: string, + } +} + +export class ApplicationResources extends jspb.Message { + clearKindsList(): void; + getKindsList(): Array<string>; + setKindsList(value: Array<string>): void; + addKinds(value: string, index?: number): string; + + getSelector(): string; + setSelector(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): ApplicationResources.AsObject; + static toObject(includeInstance: boolean, msg: ApplicationResources): ApplicationResources.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; + static serializeBinaryToWriter(message: ApplicationResources, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): ApplicationResources; + static deserializeBinaryFromReader(message: ApplicationResources, reader: jspb.BinaryReader): ApplicationResources; +} + +export namespace ApplicationResources { + export type AsObject = { + kindsList: Array<string>, + selector: string, + } +} + diff --git a/app/src/generated/proto/applications_pb.js b/app/src/generated/proto/applications_pb.js new file mode 100644 index 000000000..ca3c4caac --- /dev/null +++ b/app/src/generated/proto/applications_pb.js @@ -0,0 +1,732 @@ +// source: applications.proto +/** + * @fileoverview + * @enhanceable + * @suppress {messageConventions} JS Compiler reports an error if a variable or + * field starts with 'MSG_' and isn't a translatable message. + * @public + */ +// GENERATED CODE -- DO NOT EDIT! +/* eslint-disable */ +// @ts-nocheck + +var jspb = require('google-protobuf'); +var goog = jspb; +var global = Function('return this')(); + +goog.exportSymbol('proto.clusters.Application', null, global); +goog.exportSymbol('proto.clusters.ApplicationLink', null, global); +goog.exportSymbol('proto.clusters.ApplicationResources', null, global); +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.clusters.Application = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.clusters.Application.repeatedFields_, null); +}; +goog.inherits(proto.clusters.Application, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.clusters.Application.displayName = 'proto.clusters.Application'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.clusters.ApplicationLink = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.clusters.ApplicationLink, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.clusters.ApplicationLink.displayName = 'proto.clusters.ApplicationLink'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.clusters.ApplicationResources = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.clusters.ApplicationResources.repeatedFields_, null); +}; +goog.inherits(proto.clusters.ApplicationResources, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.clusters.ApplicationResources.displayName = 'proto.clusters.ApplicationResources'; +} + +/** + * List of repeated fields within this message type. + * @private {!Array<number>} + * @const + */ +proto.clusters.Application.repeatedFields_ = [4,5]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.clusters.Application.prototype.toObject = function(opt_includeInstance) { + return proto.clusters.Application.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.clusters.Application} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.Application.toObject = function(includeInstance, msg) { + var f, obj = { + cluster: jspb.Message.getFieldWithDefault(msg, 1, ""), + namespace: jspb.Message.getFieldWithDefault(msg, 2, ""), + name: jspb.Message.getFieldWithDefault(msg, 3, ""), + linksList: jspb.Message.toObjectList(msg.getLinksList(), + proto.clusters.ApplicationLink.toObject, includeInstance), + resourcesList: jspb.Message.toObjectList(msg.getResourcesList(), + proto.clusters.ApplicationResources.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.clusters.Application} + */ +proto.clusters.Application.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.clusters.Application; + return proto.clusters.Application.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.clusters.Application} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.clusters.Application} + */ +proto.clusters.Application.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setCluster(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setNamespace(value); + break; + case 3: + var value = /** @type {string} */ (reader.readString()); + msg.setName(value); + break; + case 4: + var value = new proto.clusters.ApplicationLink; + reader.readMessage(value,proto.clusters.ApplicationLink.deserializeBinaryFromReader); + msg.addLinks(value); + break; + case 5: + var value = new proto.clusters.ApplicationResources; + reader.readMessage(value,proto.clusters.ApplicationResources.deserializeBinaryFromReader); + msg.addResources(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.clusters.Application.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.clusters.Application.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.clusters.Application} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.Application.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getCluster(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getNamespace(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } + f = message.getName(); + if (f.length > 0) { + writer.writeString( + 3, + f + ); + } + f = message.getLinksList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 4, + f, + proto.clusters.ApplicationLink.serializeBinaryToWriter + ); + } + f = message.getResourcesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 5, + f, + proto.clusters.ApplicationResources.serializeBinaryToWriter + ); + } +}; + + +/** + * optional string cluster = 1; + * @return {string} + */ +proto.clusters.Application.prototype.getCluster = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.clusters.Application} returns this + */ +proto.clusters.Application.prototype.setCluster = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional string namespace = 2; + * @return {string} + */ +proto.clusters.Application.prototype.getNamespace = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.clusters.Application} returns this + */ +proto.clusters.Application.prototype.setNamespace = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); +}; + + +/** + * optional string name = 3; + * @return {string} + */ +proto.clusters.Application.prototype.getName = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); +}; + + +/** + * @param {string} value + * @return {!proto.clusters.Application} returns this + */ +proto.clusters.Application.prototype.setName = function(value) { + return jspb.Message.setProto3StringField(this, 3, value); +}; + + +/** + * repeated ApplicationLink links = 4; + * @return {!Array<!proto.clusters.ApplicationLink>} + */ +proto.clusters.Application.prototype.getLinksList = function() { + return /** @type{!Array<!proto.clusters.ApplicationLink>} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.clusters.ApplicationLink, 4)); +}; + + +/** + * @param {!Array<!proto.clusters.ApplicationLink>} value + * @return {!proto.clusters.Application} returns this +*/ +proto.clusters.Application.prototype.setLinksList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 4, value); +}; + + +/** + * @param {!proto.clusters.ApplicationLink=} opt_value + * @param {number=} opt_index + * @return {!proto.clusters.ApplicationLink} + */ +proto.clusters.Application.prototype.addLinks = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 4, opt_value, proto.clusters.ApplicationLink, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.clusters.Application} returns this + */ +proto.clusters.Application.prototype.clearLinksList = function() { + return this.setLinksList([]); +}; + + +/** + * repeated ApplicationResources resources = 5; + * @return {!Array<!proto.clusters.ApplicationResources>} + */ +proto.clusters.Application.prototype.getResourcesList = function() { + return /** @type{!Array<!proto.clusters.ApplicationResources>} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.clusters.ApplicationResources, 5)); +}; + + +/** + * @param {!Array<!proto.clusters.ApplicationResources>} value + * @return {!proto.clusters.Application} returns this +*/ +proto.clusters.Application.prototype.setResourcesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 5, value); +}; + + +/** + * @param {!proto.clusters.ApplicationResources=} opt_value + * @param {number=} opt_index + * @return {!proto.clusters.ApplicationResources} + */ +proto.clusters.Application.prototype.addResources = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 5, opt_value, proto.clusters.ApplicationResources, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.clusters.Application} returns this + */ +proto.clusters.Application.prototype.clearResourcesList = function() { + return this.setResourcesList([]); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.clusters.ApplicationLink.prototype.toObject = function(opt_includeInstance) { + return proto.clusters.ApplicationLink.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.clusters.ApplicationLink} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.ApplicationLink.toObject = function(includeInstance, msg) { + var f, obj = { + title: jspb.Message.getFieldWithDefault(msg, 1, ""), + link: jspb.Message.getFieldWithDefault(msg, 2, "") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.clusters.ApplicationLink} + */ +proto.clusters.ApplicationLink.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.clusters.ApplicationLink; + return proto.clusters.ApplicationLink.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.clusters.ApplicationLink} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.clusters.ApplicationLink} + */ +proto.clusters.ApplicationLink.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setTitle(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setLink(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.clusters.ApplicationLink.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.clusters.ApplicationLink.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.clusters.ApplicationLink} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.ApplicationLink.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getTitle(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getLink(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } +}; + + +/** + * optional string title = 1; + * @return {string} + */ +proto.clusters.ApplicationLink.prototype.getTitle = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.clusters.ApplicationLink} returns this + */ +proto.clusters.ApplicationLink.prototype.setTitle = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional string link = 2; + * @return {string} + */ +proto.clusters.ApplicationLink.prototype.getLink = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.clusters.ApplicationLink} returns this + */ +proto.clusters.ApplicationLink.prototype.setLink = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array<number>} + * @const + */ +proto.clusters.ApplicationResources.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.clusters.ApplicationResources.prototype.toObject = function(opt_includeInstance) { + return proto.clusters.ApplicationResources.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.clusters.ApplicationResources} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.ApplicationResources.toObject = function(includeInstance, msg) { + var f, obj = { + kindsList: (f = jspb.Message.getRepeatedField(msg, 1)) == null ? undefined : f, + selector: jspb.Message.getFieldWithDefault(msg, 2, "") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.clusters.ApplicationResources} + */ +proto.clusters.ApplicationResources.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.clusters.ApplicationResources; + return proto.clusters.ApplicationResources.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.clusters.ApplicationResources} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.clusters.ApplicationResources} + */ +proto.clusters.ApplicationResources.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.addKinds(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setSelector(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.clusters.ApplicationResources.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.clusters.ApplicationResources.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.clusters.ApplicationResources} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.ApplicationResources.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getKindsList(); + if (f.length > 0) { + writer.writeRepeatedString( + 1, + f + ); + } + f = message.getSelector(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } +}; + + +/** + * repeated string kinds = 1; + * @return {!Array<string>} + */ +proto.clusters.ApplicationResources.prototype.getKindsList = function() { + return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** + * @param {!Array<string>} value + * @return {!proto.clusters.ApplicationResources} returns this + */ +proto.clusters.ApplicationResources.prototype.setKindsList = function(value) { + return jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + * @return {!proto.clusters.ApplicationResources} returns this + */ +proto.clusters.ApplicationResources.prototype.addKinds = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.clusters.ApplicationResources} returns this + */ +proto.clusters.ApplicationResources.prototype.clearKindsList = function() { + return this.setKindsList([]); +}; + + +/** + * optional string selector = 2; + * @return {string} + */ +proto.clusters.ApplicationResources.prototype.getSelector = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.clusters.ApplicationResources} returns this + */ +proto.clusters.ApplicationResources.prototype.setSelector = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); +}; + + +goog.object.extend(exports, proto.clusters); diff --git a/app/src/generated/proto/applications_pb_service.d.ts b/app/src/generated/proto/applications_pb_service.d.ts new file mode 100644 index 000000000..14b72579b --- /dev/null +++ b/app/src/generated/proto/applications_pb_service.d.ts @@ -0,0 +1,3 @@ +// package: clusters +// file: applications.proto + diff --git a/app/src/generated/proto/applications_pb_service.js b/app/src/generated/proto/applications_pb_service.js new file mode 100644 index 000000000..14b72579b --- /dev/null +++ b/app/src/generated/proto/applications_pb_service.js @@ -0,0 +1,3 @@ +// package: clusters +// file: applications.proto + diff --git a/app/src/generated/proto/clusters_grpc_web_pb.js b/app/src/generated/proto/clusters_grpc_web_pb.js index f3fd601fe..92ececac8 100644 --- a/app/src/generated/proto/clusters_grpc_web_pb.js +++ b/app/src/generated/proto/clusters_grpc_web_pb.js @@ -15,6 +15,8 @@ const grpc = {}; grpc.web = require('grpc-web'); + +var applications_pb = require('./applications_pb.js') const proto = {}; proto.clusters = require('./clusters_pb.js'); @@ -310,5 +312,165 @@ proto.clusters.ClustersPromiseClient.prototype.getResources = }; +/** + * @const + * @type {!grpc.web.MethodDescriptor< + * !proto.clusters.GetApplicationsRequest, + * !proto.clusters.GetApplicationsResponse>} + */ +const methodDescriptor_Clusters_GetApplications = new grpc.web.MethodDescriptor( + '/clusters.Clusters/GetApplications', + grpc.web.MethodType.UNARY, + proto.clusters.GetApplicationsRequest, + proto.clusters.GetApplicationsResponse, + /** + * @param {!proto.clusters.GetApplicationsRequest} request + * @return {!Uint8Array} + */ + function(request) { + return request.serializeBinary(); + }, + proto.clusters.GetApplicationsResponse.deserializeBinary +); + + +/** + * @const + * @type {!grpc.web.AbstractClientBase.MethodInfo< + * !proto.clusters.GetApplicationsRequest, + * !proto.clusters.GetApplicationsResponse>} + */ +const methodInfo_Clusters_GetApplications = new grpc.web.AbstractClientBase.MethodInfo( + proto.clusters.GetApplicationsResponse, + /** + * @param {!proto.clusters.GetApplicationsRequest} request + * @return {!Uint8Array} + */ + function(request) { + return request.serializeBinary(); + }, + proto.clusters.GetApplicationsResponse.deserializeBinary +); + + +/** + * @param {!proto.clusters.GetApplicationsRequest} request The + * request proto + * @param {?Object<string, string>} metadata User defined + * call metadata + * @param {function(?grpc.web.Error, ?proto.clusters.GetApplicationsResponse)} + * callback The callback function(error, response) + * @return {!grpc.web.ClientReadableStream<!proto.clusters.GetApplicationsResponse>|undefined} + * The XHR Node Readable Stream + */ +proto.clusters.ClustersClient.prototype.getApplications = + function(request, metadata, callback) { + return this.client_.rpcCall(this.hostname_ + + '/clusters.Clusters/GetApplications', + request, + metadata || {}, + methodDescriptor_Clusters_GetApplications, + callback); +}; + + +/** + * @param {!proto.clusters.GetApplicationsRequest} request The + * request proto + * @param {?Object<string, string>} metadata User defined + * call metadata + * @return {!Promise<!proto.clusters.GetApplicationsResponse>} + * Promise that resolves to the response + */ +proto.clusters.ClustersPromiseClient.prototype.getApplications = + function(request, metadata) { + return this.client_.unaryCall(this.hostname_ + + '/clusters.Clusters/GetApplications', + request, + metadata || {}, + methodDescriptor_Clusters_GetApplications); +}; + + +/** + * @const + * @type {!grpc.web.MethodDescriptor< + * !proto.clusters.GetApplicationRequest, + * !proto.clusters.GetApplicationResponse>} + */ +const methodDescriptor_Clusters_GetApplication = new grpc.web.MethodDescriptor( + '/clusters.Clusters/GetApplication', + grpc.web.MethodType.UNARY, + proto.clusters.GetApplicationRequest, + proto.clusters.GetApplicationResponse, + /** + * @param {!proto.clusters.GetApplicationRequest} request + * @return {!Uint8Array} + */ + function(request) { + return request.serializeBinary(); + }, + proto.clusters.GetApplicationResponse.deserializeBinary +); + + +/** + * @const + * @type {!grpc.web.AbstractClientBase.MethodInfo< + * !proto.clusters.GetApplicationRequest, + * !proto.clusters.GetApplicationResponse>} + */ +const methodInfo_Clusters_GetApplication = new grpc.web.AbstractClientBase.MethodInfo( + proto.clusters.GetApplicationResponse, + /** + * @param {!proto.clusters.GetApplicationRequest} request + * @return {!Uint8Array} + */ + function(request) { + return request.serializeBinary(); + }, + proto.clusters.GetApplicationResponse.deserializeBinary +); + + +/** + * @param {!proto.clusters.GetApplicationRequest} request The + * request proto + * @param {?Object<string, string>} metadata User defined + * call metadata + * @param {function(?grpc.web.Error, ?proto.clusters.GetApplicationResponse)} + * callback The callback function(error, response) + * @return {!grpc.web.ClientReadableStream<!proto.clusters.GetApplicationResponse>|undefined} + * The XHR Node Readable Stream + */ +proto.clusters.ClustersClient.prototype.getApplication = + function(request, metadata, callback) { + return this.client_.rpcCall(this.hostname_ + + '/clusters.Clusters/GetApplication', + request, + metadata || {}, + methodDescriptor_Clusters_GetApplication, + callback); +}; + + +/** + * @param {!proto.clusters.GetApplicationRequest} request The + * request proto + * @param {?Object<string, string>} metadata User defined + * call metadata + * @return {!Promise<!proto.clusters.GetApplicationResponse>} + * Promise that resolves to the response + */ +proto.clusters.ClustersPromiseClient.prototype.getApplication = + function(request, metadata) { + return this.client_.unaryCall(this.hostname_ + + '/clusters.Clusters/GetApplication', + request, + metadata || {}, + methodDescriptor_Clusters_GetApplication); +}; + + module.exports = proto.clusters; diff --git a/app/src/generated/proto/clusters_pb.d.ts b/app/src/generated/proto/clusters_pb.d.ts index d8b3c33ce..6dd424baf 100644 --- a/app/src/generated/proto/clusters_pb.d.ts +++ b/app/src/generated/proto/clusters_pb.d.ts @@ -2,6 +2,7 @@ // file: clusters.proto import * as jspb from "google-protobuf"; +import * as applications_pb from "./applications_pb"; export class GetClustersRequest extends jspb.Message { serializeBinary(): Uint8Array; @@ -179,3 +180,103 @@ export namespace Resources { } } +export class GetApplicationsRequest extends jspb.Message { + clearClustersList(): void; + getClustersList(): Array<string>; + setClustersList(value: Array<string>): void; + addClusters(value: string, index?: number): string; + + clearNamespacesList(): void; + getNamespacesList(): Array<string>; + setNamespacesList(value: Array<string>): void; + addNamespaces(value: string, index?: number): string; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetApplicationsRequest.AsObject; + static toObject(includeInstance: boolean, msg: GetApplicationsRequest): GetApplicationsRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; + static serializeBinaryToWriter(message: GetApplicationsRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetApplicationsRequest; + static deserializeBinaryFromReader(message: GetApplicationsRequest, reader: jspb.BinaryReader): GetApplicationsRequest; +} + +export namespace GetApplicationsRequest { + export type AsObject = { + clustersList: Array<string>, + namespacesList: Array<string>, + } +} + +export class GetApplicationsResponse extends jspb.Message { + clearApplicationsList(): void; + getApplicationsList(): Array<applications_pb.Application>; + setApplicationsList(value: Array<applications_pb.Application>): void; + addApplications(value?: applications_pb.Application, index?: number): applications_pb.Application; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetApplicationsResponse.AsObject; + static toObject(includeInstance: boolean, msg: GetApplicationsResponse): GetApplicationsResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; + static serializeBinaryToWriter(message: GetApplicationsResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetApplicationsResponse; + static deserializeBinaryFromReader(message: GetApplicationsResponse, reader: jspb.BinaryReader): GetApplicationsResponse; +} + +export namespace GetApplicationsResponse { + export type AsObject = { + applicationsList: Array<applications_pb.Application.AsObject>, + } +} + +export class GetApplicationRequest extends jspb.Message { + getCluster(): string; + setCluster(value: string): void; + + getNamespace(): string; + setNamespace(value: string): void; + + getName(): string; + setName(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetApplicationRequest.AsObject; + static toObject(includeInstance: boolean, msg: GetApplicationRequest): GetApplicationRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; + static serializeBinaryToWriter(message: GetApplicationRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetApplicationRequest; + static deserializeBinaryFromReader(message: GetApplicationRequest, reader: jspb.BinaryReader): GetApplicationRequest; +} + +export namespace GetApplicationRequest { + export type AsObject = { + cluster: string, + namespace: string, + name: string, + } +} + +export class GetApplicationResponse extends jspb.Message { + hasApplication(): boolean; + clearApplication(): void; + getApplication(): applications_pb.Application | undefined; + setApplication(value?: applications_pb.Application): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetApplicationResponse.AsObject; + static toObject(includeInstance: boolean, msg: GetApplicationResponse): GetApplicationResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>}; + static serializeBinaryToWriter(message: GetApplicationResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetApplicationResponse; + static deserializeBinaryFromReader(message: GetApplicationResponse, reader: jspb.BinaryReader): GetApplicationResponse; +} + +export namespace GetApplicationResponse { + export type AsObject = { + application?: applications_pb.Application.AsObject, + } +} + diff --git a/app/src/generated/proto/clusters_pb.js b/app/src/generated/proto/clusters_pb.js index 1af7c9389..118ba6326 100644 --- a/app/src/generated/proto/clusters_pb.js +++ b/app/src/generated/proto/clusters_pb.js @@ -14,6 +14,12 @@ var jspb = require('google-protobuf'); var goog = jspb; var global = Function('return this')(); +var applications_pb = require('./applications_pb.js'); +goog.object.extend(proto, applications_pb); +goog.exportSymbol('proto.clusters.GetApplicationRequest', null, global); +goog.exportSymbol('proto.clusters.GetApplicationResponse', null, global); +goog.exportSymbol('proto.clusters.GetApplicationsRequest', null, global); +goog.exportSymbol('proto.clusters.GetApplicationsResponse', null, global); goog.exportSymbol('proto.clusters.GetClustersRequest', null, global); goog.exportSymbol('proto.clusters.GetClustersResponse', null, global); goog.exportSymbol('proto.clusters.GetNamespacesRequest', null, global); @@ -168,6 +174,90 @@ if (goog.DEBUG && !COMPILED) { */ proto.clusters.Resources.displayName = 'proto.clusters.Resources'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.clusters.GetApplicationsRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.clusters.GetApplicationsRequest.repeatedFields_, null); +}; +goog.inherits(proto.clusters.GetApplicationsRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.clusters.GetApplicationsRequest.displayName = 'proto.clusters.GetApplicationsRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.clusters.GetApplicationsResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.clusters.GetApplicationsResponse.repeatedFields_, null); +}; +goog.inherits(proto.clusters.GetApplicationsResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.clusters.GetApplicationsResponse.displayName = 'proto.clusters.GetApplicationsResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.clusters.GetApplicationRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.clusters.GetApplicationRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.clusters.GetApplicationRequest.displayName = 'proto.clusters.GetApplicationRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.clusters.GetApplicationResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.clusters.GetApplicationResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.clusters.GetApplicationResponse.displayName = 'proto.clusters.GetApplicationResponse'; +} @@ -1412,4 +1502,710 @@ proto.clusters.Resources.prototype.setResourcelist = function(value) { }; + +/** + * List of repeated fields within this message type. + * @private {!Array<number>} + * @const + */ +proto.clusters.GetApplicationsRequest.repeatedFields_ = [1,2]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.clusters.GetApplicationsRequest.prototype.toObject = function(opt_includeInstance) { + return proto.clusters.GetApplicationsRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.clusters.GetApplicationsRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.GetApplicationsRequest.toObject = function(includeInstance, msg) { + var f, obj = { + clustersList: (f = jspb.Message.getRepeatedField(msg, 1)) == null ? undefined : f, + namespacesList: (f = jspb.Message.getRepeatedField(msg, 2)) == null ? undefined : f + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.clusters.GetApplicationsRequest} + */ +proto.clusters.GetApplicationsRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.clusters.GetApplicationsRequest; + return proto.clusters.GetApplicationsRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.clusters.GetApplicationsRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.clusters.GetApplicationsRequest} + */ +proto.clusters.GetApplicationsRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.addClusters(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.addNamespaces(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.clusters.GetApplicationsRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.clusters.GetApplicationsRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.clusters.GetApplicationsRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.GetApplicationsRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getClustersList(); + if (f.length > 0) { + writer.writeRepeatedString( + 1, + f + ); + } + f = message.getNamespacesList(); + if (f.length > 0) { + writer.writeRepeatedString( + 2, + f + ); + } +}; + + +/** + * repeated string clusters = 1; + * @return {!Array<string>} + */ +proto.clusters.GetApplicationsRequest.prototype.getClustersList = function() { + return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** + * @param {!Array<string>} value + * @return {!proto.clusters.GetApplicationsRequest} returns this + */ +proto.clusters.GetApplicationsRequest.prototype.setClustersList = function(value) { + return jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + * @return {!proto.clusters.GetApplicationsRequest} returns this + */ +proto.clusters.GetApplicationsRequest.prototype.addClusters = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.clusters.GetApplicationsRequest} returns this + */ +proto.clusters.GetApplicationsRequest.prototype.clearClustersList = function() { + return this.setClustersList([]); +}; + + +/** + * repeated string namespaces = 2; + * @return {!Array<string>} + */ +proto.clusters.GetApplicationsRequest.prototype.getNamespacesList = function() { + return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 2)); +}; + + +/** + * @param {!Array<string>} value + * @return {!proto.clusters.GetApplicationsRequest} returns this + */ +proto.clusters.GetApplicationsRequest.prototype.setNamespacesList = function(value) { + return jspb.Message.setField(this, 2, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + * @return {!proto.clusters.GetApplicationsRequest} returns this + */ +proto.clusters.GetApplicationsRequest.prototype.addNamespaces = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 2, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.clusters.GetApplicationsRequest} returns this + */ +proto.clusters.GetApplicationsRequest.prototype.clearNamespacesList = function() { + return this.setNamespacesList([]); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array<number>} + * @const + */ +proto.clusters.GetApplicationsResponse.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.clusters.GetApplicationsResponse.prototype.toObject = function(opt_includeInstance) { + return proto.clusters.GetApplicationsResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.clusters.GetApplicationsResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.GetApplicationsResponse.toObject = function(includeInstance, msg) { + var f, obj = { + applicationsList: jspb.Message.toObjectList(msg.getApplicationsList(), + applications_pb.Application.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.clusters.GetApplicationsResponse} + */ +proto.clusters.GetApplicationsResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.clusters.GetApplicationsResponse; + return proto.clusters.GetApplicationsResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.clusters.GetApplicationsResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.clusters.GetApplicationsResponse} + */ +proto.clusters.GetApplicationsResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new applications_pb.Application; + reader.readMessage(value,applications_pb.Application.deserializeBinaryFromReader); + msg.addApplications(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.clusters.GetApplicationsResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.clusters.GetApplicationsResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.clusters.GetApplicationsResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.GetApplicationsResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getApplicationsList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + applications_pb.Application.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated Application applications = 1; + * @return {!Array<!proto.clusters.Application>} + */ +proto.clusters.GetApplicationsResponse.prototype.getApplicationsList = function() { + return /** @type{!Array<!proto.clusters.Application>} */ ( + jspb.Message.getRepeatedWrapperField(this, applications_pb.Application, 1)); +}; + + +/** + * @param {!Array<!proto.clusters.Application>} value + * @return {!proto.clusters.GetApplicationsResponse} returns this +*/ +proto.clusters.GetApplicationsResponse.prototype.setApplicationsList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.clusters.Application=} opt_value + * @param {number=} opt_index + * @return {!proto.clusters.Application} + */ +proto.clusters.GetApplicationsResponse.prototype.addApplications = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.clusters.Application, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.clusters.GetApplicationsResponse} returns this + */ +proto.clusters.GetApplicationsResponse.prototype.clearApplicationsList = function() { + return this.setApplicationsList([]); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.clusters.GetApplicationRequest.prototype.toObject = function(opt_includeInstance) { + return proto.clusters.GetApplicationRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.clusters.GetApplicationRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.GetApplicationRequest.toObject = function(includeInstance, msg) { + var f, obj = { + cluster: jspb.Message.getFieldWithDefault(msg, 1, ""), + namespace: jspb.Message.getFieldWithDefault(msg, 2, ""), + name: jspb.Message.getFieldWithDefault(msg, 3, "") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.clusters.GetApplicationRequest} + */ +proto.clusters.GetApplicationRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.clusters.GetApplicationRequest; + return proto.clusters.GetApplicationRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.clusters.GetApplicationRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.clusters.GetApplicationRequest} + */ +proto.clusters.GetApplicationRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setCluster(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setNamespace(value); + break; + case 3: + var value = /** @type {string} */ (reader.readString()); + msg.setName(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.clusters.GetApplicationRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.clusters.GetApplicationRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.clusters.GetApplicationRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.GetApplicationRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getCluster(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getNamespace(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } + f = message.getName(); + if (f.length > 0) { + writer.writeString( + 3, + f + ); + } +}; + + +/** + * optional string cluster = 1; + * @return {string} + */ +proto.clusters.GetApplicationRequest.prototype.getCluster = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.clusters.GetApplicationRequest} returns this + */ +proto.clusters.GetApplicationRequest.prototype.setCluster = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional string namespace = 2; + * @return {string} + */ +proto.clusters.GetApplicationRequest.prototype.getNamespace = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.clusters.GetApplicationRequest} returns this + */ +proto.clusters.GetApplicationRequest.prototype.setNamespace = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); +}; + + +/** + * optional string name = 3; + * @return {string} + */ +proto.clusters.GetApplicationRequest.prototype.getName = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); +}; + + +/** + * @param {string} value + * @return {!proto.clusters.GetApplicationRequest} returns this + */ +proto.clusters.GetApplicationRequest.prototype.setName = function(value) { + return jspb.Message.setProto3StringField(this, 3, value); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.clusters.GetApplicationResponse.prototype.toObject = function(opt_includeInstance) { + return proto.clusters.GetApplicationResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.clusters.GetApplicationResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.GetApplicationResponse.toObject = function(includeInstance, msg) { + var f, obj = { + application: (f = msg.getApplication()) && applications_pb.Application.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.clusters.GetApplicationResponse} + */ +proto.clusters.GetApplicationResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.clusters.GetApplicationResponse; + return proto.clusters.GetApplicationResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.clusters.GetApplicationResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.clusters.GetApplicationResponse} + */ +proto.clusters.GetApplicationResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new applications_pb.Application; + reader.readMessage(value,applications_pb.Application.deserializeBinaryFromReader); + msg.setApplication(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.clusters.GetApplicationResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.clusters.GetApplicationResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.clusters.GetApplicationResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.clusters.GetApplicationResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getApplication(); + if (f != null) { + writer.writeMessage( + 1, + f, + applications_pb.Application.serializeBinaryToWriter + ); + } +}; + + +/** + * optional Application application = 1; + * @return {?proto.clusters.Application} + */ +proto.clusters.GetApplicationResponse.prototype.getApplication = function() { + return /** @type{?proto.clusters.Application} */ ( + jspb.Message.getWrapperField(this, applications_pb.Application, 1)); +}; + + +/** + * @param {?proto.clusters.Application|undefined} value + * @return {!proto.clusters.GetApplicationResponse} returns this +*/ +proto.clusters.GetApplicationResponse.prototype.setApplication = function(value) { + return jspb.Message.setWrapperField(this, 1, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.clusters.GetApplicationResponse} returns this + */ +proto.clusters.GetApplicationResponse.prototype.clearApplication = function() { + return this.setApplication(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.clusters.GetApplicationResponse.prototype.hasApplication = function() { + return jspb.Message.getField(this, 1) != null; +}; + + goog.object.extend(exports, proto.clusters); diff --git a/app/src/generated/proto/clusters_pb_service.d.ts b/app/src/generated/proto/clusters_pb_service.d.ts index c45b14af5..2bf56642f 100644 --- a/app/src/generated/proto/clusters_pb_service.d.ts +++ b/app/src/generated/proto/clusters_pb_service.d.ts @@ -31,11 +31,31 @@ type ClustersGetResources = { readonly responseType: typeof clusters_pb.GetResourcesResponse; }; +type ClustersGetApplications = { + readonly methodName: string; + readonly service: typeof Clusters; + readonly requestStream: false; + readonly responseStream: false; + readonly requestType: typeof clusters_pb.GetApplicationsRequest; + readonly responseType: typeof clusters_pb.GetApplicationsResponse; +}; + +type ClustersGetApplication = { + readonly methodName: string; + readonly service: typeof Clusters; + readonly requestStream: false; + readonly responseStream: false; + readonly requestType: typeof clusters_pb.GetApplicationRequest; + readonly responseType: typeof clusters_pb.GetApplicationResponse; +}; + export class Clusters { static readonly serviceName: string; static readonly GetClusters: ClustersGetClusters; static readonly GetNamespaces: ClustersGetNamespaces; static readonly GetResources: ClustersGetResources; + static readonly GetApplications: ClustersGetApplications; + static readonly GetApplication: ClustersGetApplication; } export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } @@ -97,5 +117,23 @@ export class ClustersClient { requestMessage: clusters_pb.GetResourcesRequest, callback: (error: ServiceError|null, responseMessage: clusters_pb.GetResourcesResponse|null) => void ): UnaryResponse; + getApplications( + requestMessage: clusters_pb.GetApplicationsRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: clusters_pb.GetApplicationsResponse|null) => void + ): UnaryResponse; + getApplications( + requestMessage: clusters_pb.GetApplicationsRequest, + callback: (error: ServiceError|null, responseMessage: clusters_pb.GetApplicationsResponse|null) => void + ): UnaryResponse; + getApplication( + requestMessage: clusters_pb.GetApplicationRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: clusters_pb.GetApplicationResponse|null) => void + ): UnaryResponse; + getApplication( + requestMessage: clusters_pb.GetApplicationRequest, + callback: (error: ServiceError|null, responseMessage: clusters_pb.GetApplicationResponse|null) => void + ): UnaryResponse; } diff --git a/app/src/generated/proto/clusters_pb_service.js b/app/src/generated/proto/clusters_pb_service.js index a1922e41c..a1a934763 100644 --- a/app/src/generated/proto/clusters_pb_service.js +++ b/app/src/generated/proto/clusters_pb_service.js @@ -37,6 +37,24 @@ Clusters.GetResources = { responseType: clusters_pb.GetResourcesResponse }; +Clusters.GetApplications = { + methodName: "GetApplications", + service: Clusters, + requestStream: false, + responseStream: false, + requestType: clusters_pb.GetApplicationsRequest, + responseType: clusters_pb.GetApplicationsResponse +}; + +Clusters.GetApplication = { + methodName: "GetApplication", + service: Clusters, + requestStream: false, + responseStream: false, + requestType: clusters_pb.GetApplicationRequest, + responseType: clusters_pb.GetApplicationResponse +}; + exports.Clusters = Clusters; function ClustersClient(serviceHost, options) { @@ -137,5 +155,67 @@ ClustersClient.prototype.getResources = function getResources(requestMessage, me }; }; +ClustersClient.prototype.getApplications = function getApplications(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(Clusters.GetApplications, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + +ClustersClient.prototype.getApplication = function getApplication(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(Clusters.GetApplication, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + exports.ClustersClient = ClustersClient; diff --git a/app/src/index.tsx b/app/src/index.tsx index c9ebadbf8..11c8f2e1c 100644 --- a/app/src/index.tsx +++ b/app/src/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import App from './App'; +import App from 'App'; ReactDOM.render( <React.StrictMode> diff --git a/app/src/utils/constants.ts b/app/src/utils/constants.ts index 485b79f36..77657a28b 100644 --- a/app/src/utils/constants.ts +++ b/app/src/utils/constants.ts @@ -1 +1,8 @@ +// apiURL is the URL, which should be used for the GRPC requests. When the React UI is served for development +// (yarn start), we are using the complete URL for the Envoy container. In production the React UI should be served via +// the same URL as the gRPC API so that we can omit the URL. The correct routing should be handled by Envoy. export const apiURL = process.env.NODE_ENV === 'production' ? '' : 'http://localhost:15222'; + +// applicationsDescription is the description, which is displayed in the UI for the Application CR. Similar to other +// resources, this should be a short description of the Application CR and for what it is used. +export const applicationsDescription = 'Applications are a Custom Resource for kobs.'; diff --git a/app/src/utils/helpers.ts b/app/src/utils/helpers.ts index 6f82af7c9..02bf9ede4 100644 --- a/app/src/utils/helpers.ts +++ b/app/src/utils/helpers.ts @@ -1,5 +1,5 @@ // timeDifference calculates the difference of two given timestamps and returns a human readable string for the -// difference. +// difference. It is used to get the same style for the age of resources like it is displayed by kubectl. export const timeDifference = (current: number, previous: number): string => { const msPerMinute = 60 * 1000; const msPerHour = msPerMinute * 60; diff --git a/app/tsconfig.json b/app/tsconfig.json index a273b0cfc..9c7d4a8a4 100644 --- a/app/tsconfig.json +++ b/app/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "baseUrl": "src", "target": "es5", "lib": [ "dom", diff --git a/deploy/docker/envoy/envoy.yaml b/deploy/docker/envoy/envoy.yaml index 4c04bc1cc..374903b94 100644 --- a/deploy/docker/envoy/envoy.yaml +++ b/deploy/docker/envoy/envoy.yaml @@ -32,8 +32,7 @@ static_resources: domains: ["*"] routes: - match: - # prefix: "/" - prefix: "/clusters.Clusters" + prefix: "/clusters." route: cluster: api-server max_stream_duration: diff --git a/deploy/kustomize/crds/kobs.io_applications.yaml b/deploy/kustomize/crds/kobs.io_applications.yaml new file mode 100644 index 000000000..31b1f5186 --- /dev/null +++ b/deploy/kustomize/crds/kobs.io_applications.yaml @@ -0,0 +1,90 @@ + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: applications.kobs.io +spec: + group: kobs.io + names: + kind: Application + listKind: ApplicationList + plural: applications + singular: application + scope: Namespaced + validation: + openAPIV3Schema: + description: Application is the Application CRD, which consists of the Kubernetes + metadata and the Application from the protobuf definition. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Application is the specification for an application. This specification + is also used for the Kubernetes CRD as ApplicationSpec. This is also the + reason why we use istio.io/tools/cmd/protoc-gen-deepcopy within the code + generation, to generate the deepcopy function, which are required to use + the Application within a CRD. + properties: + cluster: + type: string + links: + items: + description: ApplicationLink is the format of a link, which can be + provided within an application. A link consists of a title, which + is displayed in the frontend and the link link (title=Example, link=https://example.com). + properties: + link: + type: string + title: + type: string + type: object + type: array + name: + type: string + namespace: + type: string + resources: + items: + description: ApplicationResources is the specification to retrieve + all Kubernetes resources, which can be associated with the application. + For that, a list of kinds (deployments, pods, statefulsets) as specified + in app/src/components/resources/helpers.tsx and a selector must + be set. Currently only label selector is supported, e.g. app=example. + properties: + kinds: + items: + type: string + type: array + selector: + type: string + type: object + type: array + type: object + required: + - spec + type: object + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/pkg/api/clusters/cluster/cluster.go b/pkg/api/clusters/cluster/cluster.go index 4478cd79c..1c9b721d6 100644 --- a/pkg/api/clusters/cluster/cluster.go +++ b/pkg/api/clusters/cluster/cluster.go @@ -2,8 +2,13 @@ package cluster import ( "context" + "regexp" + "strings" "time" + kobsClientsetVersioned "github.com/kobsio/kobs/pkg/generated/clientset/versioned" + "github.com/kobsio/kobs/pkg/generated/proto" + "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -11,15 +16,17 @@ import ( ) var ( - log = logrus.WithFields(logrus.Fields{"package": "cluster"}) + log = logrus.WithFields(logrus.Fields{"package": "cluster"}) + slugifyRe = regexp.MustCompile("[^a-z0-9]+") ) // Cluster is a Kubernetes cluster. It contains all required fields to interact with the cluster and it's services. type Cluster struct { - cache Cache - clientset *kubernetes.Clientset - options Options - name string + cache Cache + clientset *kubernetes.Clientset + kobsClientset *kobsClientsetVersioned.Clientset + options Options + name string } // Options contains various options, which could be set for a cluster. For example a user can set the cache duration for @@ -101,18 +108,70 @@ func (c *Cluster) GetResources(ctx context.Context, namespace, path, resource, p return string(res), nil } +// GetApplications returns a list of applications gor the given namespace. It also adds the cluster, namespace and +// application name to the application CR, so that this information must not be specified by the user in the CR. +func (c *Cluster) GetApplications(ctx context.Context, namespace string) ([]*proto.Application, error) { + applicationsList, err := c.kobsClientset.KobsV1alpha1().Applications(namespace).List(ctx, metav1.ListOptions{}) + if err != nil { + return nil, err + } + + var applications []*proto.Application + + for _, app := range applicationsList.Items { + if app.Spec == nil { + continue + } + + application := app.Spec + application.Cluster = c.name + application.Namespace = app.Namespace + application.Name = app.Name + + applications = append(applications, application) + } + + return applications, nil +} + +// GetApplication returns a application for the given namespace and name. After the application is retrieved we replace, +// the cluster, namespace and name in the spec of the Application CR. This is needed, so that the user doesn't have to, +// provide these fields. +func (c *Cluster) GetApplication(ctx context.Context, namespace, name string) (*proto.Application, error) { + applicationCR, err := c.kobsClientset.KobsV1alpha1().Applications(namespace).Get(ctx, name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + + application := applicationCR.Spec + application.Cluster = c.name + application.Namespace = namespace + application.Name = name + + return application, nil +} + // NewCluster returns a new cluster. Each cluster must have a unique name and a client to make requests against the // Kubernetes API server of this cluster. func NewCluster(name string, restConfig *rest.Config) (*Cluster, error) { clientset, err := kubernetes.NewForConfig(restConfig) if err != nil { - log.WithError(err).Debugf("Could not create clientset.") + log.WithError(err).Debugf("Could not create Kubernetes clientset.") + return nil, err + } + + kobsClientset, err := kobsClientsetVersioned.NewForConfig(restConfig) + if err != nil { + log.WithError(err).Debugf("Could not create kobs clientset.") return nil, err } + name = strings.Trim(slugifyRe.ReplaceAllString(strings.ToLower(name), "-"), "-") + return &Cluster{ - clientset: clientset, - name: name, + clientset: clientset, + kobsClientset: kobsClientset, + name: name, }, nil } diff --git a/pkg/api/clusters/clusters.go b/pkg/api/clusters/clusters.go index 5d274b553..293c5def5 100644 --- a/pkg/api/clusters/clusters.go +++ b/pkg/api/clusters/clusters.go @@ -146,6 +146,54 @@ func (c *Clusters) GetResources(ctx context.Context, getResourcesRequest *proto. }, nil } +// GetApplications returns a list of applications for the given clusters and namespaces. +// To generate this list, we loop over every cluster and namespace and try to get the applications for this. +func (c *Clusters) GetApplications(ctx context.Context, getApplicationsRequest *proto.GetApplicationsRequest) (*proto.GetApplicationsResponse, error) { + var applications []*proto.Application + + log.WithFields(logrus.Fields{"clusters": getApplicationsRequest.Clusters, "namespaces": getApplicationsRequest.Namespaces}).Tracef("Get applications.") + + for _, clusterName := range getApplicationsRequest.Clusters { + cluster := c.getCluster(clusterName) + if cluster == nil { + return nil, fmt.Errorf("invalid cluster name") + } + + for _, namespace := range getApplicationsRequest.Namespaces { + list, err := cluster.GetApplications(ctx, namespace) + if err != nil { + return nil, err + } + + applications = append(applications, list...) + } + } + + return &proto.GetApplicationsResponse{ + Applications: applications, + }, nil +} + +// GetApplication returns a single application with the given name in the given cluster and namespace. If there isn't, +// such an application an error is returned. +func (c *Clusters) GetApplication(ctx context.Context, getApplicationRequest *proto.GetApplicationRequest) (*proto.GetApplicationResponse, error) { + log.WithFields(logrus.Fields{"cluster": getApplicationRequest.Cluster, "namespace": getApplicationRequest.Namespace, "name": getApplicationRequest.Name}).Tracef("Get application.") + + cluster := c.getCluster(getApplicationRequest.Cluster) + if cluster == nil { + return nil, fmt.Errorf("invalid cluster name") + } + + application, err := cluster.GetApplication(ctx, getApplicationRequest.Namespace, getApplicationRequest.Name) + if err != nil { + return nil, err + } + + return &proto.GetApplicationResponse{ + Application: application, + }, nil +} + // Load loads all clusters for the given configuration. // The clusters can be retrieved from different providers. Currently we are supporting incluster configuration and // kubeconfig files. In the future it is planning to directly support GKE, EKS, AKS, etc. diff --git a/pkg/api/kubernetes/apis/application/register.go b/pkg/api/kubernetes/apis/application/register.go new file mode 100644 index 000000000..9cc2e9eff --- /dev/null +++ b/pkg/api/kubernetes/apis/application/register.go @@ -0,0 +1,6 @@ +package application + +// GroupName is the group name used in this package. +const ( + GroupName = "kobs.io" +) diff --git a/pkg/api/kubernetes/apis/application/v1alpha1/doc.go b/pkg/api/kubernetes/apis/application/v1alpha1/doc.go new file mode 100644 index 000000000..5468941d2 --- /dev/null +++ b/pkg/api/kubernetes/apis/application/v1alpha1/doc.go @@ -0,0 +1,4 @@ +// +k8s:deepcopy-gen=package +// +groupName=kobs.io + +package v1alpha1 diff --git a/pkg/api/kubernetes/apis/application/v1alpha1/register.go b/pkg/api/kubernetes/apis/application/v1alpha1/register.go new file mode 100644 index 000000000..a7500c4c6 --- /dev/null +++ b/pkg/api/kubernetes/apis/application/v1alpha1/register.go @@ -0,0 +1,39 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + application "github.com/kobsio/kobs/pkg/api/kubernetes/apis/application" +) + +// SchemeGroupVersion is group version used to register these objects. +var SchemeGroupVersion = schema.GroupVersion{Group: application.GroupName, Version: "v1alpha1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind. +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource. +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + // SchemeBuilder initializes a scheme builder. + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme is a global function that registers this API group & version to a scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Application{}, + &ApplicationList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/api/kubernetes/apis/application/v1alpha1/types.go b/pkg/api/kubernetes/apis/application/v1alpha1/types.go new file mode 100644 index 000000000..72780e6fe --- /dev/null +++ b/pkg/api/kubernetes/apis/application/v1alpha1/types.go @@ -0,0 +1,28 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/kobsio/kobs/pkg/generated/proto" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Application is the Application CRD, which consists of the Kubernetes metadata and the Application from the protobuf +// definition. +type Application struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec *proto.Application `json:"spec"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ApplicationList is the structure of a list of Application CRs. +type ApplicationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Application `json:"items"` +} diff --git a/pkg/api/kubernetes/apis/application/v1alpha1/zz_generated.deepcopy.go b/pkg/api/kubernetes/apis/application/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000..31e0371c1 --- /dev/null +++ b/pkg/api/kubernetes/apis/application/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,88 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Application) DeepCopyInto(out *Application) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Application. +func (in *Application) DeepCopy() *Application { + if in == nil { + return nil + } + out := new(Application) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Application) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationList) DeepCopyInto(out *ApplicationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Application, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationList. +func (in *ApplicationList) DeepCopy() *ApplicationList { + if in == nil { + return nil + } + out := new(ApplicationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApplicationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/pkg/generated/clientset/versioned/clientset.go b/pkg/generated/clientset/versioned/clientset.go new file mode 100644 index 000000000..f955d9780 --- /dev/null +++ b/pkg/generated/clientset/versioned/clientset.go @@ -0,0 +1,97 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + "fmt" + + kobsv1alpha1 "github.com/kobsio/kobs/pkg/generated/clientset/versioned/typed/application/v1alpha1" + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + KobsV1alpha1() kobsv1alpha1.KobsV1alpha1Interface +} + +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + *discovery.DiscoveryClient + kobsV1alpha1 *kobsv1alpha1.KobsV1alpha1Client +} + +// KobsV1alpha1 retrieves the KobsV1alpha1Client +func (c *Clientset) KobsV1alpha1() kobsv1alpha1.KobsV1alpha1Interface { + return c.kobsV1alpha1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + var cs Clientset + var err error + cs.kobsV1alpha1, err = kobsv1alpha1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + var cs Clientset + cs.kobsV1alpha1 = kobsv1alpha1.NewForConfigOrDie(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) + return &cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.kobsV1alpha1 = kobsv1alpha1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/pkg/generated/clientset/versioned/doc.go b/pkg/generated/clientset/versioned/doc.go new file mode 100644 index 000000000..41721ca52 --- /dev/null +++ b/pkg/generated/clientset/versioned/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated clientset. +package versioned diff --git a/pkg/generated/clientset/versioned/fake/clientset_generated.go b/pkg/generated/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 000000000..19e847b17 --- /dev/null +++ b/pkg/generated/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,82 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + clientset "github.com/kobsio/kobs/pkg/generated/clientset/versioned" + kobsv1alpha1 "github.com/kobsio/kobs/pkg/generated/clientset/versioned/typed/application/v1alpha1" + fakekobsv1alpha1 "github.com/kobsio/kobs/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +var _ clientset.Interface = &Clientset{} + +// KobsV1alpha1 retrieves the KobsV1alpha1Client +func (c *Clientset) KobsV1alpha1() kobsv1alpha1.KobsV1alpha1Interface { + return &fakekobsv1alpha1.FakeKobsV1alpha1{Fake: &c.Fake} +} diff --git a/pkg/generated/clientset/versioned/fake/doc.go b/pkg/generated/clientset/versioned/fake/doc.go new file mode 100644 index 000000000..9b99e7167 --- /dev/null +++ b/pkg/generated/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/pkg/generated/clientset/versioned/fake/register.go b/pkg/generated/clientset/versioned/fake/register.go new file mode 100644 index 000000000..9d831f809 --- /dev/null +++ b/pkg/generated/clientset/versioned/fake/register.go @@ -0,0 +1,56 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + kobsv1alpha1 "github.com/kobsio/kobs/pkg/api/kubernetes/apis/application/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + kobsv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/pkg/generated/clientset/versioned/scheme/doc.go b/pkg/generated/clientset/versioned/scheme/doc.go new file mode 100644 index 000000000..7dc375616 --- /dev/null +++ b/pkg/generated/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/pkg/generated/clientset/versioned/scheme/register.go b/pkg/generated/clientset/versioned/scheme/register.go new file mode 100644 index 000000000..987e8600d --- /dev/null +++ b/pkg/generated/clientset/versioned/scheme/register.go @@ -0,0 +1,56 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + kobsv1alpha1 "github.com/kobsio/kobs/pkg/api/kubernetes/apis/application/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + kobsv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/pkg/generated/clientset/versioned/typed/application/v1alpha1/application.go b/pkg/generated/clientset/versioned/typed/application/v1alpha1/application.go new file mode 100644 index 000000000..0b63f61fe --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/application/v1alpha1/application.go @@ -0,0 +1,178 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/kobsio/kobs/pkg/api/kubernetes/apis/application/v1alpha1" + scheme "github.com/kobsio/kobs/pkg/generated/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// ApplicationsGetter has a method to return a ApplicationInterface. +// A group's client should implement this interface. +type ApplicationsGetter interface { + Applications(namespace string) ApplicationInterface +} + +// ApplicationInterface has methods to work with Application resources. +type ApplicationInterface interface { + Create(ctx context.Context, application *v1alpha1.Application, opts v1.CreateOptions) (*v1alpha1.Application, error) + Update(ctx context.Context, application *v1alpha1.Application, opts v1.UpdateOptions) (*v1alpha1.Application, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.Application, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.ApplicationList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Application, err error) + ApplicationExpansion +} + +// applications implements ApplicationInterface +type applications struct { + client rest.Interface + ns string +} + +// newApplications returns a Applications +func newApplications(c *KobsV1alpha1Client, namespace string) *applications { + return &applications{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the application, and returns the corresponding application object, and an error if there is any. +func (c *applications) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Application, err error) { + result = &v1alpha1.Application{} + err = c.client.Get(). + Namespace(c.ns). + Resource("applications"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Applications that match those selectors. +func (c *applications) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ApplicationList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.ApplicationList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("applications"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested applications. +func (c *applications) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("applications"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a application and creates it. Returns the server's representation of the application, and an error, if there is any. +func (c *applications) Create(ctx context.Context, application *v1alpha1.Application, opts v1.CreateOptions) (result *v1alpha1.Application, err error) { + result = &v1alpha1.Application{} + err = c.client.Post(). + Namespace(c.ns). + Resource("applications"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(application). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a application and updates it. Returns the server's representation of the application, and an error, if there is any. +func (c *applications) Update(ctx context.Context, application *v1alpha1.Application, opts v1.UpdateOptions) (result *v1alpha1.Application, err error) { + result = &v1alpha1.Application{} + err = c.client.Put(). + Namespace(c.ns). + Resource("applications"). + Name(application.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(application). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the application and deletes it. Returns an error if one occurs. +func (c *applications) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("applications"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *applications) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("applications"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched application. +func (c *applications) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Application, err error) { + result = &v1alpha1.Application{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("applications"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/generated/clientset/versioned/typed/application/v1alpha1/application_client.go b/pkg/generated/clientset/versioned/typed/application/v1alpha1/application_client.go new file mode 100644 index 000000000..dcd5812d4 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/application/v1alpha1/application_client.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/kobsio/kobs/pkg/api/kubernetes/apis/application/v1alpha1" + "github.com/kobsio/kobs/pkg/generated/clientset/versioned/scheme" + rest "k8s.io/client-go/rest" +) + +type KobsV1alpha1Interface interface { + RESTClient() rest.Interface + ApplicationsGetter +} + +// KobsV1alpha1Client is used to interact with features provided by the kobs.io group. +type KobsV1alpha1Client struct { + restClient rest.Interface +} + +func (c *KobsV1alpha1Client) Applications(namespace string) ApplicationInterface { + return newApplications(c, namespace) +} + +// NewForConfig creates a new KobsV1alpha1Client for the given config. +func NewForConfig(c *rest.Config) (*KobsV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &KobsV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new KobsV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *KobsV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new KobsV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *KobsV1alpha1Client { + return &KobsV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *KobsV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/generated/clientset/versioned/typed/application/v1alpha1/doc.go b/pkg/generated/clientset/versioned/typed/application/v1alpha1/doc.go new file mode 100644 index 000000000..df51baa4d --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/application/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1alpha1 diff --git a/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake/doc.go b/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake/fake_application.go b/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake/fake_application.go new file mode 100644 index 000000000..cb849923b --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake/fake_application.go @@ -0,0 +1,130 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/kobsio/kobs/pkg/api/kubernetes/apis/application/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeApplications implements ApplicationInterface +type FakeApplications struct { + Fake *FakeKobsV1alpha1 + ns string +} + +var applicationsResource = schema.GroupVersionResource{Group: "kobs.io", Version: "v1alpha1", Resource: "applications"} + +var applicationsKind = schema.GroupVersionKind{Group: "kobs.io", Version: "v1alpha1", Kind: "Application"} + +// Get takes name of the application, and returns the corresponding application object, and an error if there is any. +func (c *FakeApplications) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Application, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(applicationsResource, c.ns, name), &v1alpha1.Application{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Application), err +} + +// List takes label and field selectors, and returns the list of Applications that match those selectors. +func (c *FakeApplications) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ApplicationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(applicationsResource, applicationsKind, c.ns, opts), &v1alpha1.ApplicationList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ApplicationList{ListMeta: obj.(*v1alpha1.ApplicationList).ListMeta} + for _, item := range obj.(*v1alpha1.ApplicationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested applications. +func (c *FakeApplications) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(applicationsResource, c.ns, opts)) + +} + +// Create takes the representation of a application and creates it. Returns the server's representation of the application, and an error, if there is any. +func (c *FakeApplications) Create(ctx context.Context, application *v1alpha1.Application, opts v1.CreateOptions) (result *v1alpha1.Application, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(applicationsResource, c.ns, application), &v1alpha1.Application{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Application), err +} + +// Update takes the representation of a application and updates it. Returns the server's representation of the application, and an error, if there is any. +func (c *FakeApplications) Update(ctx context.Context, application *v1alpha1.Application, opts v1.UpdateOptions) (result *v1alpha1.Application, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(applicationsResource, c.ns, application), &v1alpha1.Application{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Application), err +} + +// Delete takes name of the application and deletes it. Returns an error if one occurs. +func (c *FakeApplications) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(applicationsResource, c.ns, name), &v1alpha1.Application{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeApplications) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(applicationsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ApplicationList{}) + return err +} + +// Patch applies the patch and returns the patched application. +func (c *FakeApplications) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Application, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(applicationsResource, c.ns, name, pt, data, subresources...), &v1alpha1.Application{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Application), err +} diff --git a/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake/fake_application_client.go b/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake/fake_application_client.go new file mode 100644 index 000000000..b1515a80a --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake/fake_application_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/kobsio/kobs/pkg/generated/clientset/versioned/typed/application/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeKobsV1alpha1 struct { + *testing.Fake +} + +func (c *FakeKobsV1alpha1) Applications(namespace string) v1alpha1.ApplicationInterface { + return &FakeApplications{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeKobsV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/generated/clientset/versioned/typed/application/v1alpha1/generated_expansion.go b/pkg/generated/clientset/versioned/typed/application/v1alpha1/generated_expansion.go new file mode 100644 index 000000000..5cd0d180c --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/application/v1alpha1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +type ApplicationExpansion interface{} diff --git a/pkg/generated/informers/externalversions/application/interface.go b/pkg/generated/informers/externalversions/application/interface.go new file mode 100644 index 000000000..8abf606ea --- /dev/null +++ b/pkg/generated/informers/externalversions/application/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package application + +import ( + v1alpha1 "github.com/kobsio/kobs/pkg/generated/informers/externalversions/application/v1alpha1" + internalinterfaces "github.com/kobsio/kobs/pkg/generated/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/generated/informers/externalversions/application/v1alpha1/application.go b/pkg/generated/informers/externalversions/application/v1alpha1/application.go new file mode 100644 index 000000000..b6106a6ba --- /dev/null +++ b/pkg/generated/informers/externalversions/application/v1alpha1/application.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + applicationv1alpha1 "github.com/kobsio/kobs/pkg/api/kubernetes/apis/application/v1alpha1" + versioned "github.com/kobsio/kobs/pkg/generated/clientset/versioned" + internalinterfaces "github.com/kobsio/kobs/pkg/generated/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/kobsio/kobs/pkg/generated/listers/application/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// ApplicationInformer provides access to a shared informer and lister for +// Applications. +type ApplicationInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.ApplicationLister +} + +type applicationInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewApplicationInformer constructs a new informer for Application type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewApplicationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredApplicationInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredApplicationInformer constructs a new informer for Application type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredApplicationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.KobsV1alpha1().Applications(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.KobsV1alpha1().Applications(namespace).Watch(context.TODO(), options) + }, + }, + &applicationv1alpha1.Application{}, + resyncPeriod, + indexers, + ) +} + +func (f *applicationInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredApplicationInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *applicationInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&applicationv1alpha1.Application{}, f.defaultInformer) +} + +func (f *applicationInformer) Lister() v1alpha1.ApplicationLister { + return v1alpha1.NewApplicationLister(f.Informer().GetIndexer()) +} diff --git a/pkg/generated/informers/externalversions/application/v1alpha1/interface.go b/pkg/generated/informers/externalversions/application/v1alpha1/interface.go new file mode 100644 index 000000000..532c8d13c --- /dev/null +++ b/pkg/generated/informers/externalversions/application/v1alpha1/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + internalinterfaces "github.com/kobsio/kobs/pkg/generated/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Applications returns a ApplicationInformer. + Applications() ApplicationInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Applications returns a ApplicationInformer. +func (v *version) Applications() ApplicationInformer { + return &applicationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/generated/informers/externalversions/factory.go b/pkg/generated/informers/externalversions/factory.go new file mode 100644 index 000000000..9ff363860 --- /dev/null +++ b/pkg/generated/informers/externalversions/factory.go @@ -0,0 +1,180 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + versioned "github.com/kobsio/kobs/pkg/generated/clientset/versioned" + application "github.com/kobsio/kobs/pkg/generated/informers/externalversions/application" + internalinterfaces "github.com/kobsio/kobs/pkg/generated/informers/externalversions/internalinterfaces" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + Kobs() application.Interface +} + +func (f *sharedInformerFactory) Kobs() application.Interface { + return application.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/generated/informers/externalversions/generic.go b/pkg/generated/informers/externalversions/generic.go new file mode 100644 index 000000000..0858a8307 --- /dev/null +++ b/pkg/generated/informers/externalversions/generic.go @@ -0,0 +1,62 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + v1alpha1 "github.com/kobsio/kobs/pkg/api/kubernetes/apis/application/v1alpha1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=kobs.io, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("applications"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Kobs().V1alpha1().Applications().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 000000000..1353cfc36 --- /dev/null +++ b/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + versioned "github.com/kobsio/kobs/pkg/generated/clientset/versioned" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/pkg/generated/listers/application/v1alpha1/application.go b/pkg/generated/listers/application/v1alpha1/application.go new file mode 100644 index 000000000..bd888cce0 --- /dev/null +++ b/pkg/generated/listers/application/v1alpha1/application.go @@ -0,0 +1,99 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/kobsio/kobs/pkg/api/kubernetes/apis/application/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// ApplicationLister helps list Applications. +// All objects returned here must be treated as read-only. +type ApplicationLister interface { + // List lists all Applications in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.Application, err error) + // Applications returns an object that can list and get Applications. + Applications(namespace string) ApplicationNamespaceLister + ApplicationListerExpansion +} + +// applicationLister implements the ApplicationLister interface. +type applicationLister struct { + indexer cache.Indexer +} + +// NewApplicationLister returns a new ApplicationLister. +func NewApplicationLister(indexer cache.Indexer) ApplicationLister { + return &applicationLister{indexer: indexer} +} + +// List lists all Applications in the indexer. +func (s *applicationLister) List(selector labels.Selector) (ret []*v1alpha1.Application, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Application)) + }) + return ret, err +} + +// Applications returns an object that can list and get Applications. +func (s *applicationLister) Applications(namespace string) ApplicationNamespaceLister { + return applicationNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ApplicationNamespaceLister helps list and get Applications. +// All objects returned here must be treated as read-only. +type ApplicationNamespaceLister interface { + // List lists all Applications in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.Application, err error) + // Get retrieves the Application from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.Application, error) + ApplicationNamespaceListerExpansion +} + +// applicationNamespaceLister implements the ApplicationNamespaceLister +// interface. +type applicationNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Applications in the indexer for a given namespace. +func (s applicationNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Application, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Application)) + }) + return ret, err +} + +// Get retrieves the Application from the indexer for a given namespace and name. +func (s applicationNamespaceLister) Get(name string) (*v1alpha1.Application, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("application"), name) + } + return obj.(*v1alpha1.Application), nil +} diff --git a/pkg/generated/listers/application/v1alpha1/expansion_generated.go b/pkg/generated/listers/application/v1alpha1/expansion_generated.go new file mode 100644 index 000000000..f31b9c747 --- /dev/null +++ b/pkg/generated/listers/application/v1alpha1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +// ApplicationListerExpansion allows custom methods to be added to +// ApplicationLister. +type ApplicationListerExpansion interface{} + +// ApplicationNamespaceListerExpansion allows custom methods to be added to +// ApplicationNamespaceLister. +type ApplicationNamespaceListerExpansion interface{} diff --git a/pkg/generated/proto/applications.pb.go b/pkg/generated/proto/applications.pb.go new file mode 100644 index 000000000..cf6984444 --- /dev/null +++ b/pkg/generated/proto/applications.pb.go @@ -0,0 +1,348 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0 +// protoc v3.14.0 +// source: applications.proto + +package proto + +import ( + proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// Application is the specification for an application. This specification is also used for the Kubernetes CRD as +// ApplicationSpec. +// This is also the reason why we use istio.io/tools/cmd/protoc-gen-deepcopy within the code generation, to generate the +// deepcopy function, which are required to use the Application within a CRD. +type Application struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cluster string `protobuf:"bytes,1,opt,name=cluster,proto3" json:"cluster,omitempty"` + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Links []*ApplicationLink `protobuf:"bytes,4,rep,name=links,proto3" json:"links,omitempty"` + Resources []*ApplicationResources `protobuf:"bytes,5,rep,name=resources,proto3" json:"resources,omitempty"` +} + +func (x *Application) Reset() { + *x = Application{} + if protoimpl.UnsafeEnabled { + mi := &file_applications_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Application) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Application) ProtoMessage() {} + +func (x *Application) ProtoReflect() protoreflect.Message { + mi := &file_applications_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Application.ProtoReflect.Descriptor instead. +func (*Application) Descriptor() ([]byte, []int) { + return file_applications_proto_rawDescGZIP(), []int{0} +} + +func (x *Application) GetCluster() string { + if x != nil { + return x.Cluster + } + return "" +} + +func (x *Application) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *Application) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Application) GetLinks() []*ApplicationLink { + if x != nil { + return x.Links + } + return nil +} + +func (x *Application) GetResources() []*ApplicationResources { + if x != nil { + return x.Resources + } + return nil +} + +// ApplicationLink is the format of a link, which can be provided within an application. A link consists of a title, +// which is displayed in the frontend and the link link (title=Example, link=https://example.com). +type ApplicationLink struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Link string `protobuf:"bytes,2,opt,name=link,proto3" json:"link,omitempty"` +} + +func (x *ApplicationLink) Reset() { + *x = ApplicationLink{} + if protoimpl.UnsafeEnabled { + mi := &file_applications_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplicationLink) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplicationLink) ProtoMessage() {} + +func (x *ApplicationLink) ProtoReflect() protoreflect.Message { + mi := &file_applications_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplicationLink.ProtoReflect.Descriptor instead. +func (*ApplicationLink) Descriptor() ([]byte, []int) { + return file_applications_proto_rawDescGZIP(), []int{1} +} + +func (x *ApplicationLink) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *ApplicationLink) GetLink() string { + if x != nil { + return x.Link + } + return "" +} + +// ApplicationResources is the specification to retrieve all Kubernetes resources, which can be associated with the +// application. For that, a list of kinds (deployments, pods, statefulsets) as specified in +// app/src/components/resources/helpers.tsx and a selector must be set. Currently only label selector is supported, +// e.g. app=example. +type ApplicationResources struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Kinds []string `protobuf:"bytes,1,rep,name=kinds,proto3" json:"kinds,omitempty"` + Selector string `protobuf:"bytes,2,opt,name=selector,proto3" json:"selector,omitempty"` +} + +func (x *ApplicationResources) Reset() { + *x = ApplicationResources{} + if protoimpl.UnsafeEnabled { + mi := &file_applications_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplicationResources) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplicationResources) ProtoMessage() {} + +func (x *ApplicationResources) ProtoReflect() protoreflect.Message { + mi := &file_applications_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplicationResources.ProtoReflect.Descriptor instead. +func (*ApplicationResources) Descriptor() ([]byte, []int) { + return file_applications_proto_rawDescGZIP(), []int{2} +} + +func (x *ApplicationResources) GetKinds() []string { + if x != nil { + return x.Kinds + } + return nil +} + +func (x *ApplicationResources) GetSelector() string { + if x != nil { + return x.Selector + } + return "" +} + +var File_applications_proto protoreflect.FileDescriptor + +var file_applications_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x22, 0xc8, + 0x01, 0x0a, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, + 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x6c, 0x69, + 0x6e, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x3c, 0x0a, 0x09, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x09, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x3b, 0x0a, 0x0f, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, + 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x48, 0x0a, 0x14, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6b, + 0x69, 0x6e, 0x64, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, + 0x6f, 0x62, 0x73, 0x69, 0x6f, 0x2f, 0x6b, 0x6f, 0x62, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_applications_proto_rawDescOnce sync.Once + file_applications_proto_rawDescData = file_applications_proto_rawDesc +) + +func file_applications_proto_rawDescGZIP() []byte { + file_applications_proto_rawDescOnce.Do(func() { + file_applications_proto_rawDescData = protoimpl.X.CompressGZIP(file_applications_proto_rawDescData) + }) + return file_applications_proto_rawDescData +} + +var file_applications_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_applications_proto_goTypes = []interface{}{ + (*Application)(nil), // 0: clusters.Application + (*ApplicationLink)(nil), // 1: clusters.ApplicationLink + (*ApplicationResources)(nil), // 2: clusters.ApplicationResources +} +var file_applications_proto_depIdxs = []int32{ + 1, // 0: clusters.Application.links:type_name -> clusters.ApplicationLink + 2, // 1: clusters.Application.resources:type_name -> clusters.ApplicationResources + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_applications_proto_init() } +func file_applications_proto_init() { + if File_applications_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_applications_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Application); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_applications_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplicationLink); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_applications_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplicationResources); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_applications_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_applications_proto_goTypes, + DependencyIndexes: file_applications_proto_depIdxs, + MessageInfos: file_applications_proto_msgTypes, + }.Build() + File_applications_proto = out.File + file_applications_proto_rawDesc = nil + file_applications_proto_goTypes = nil + file_applications_proto_depIdxs = nil +} diff --git a/pkg/generated/proto/applications_deepcopy.gen.go b/pkg/generated/proto/applications_deepcopy.gen.go new file mode 100644 index 000000000..7b6f105d9 --- /dev/null +++ b/pkg/generated/proto/applications_deepcopy.gen.go @@ -0,0 +1,78 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: applications.proto + +package proto + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// DeepCopyInto supports using Application within kubernetes types, where deepcopy-gen is used. +func (in *Application) DeepCopyInto(out *Application) { + p := proto.Clone(in).(*Application) + *out = *p +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Application. Required by controller-gen. +func (in *Application) DeepCopy() *Application { + if in == nil { + return nil + } + out := new(Application) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new Application. Required by controller-gen. +func (in *Application) DeepCopyInterface() interface{} { + return in.DeepCopy() +} + +// DeepCopyInto supports using ApplicationLink within kubernetes types, where deepcopy-gen is used. +func (in *ApplicationLink) DeepCopyInto(out *ApplicationLink) { + p := proto.Clone(in).(*ApplicationLink) + *out = *p +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationLink. Required by controller-gen. +func (in *ApplicationLink) DeepCopy() *ApplicationLink { + if in == nil { + return nil + } + out := new(ApplicationLink) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationLink. Required by controller-gen. +func (in *ApplicationLink) DeepCopyInterface() interface{} { + return in.DeepCopy() +} + +// DeepCopyInto supports using ApplicationResources within kubernetes types, where deepcopy-gen is used. +func (in *ApplicationResources) DeepCopyInto(out *ApplicationResources) { + p := proto.Clone(in).(*ApplicationResources) + *out = *p +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationResources. Required by controller-gen. +func (in *ApplicationResources) DeepCopy() *ApplicationResources { + if in == nil { + return nil + } + out := new(ApplicationResources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationResources. Required by controller-gen. +func (in *ApplicationResources) DeepCopyInterface() interface{} { + return in.DeepCopy() +} diff --git a/pkg/generated/proto/applications_grpc.pb.go b/pkg/generated/proto/applications_grpc.pb.go new file mode 100644 index 000000000..da2ef3963 --- /dev/null +++ b/pkg/generated/proto/applications_grpc.pb.go @@ -0,0 +1,137 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// ApplicationsClient is the client API for Applications service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ApplicationsClient interface { + GetApplications(ctx context.Context, in *GetApplicationsRequest, opts ...grpc.CallOption) (*GetApplicationsResponse, error) + GetApplication(ctx context.Context, in *GetApplicationRequest, opts ...grpc.CallOption) (*GetApplicationResponse, error) +} + +type applicationsClient struct { + cc grpc.ClientConnInterface +} + +func NewApplicationsClient(cc grpc.ClientConnInterface) ApplicationsClient { + return &applicationsClient{cc} +} + +func (c *applicationsClient) GetApplications(ctx context.Context, in *GetApplicationsRequest, opts ...grpc.CallOption) (*GetApplicationsResponse, error) { + out := new(GetApplicationsResponse) + err := c.cc.Invoke(ctx, "/clusters.Applications/GetApplications", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *applicationsClient) GetApplication(ctx context.Context, in *GetApplicationRequest, opts ...grpc.CallOption) (*GetApplicationResponse, error) { + out := new(GetApplicationResponse) + err := c.cc.Invoke(ctx, "/clusters.Applications/GetApplication", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ApplicationsServer is the server API for Applications service. +// All implementations must embed UnimplementedApplicationsServer +// for forward compatibility +type ApplicationsServer interface { + GetApplications(context.Context, *GetApplicationsRequest) (*GetApplicationsResponse, error) + GetApplication(context.Context, *GetApplicationRequest) (*GetApplicationResponse, error) + mustEmbedUnimplementedApplicationsServer() +} + +// UnimplementedApplicationsServer must be embedded to have forward compatible implementations. +type UnimplementedApplicationsServer struct { +} + +func (UnimplementedApplicationsServer) GetApplications(context.Context, *GetApplicationsRequest) (*GetApplicationsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetApplications not implemented") +} +func (UnimplementedApplicationsServer) GetApplication(context.Context, *GetApplicationRequest) (*GetApplicationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetApplication not implemented") +} +func (UnimplementedApplicationsServer) mustEmbedUnimplementedApplicationsServer() {} + +// UnsafeApplicationsServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ApplicationsServer will +// result in compilation errors. +type UnsafeApplicationsServer interface { + mustEmbedUnimplementedApplicationsServer() +} + +func RegisterApplicationsServer(s grpc.ServiceRegistrar, srv ApplicationsServer) { + s.RegisterService(&Applications_ServiceDesc, srv) +} + +func _Applications_GetApplications_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetApplicationsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ApplicationsServer).GetApplications(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/clusters.Applications/GetApplications", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ApplicationsServer).GetApplications(ctx, req.(*GetApplicationsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Applications_GetApplication_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetApplicationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ApplicationsServer).GetApplication(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/clusters.Applications/GetApplication", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ApplicationsServer).GetApplication(ctx, req.(*GetApplicationRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Applications_ServiceDesc is the grpc.ServiceDesc for Applications service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Applications_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "clusters.Applications", + HandlerType: (*ApplicationsServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetApplications", + Handler: _Applications_GetApplications_Handler, + }, + { + MethodName: "GetApplication", + Handler: _Applications_GetApplication_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "applications.proto", +} diff --git a/pkg/generated/proto/clusters.pb.go b/pkg/generated/proto/clusters.pb.go index 553097619..8dd3d5b38 100644 --- a/pkg/generated/proto/clusters.pb.go +++ b/pkg/generated/proto/clusters.pb.go @@ -212,7 +212,8 @@ func (x *GetNamespacesResponse) GetNamespaces() []string { } // GetResourcesRequest is the request to get a specific resource for multiple clusters and namespaces. It contains the -// Kubernetes API endpoint for the resource and a list of clusters and namespaces. +// Kubernetes API endpoint for the resource and a list of clusters and namespaces. It is also possible to specify a +// parameter, which can be used to set a labelSelector or fieldSelector for the request. type GetResourcesRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -414,65 +415,317 @@ func (x *Resources) GetResourceList() string { return "" } +// GetApplicationsRequest is the message formate to get a list of applications. To get a list of applications the +// clusters and namespaces for which the applications should be retrieved must be specified. +type GetApplicationsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Clusters []string `protobuf:"bytes,1,rep,name=clusters,proto3" json:"clusters,omitempty"` + Namespaces []string `protobuf:"bytes,2,rep,name=namespaces,proto3" json:"namespaces,omitempty"` +} + +func (x *GetApplicationsRequest) Reset() { + *x = GetApplicationsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_clusters_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetApplicationsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetApplicationsRequest) ProtoMessage() {} + +func (x *GetApplicationsRequest) ProtoReflect() protoreflect.Message { + mi := &file_clusters_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetApplicationsRequest.ProtoReflect.Descriptor instead. +func (*GetApplicationsRequest) Descriptor() ([]byte, []int) { + return file_clusters_proto_rawDescGZIP(), []int{7} +} + +func (x *GetApplicationsRequest) GetClusters() []string { + if x != nil { + return x.Clusters + } + return nil +} + +func (x *GetApplicationsRequest) GetNamespaces() []string { + if x != nil { + return x.Namespaces + } + return nil +} + +// GetApplicationsResponse is the response for a GetApplications request, which returns a list of applications. +type GetApplicationsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Applications []*Application `protobuf:"bytes,1,rep,name=applications,proto3" json:"applications,omitempty"` +} + +func (x *GetApplicationsResponse) Reset() { + *x = GetApplicationsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_clusters_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetApplicationsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetApplicationsResponse) ProtoMessage() {} + +func (x *GetApplicationsResponse) ProtoReflect() protoreflect.Message { + mi := &file_clusters_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetApplicationsResponse.ProtoReflect.Descriptor instead. +func (*GetApplicationsResponse) Descriptor() ([]byte, []int) { + return file_clusters_proto_rawDescGZIP(), []int{8} +} + +func (x *GetApplicationsResponse) GetApplications() []*Application { + if x != nil { + return x.Applications + } + return nil +} + +// GetApplicationRequest is the format to get a single application. Each application can be identified by the cluster, +// namespace and name of the application. +type GetApplicationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cluster string `protobuf:"bytes,1,opt,name=cluster,proto3" json:"cluster,omitempty"` + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *GetApplicationRequest) Reset() { + *x = GetApplicationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_clusters_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetApplicationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetApplicationRequest) ProtoMessage() {} + +func (x *GetApplicationRequest) ProtoReflect() protoreflect.Message { + mi := &file_clusters_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetApplicationRequest.ProtoReflect.Descriptor instead. +func (*GetApplicationRequest) Descriptor() ([]byte, []int) { + return file_clusters_proto_rawDescGZIP(), []int{9} +} + +func (x *GetApplicationRequest) GetCluster() string { + if x != nil { + return x.Cluster + } + return "" +} + +func (x *GetApplicationRequest) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *GetApplicationRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// GetApplicationResponse is the response for a GetApplication request, which returns a single application. +type GetApplicationResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Application *Application `protobuf:"bytes,1,opt,name=application,proto3" json:"application,omitempty"` +} + +func (x *GetApplicationResponse) Reset() { + *x = GetApplicationResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_clusters_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetApplicationResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetApplicationResponse) ProtoMessage() {} + +func (x *GetApplicationResponse) ProtoReflect() protoreflect.Message { + mi := &file_clusters_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetApplicationResponse.ProtoReflect.Descriptor instead. +func (*GetApplicationResponse) Descriptor() ([]byte, []int) { + return file_clusters_proto_rawDescGZIP(), []int{10} +} + +func (x *GetApplicationResponse) GetApplication() *Application { + if x != nil { + return x.Application + } + return nil +} + var File_clusters_proto protoreflect.FileDescriptor var file_clusters_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, - 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x22, 0x31, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x73, 0x22, 0x32, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, + 0x12, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x1a, 0x12, 0x61, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x14, + 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x22, 0x31, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x22, 0x37, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, - 0x22, 0xb5, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61, 0x6d, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x22, 0x49, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x31, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x22, 0x67, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x32, 0xfd, 0x01, 0x0a, - 0x08, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x47, 0x65, 0x74, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1c, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0c, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x63, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x6c, 0x75, - 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2c, 0x5a, 0x2a, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x6f, 0x62, 0x73, 0x69, - 0x6f, 0x2f, 0x6b, 0x6f, 0x62, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x22, 0x32, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x22, 0x37, 0x0a, 0x15, 0x47, + 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x22, 0xb5, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x22, 0x49, 0x0a, 0x14, + 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x09, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x67, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1c, + 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x0c, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, + 0x22, 0x54, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x22, 0x54, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x39, 0x0a, 0x0c, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x63, 0x0a, 0x15, + 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, + 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x22, 0x51, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x32, 0xae, 0x03, 0x0a, 0x08, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, + 0x12, 0x1c, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, + 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x52, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, + 0x12, 0x1e, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1f, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, + 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x63, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x55, + 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x1f, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x41, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x20, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x6f, 0x62, 0x73, 0x69, 0x6f, 0x2f, 0x6b, 0x6f, 0x62, 0x73, 0x2f, + 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -487,29 +740,40 @@ func file_clusters_proto_rawDescGZIP() []byte { return file_clusters_proto_rawDescData } -var file_clusters_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_clusters_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_clusters_proto_goTypes = []interface{}{ - (*GetClustersRequest)(nil), // 0: clusters.GetClustersRequest - (*GetClustersResponse)(nil), // 1: clusters.GetClustersResponse - (*GetNamespacesRequest)(nil), // 2: clusters.GetNamespacesRequest - (*GetNamespacesResponse)(nil), // 3: clusters.GetNamespacesResponse - (*GetResourcesRequest)(nil), // 4: clusters.GetResourcesRequest - (*GetResourcesResponse)(nil), // 5: clusters.GetResourcesResponse - (*Resources)(nil), // 6: clusters.Resources + (*GetClustersRequest)(nil), // 0: clusters.GetClustersRequest + (*GetClustersResponse)(nil), // 1: clusters.GetClustersResponse + (*GetNamespacesRequest)(nil), // 2: clusters.GetNamespacesRequest + (*GetNamespacesResponse)(nil), // 3: clusters.GetNamespacesResponse + (*GetResourcesRequest)(nil), // 4: clusters.GetResourcesRequest + (*GetResourcesResponse)(nil), // 5: clusters.GetResourcesResponse + (*Resources)(nil), // 6: clusters.Resources + (*GetApplicationsRequest)(nil), // 7: clusters.GetApplicationsRequest + (*GetApplicationsResponse)(nil), // 8: clusters.GetApplicationsResponse + (*GetApplicationRequest)(nil), // 9: clusters.GetApplicationRequest + (*GetApplicationResponse)(nil), // 10: clusters.GetApplicationResponse + (*Application)(nil), // 11: clusters.Application } var file_clusters_proto_depIdxs = []int32{ - 6, // 0: clusters.GetResourcesResponse.resources:type_name -> clusters.Resources - 0, // 1: clusters.Clusters.GetClusters:input_type -> clusters.GetClustersRequest - 2, // 2: clusters.Clusters.GetNamespaces:input_type -> clusters.GetNamespacesRequest - 4, // 3: clusters.Clusters.GetResources:input_type -> clusters.GetResourcesRequest - 1, // 4: clusters.Clusters.GetClusters:output_type -> clusters.GetClustersResponse - 3, // 5: clusters.Clusters.GetNamespaces:output_type -> clusters.GetNamespacesResponse - 5, // 6: clusters.Clusters.GetResources:output_type -> clusters.GetResourcesResponse - 4, // [4:7] is the sub-list for method output_type - 1, // [1:4] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 6, // 0: clusters.GetResourcesResponse.resources:type_name -> clusters.Resources + 11, // 1: clusters.GetApplicationsResponse.applications:type_name -> clusters.Application + 11, // 2: clusters.GetApplicationResponse.application:type_name -> clusters.Application + 0, // 3: clusters.Clusters.GetClusters:input_type -> clusters.GetClustersRequest + 2, // 4: clusters.Clusters.GetNamespaces:input_type -> clusters.GetNamespacesRequest + 4, // 5: clusters.Clusters.GetResources:input_type -> clusters.GetResourcesRequest + 7, // 6: clusters.Clusters.GetApplications:input_type -> clusters.GetApplicationsRequest + 9, // 7: clusters.Clusters.GetApplication:input_type -> clusters.GetApplicationRequest + 1, // 8: clusters.Clusters.GetClusters:output_type -> clusters.GetClustersResponse + 3, // 9: clusters.Clusters.GetNamespaces:output_type -> clusters.GetNamespacesResponse + 5, // 10: clusters.Clusters.GetResources:output_type -> clusters.GetResourcesResponse + 8, // 11: clusters.Clusters.GetApplications:output_type -> clusters.GetApplicationsResponse + 10, // 12: clusters.Clusters.GetApplication:output_type -> clusters.GetApplicationResponse + 8, // [8:13] is the sub-list for method output_type + 3, // [3:8] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_clusters_proto_init() } @@ -517,6 +781,7 @@ func file_clusters_proto_init() { if File_clusters_proto != nil { return } + file_applications_proto_init() if !protoimpl.UnsafeEnabled { file_clusters_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetClustersRequest); i { @@ -602,6 +867,54 @@ func file_clusters_proto_init() { return nil } } + file_clusters_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetApplicationsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clusters_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetApplicationsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clusters_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetApplicationRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clusters_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetApplicationResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -609,7 +922,7 @@ func file_clusters_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_clusters_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 11, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/generated/proto/clusters_deepcopy.gen.go b/pkg/generated/proto/clusters_deepcopy.gen.go index 1fde5101d..de2b6036b 100644 --- a/pkg/generated/proto/clusters_deepcopy.gen.go +++ b/pkg/generated/proto/clusters_deepcopy.gen.go @@ -160,3 +160,87 @@ func (in *Resources) DeepCopy() *Resources { func (in *Resources) DeepCopyInterface() interface{} { return in.DeepCopy() } + +// DeepCopyInto supports using GetApplicationsRequest within kubernetes types, where deepcopy-gen is used. +func (in *GetApplicationsRequest) DeepCopyInto(out *GetApplicationsRequest) { + p := proto.Clone(in).(*GetApplicationsRequest) + *out = *p +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GetApplicationsRequest. Required by controller-gen. +func (in *GetApplicationsRequest) DeepCopy() *GetApplicationsRequest { + if in == nil { + return nil + } + out := new(GetApplicationsRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new GetApplicationsRequest. Required by controller-gen. +func (in *GetApplicationsRequest) DeepCopyInterface() interface{} { + return in.DeepCopy() +} + +// DeepCopyInto supports using GetApplicationsResponse within kubernetes types, where deepcopy-gen is used. +func (in *GetApplicationsResponse) DeepCopyInto(out *GetApplicationsResponse) { + p := proto.Clone(in).(*GetApplicationsResponse) + *out = *p +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GetApplicationsResponse. Required by controller-gen. +func (in *GetApplicationsResponse) DeepCopy() *GetApplicationsResponse { + if in == nil { + return nil + } + out := new(GetApplicationsResponse) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new GetApplicationsResponse. Required by controller-gen. +func (in *GetApplicationsResponse) DeepCopyInterface() interface{} { + return in.DeepCopy() +} + +// DeepCopyInto supports using GetApplicationRequest within kubernetes types, where deepcopy-gen is used. +func (in *GetApplicationRequest) DeepCopyInto(out *GetApplicationRequest) { + p := proto.Clone(in).(*GetApplicationRequest) + *out = *p +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GetApplicationRequest. Required by controller-gen. +func (in *GetApplicationRequest) DeepCopy() *GetApplicationRequest { + if in == nil { + return nil + } + out := new(GetApplicationRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new GetApplicationRequest. Required by controller-gen. +func (in *GetApplicationRequest) DeepCopyInterface() interface{} { + return in.DeepCopy() +} + +// DeepCopyInto supports using GetApplicationResponse within kubernetes types, where deepcopy-gen is used. +func (in *GetApplicationResponse) DeepCopyInto(out *GetApplicationResponse) { + p := proto.Clone(in).(*GetApplicationResponse) + *out = *p +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GetApplicationResponse. Required by controller-gen. +func (in *GetApplicationResponse) DeepCopy() *GetApplicationResponse { + if in == nil { + return nil + } + out := new(GetApplicationResponse) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new GetApplicationResponse. Required by controller-gen. +func (in *GetApplicationResponse) DeepCopyInterface() interface{} { + return in.DeepCopy() +} diff --git a/pkg/generated/proto/clusters_grpc.pb.go b/pkg/generated/proto/clusters_grpc.pb.go index b58ef142d..65c3c5cb4 100644 --- a/pkg/generated/proto/clusters_grpc.pb.go +++ b/pkg/generated/proto/clusters_grpc.pb.go @@ -21,6 +21,8 @@ type ClustersClient interface { GetClusters(ctx context.Context, in *GetClustersRequest, opts ...grpc.CallOption) (*GetClustersResponse, error) GetNamespaces(ctx context.Context, in *GetNamespacesRequest, opts ...grpc.CallOption) (*GetNamespacesResponse, error) GetResources(ctx context.Context, in *GetResourcesRequest, opts ...grpc.CallOption) (*GetResourcesResponse, error) + GetApplications(ctx context.Context, in *GetApplicationsRequest, opts ...grpc.CallOption) (*GetApplicationsResponse, error) + GetApplication(ctx context.Context, in *GetApplicationRequest, opts ...grpc.CallOption) (*GetApplicationResponse, error) } type clustersClient struct { @@ -58,6 +60,24 @@ func (c *clustersClient) GetResources(ctx context.Context, in *GetResourcesReque return out, nil } +func (c *clustersClient) GetApplications(ctx context.Context, in *GetApplicationsRequest, opts ...grpc.CallOption) (*GetApplicationsResponse, error) { + out := new(GetApplicationsResponse) + err := c.cc.Invoke(ctx, "/clusters.Clusters/GetApplications", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *clustersClient) GetApplication(ctx context.Context, in *GetApplicationRequest, opts ...grpc.CallOption) (*GetApplicationResponse, error) { + out := new(GetApplicationResponse) + err := c.cc.Invoke(ctx, "/clusters.Clusters/GetApplication", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ClustersServer is the server API for Clusters service. // All implementations must embed UnimplementedClustersServer // for forward compatibility @@ -65,6 +85,8 @@ type ClustersServer interface { GetClusters(context.Context, *GetClustersRequest) (*GetClustersResponse, error) GetNamespaces(context.Context, *GetNamespacesRequest) (*GetNamespacesResponse, error) GetResources(context.Context, *GetResourcesRequest) (*GetResourcesResponse, error) + GetApplications(context.Context, *GetApplicationsRequest) (*GetApplicationsResponse, error) + GetApplication(context.Context, *GetApplicationRequest) (*GetApplicationResponse, error) mustEmbedUnimplementedClustersServer() } @@ -81,6 +103,12 @@ func (UnimplementedClustersServer) GetNamespaces(context.Context, *GetNamespaces func (UnimplementedClustersServer) GetResources(context.Context, *GetResourcesRequest) (*GetResourcesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetResources not implemented") } +func (UnimplementedClustersServer) GetApplications(context.Context, *GetApplicationsRequest) (*GetApplicationsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetApplications not implemented") +} +func (UnimplementedClustersServer) GetApplication(context.Context, *GetApplicationRequest) (*GetApplicationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetApplication not implemented") +} func (UnimplementedClustersServer) mustEmbedUnimplementedClustersServer() {} // UnsafeClustersServer may be embedded to opt out of forward compatibility for this service. @@ -148,6 +176,42 @@ func _Clusters_GetResources_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Clusters_GetApplications_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetApplicationsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ClustersServer).GetApplications(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/clusters.Clusters/GetApplications", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ClustersServer).GetApplications(ctx, req.(*GetApplicationsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Clusters_GetApplication_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetApplicationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ClustersServer).GetApplication(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/clusters.Clusters/GetApplication", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ClustersServer).GetApplication(ctx, req.(*GetApplicationRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Clusters_ServiceDesc is the grpc.ServiceDesc for Clusters service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -167,6 +231,14 @@ var Clusters_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetResources", Handler: _Clusters_GetResources_Handler, }, + { + MethodName: "GetApplications", + Handler: _Clusters_GetApplications_Handler, + }, + { + MethodName: "GetApplication", + Handler: _Clusters_GetApplication_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "clusters.proto", diff --git a/proto/applications.proto b/proto/applications.proto new file mode 100644 index 000000000..f8099c486 --- /dev/null +++ b/proto/applications.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; +package clusters; + +option go_package = "github.com/kobsio/kobs/pkg/generated/proto"; + +// Application is the specification for an application. This specification is also used for the Kubernetes CRD as +// ApplicationSpec. +// This is also the reason why we use istio.io/tools/cmd/protoc-gen-deepcopy within the code generation, to generate the +// deepcopy function, which are required to use the Application within a CRD. +message Application { + string cluster = 1; + string namespace = 2; + string name = 3; + repeated ApplicationLink links = 4; + repeated ApplicationResources resources = 5; +} + +// ApplicationLink is the format of a link, which can be provided within an application. A link consists of a title, +// which is displayed in the frontend and the link link (title=Example, link=https://example.com). +message ApplicationLink { + string title = 1; + string link = 2; +} + +// ApplicationResources is the specification to retrieve all Kubernetes resources, which can be associated with the +// application. For that, a list of kinds (deployments, pods, statefulsets) as specified in +// app/src/components/resources/helpers.tsx and a selector must be set. Currently only label selector is supported, +// e.g. app=example. +message ApplicationResources { + repeated string kinds = 1; + string selector = 2; +} diff --git a/proto/clusters.proto b/proto/clusters.proto index 5a95701f4..4da6f68ad 100644 --- a/proto/clusters.proto +++ b/proto/clusters.proto @@ -3,12 +3,16 @@ package clusters; option go_package = "github.com/kobsio/kobs/pkg/generated/proto"; +import "applications.proto"; + // Clusters is the service to execute requests against all loaded Kubernetes clusters. The service can be used to get // all clusters, the namespaces for clusters and various Kubernetes resources. service Clusters { rpc GetClusters(GetClustersRequest) returns (GetClustersResponse) {} rpc GetNamespaces(GetNamespacesRequest) returns (GetNamespacesResponse) {} rpc GetResources(GetResourcesRequest) returns (GetResourcesResponse) {} + rpc GetApplications(GetApplicationsRequest) returns (GetApplicationsResponse) {} + rpc GetApplication(GetApplicationRequest) returns (GetApplicationResponse) {} } // GetClustersRequest is the request to get all loaded Kubernetes clusters via the GetClusters method. @@ -57,3 +61,28 @@ message Resources { string namespace = 2; string resourceList = 3; } + +// GetApplicationsRequest is the message formate to get a list of applications. To get a list of applications the +// clusters and namespaces for which the applications should be retrieved must be specified. +message GetApplicationsRequest { + repeated string clusters = 1; + repeated string namespaces = 2; +} + +// GetApplicationsResponse is the response for a GetApplications request, which returns a list of applications. +message GetApplicationsResponse { + repeated Application applications = 1; +} + +// GetApplicationRequest is the format to get a single application. Each application can be identified by the cluster, +// namespace and name of the application. +message GetApplicationRequest { + string cluster = 1; + string namespace = 2; + string name = 3; +} + +// GetApplicationResponse is the response for a GetApplication request, which returns a single application. +message GetApplicationResponse { + Application application = 1; +}