Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flux Runtime Card and Page #55

Merged
merged 34 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
dd99132
Add get deployments across clusters hook
AlinaGoaga Oct 17, 2023
6f5707f
Add flux runtime card - WIP
AlinaGoaga Oct 18, 2023
cc53d00
Update proxy mock and getAllDeployments function
AlinaGoaga Oct 19, 2023
5e967e7
Install react query to retrieve data in getAllDeployments
AlinaGoaga Oct 20, 2023
c8f7295
Update flux runtime card to be organized around the clusters rather t…
AlinaGoaga Oct 21, 2023
b69fd15
Add tests for the Flux Runtime Card - WIP
AlinaGoaga Oct 21, 2023
101639f
Add test for getDeploymentsLists - WIP
AlinaGoaga Oct 21, 2023
5fc53ab
Add test for getDeploymentsLists - WIP2
AlinaGoaga Oct 21, 2023
91b2cc8
Add mock implementation for getClusters in getDeploymentsList test
AlinaGoaga Oct 23, 2023
36579a1
Update useWeaveFluxDeepLink to remove Flux Controller as we won't be …
AlinaGoaga Oct 23, 2023
8140a81
Fix the clusterNameFilteringColumn for flux runtime
AlinaGoaga Oct 23, 2023
4cc967b
Update flux runtime card to use a local ct rather than importing from…
AlinaGoaga Oct 23, 2023
bf039b9
Update data retrieval to work with dynamic workspaces - WIP
AlinaGoaga Oct 25, 2023
e51aedb
Update data retrieval to work with dynamic workspaces
AlinaGoaga Oct 25, 2023
02cd792
Solve linting errors
AlinaGoaga Oct 25, 2023
8bd5842
Small cleanup
AlinaGoaga Oct 25, 2023
a1814df
Update useGetDeployments test
AlinaGoaga Oct 25, 2023
9fd2c04
Adjust deployment structure to match k8s
AlinaGoaga Oct 26, 2023
2a7726f
Adjust deployment structure to match k8s - updated
AlinaGoaga Oct 26, 2023
3cb9112
Add clusterName as flux controllers are retrieved
AlinaGoaga Oct 26, 2023
3758906
Update types to include the flux controller cluster name
AlinaGoaga Oct 26, 2023
55f9fc5
Add Flux Runtime Page
AlinaGoaga Oct 26, 2023
9dbf311
Add Flux Runtime Page - nav and icon
AlinaGoaga Oct 27, 2023
cae0d9b
Add Flux Runtime Page - update layout
AlinaGoaga Oct 27, 2023
1b6225f
Fix up ns.name -> ns.metadata.name
foot Oct 27, 2023
60214fd
Update page exports and readme with how to add a page - WIP
AlinaGoaga Oct 27, 2023
27302f8
Merge branch 'flux-runtime' of github.com:weaveworks/weaveworks-backs…
AlinaGoaga Oct 27, 2023
71f2f9b
Update readme with instructions on how to add a page
AlinaGoaga Oct 27, 2023
470a87a
Adjust ns type in test
AlinaGoaga Oct 27, 2023
e0c4f65
Update Readme instructions on how to use page
AlinaGoaga Oct 30, 2023
57b937b
Update test mock in flux runtime for deployments and namespace
AlinaGoaga Oct 30, 2023
439178c
Add default return value for proxy in tests
AlinaGoaga Oct 30, 2023
226c36a
Small copy tweaks
foot Oct 30, 2023
7cf284c
Update plugins/backstage-plugin-flux/README.md
AlinaGoaga Oct 30, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { apis } from './apis';
import { entityPage } from './components/catalog/EntityPage';
import { searchPage } from './components/search/SearchPage';
import { Root } from './components/Root';

import { AlertDisplay, OAuthRequestDialog } from '@backstage/core-components';
import { githubAuthApiRef } from '@backstage/core-plugin-api';
import { SignInPage } from '@backstage/core-components';
Expand All @@ -36,6 +35,7 @@ import { CatalogGraphPage } from '@backstage/plugin-catalog-graph';
import { RequirePermission } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
import { EntityFluxHelmReleasesCard } from '@weaveworksoss/backstage-plugin-flux';
import { FluxRuntimePage } from '@weaveworksoss/backstage-plugin-flux';

const app = createApp({
components: {
Expand Down Expand Up @@ -111,6 +111,7 @@ const routes = (
<Route path="/settings" element={<UserSettingsPage />} />
<Route path="/catalog-graph" element={<CatalogGraphPage />} />
<Route path="/weaveworks-flux" element={<EntityFluxHelmReleasesCard />} />
<Route path="/flux-runtime" element={<FluxRuntimePage />} />
</FlatRoutes>
);

Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/components/Root/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from '@backstage/core-components';
import MenuIcon from '@material-ui/icons/Menu';
import SearchIcon from '@material-ui/icons/Search';
import { FluxIcon } from '@weaveworksoss/backstage-plugin-flux';

const useSidebarLogoStyles = makeStyles({
root: {
Expand Down Expand Up @@ -73,6 +74,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarDivider />
<SidebarScrollWrapper>
<SidebarItem icon={MapIcon} to="tech-radar" text="Tech Radar" />
<SidebarItem icon={FluxIcon} to="flux-runtime" text="Flux Runtime" />
</SidebarScrollWrapper>
</SidebarGroup>
<SidebarSpace />
Expand Down
66 changes: 65 additions & 1 deletion plugins/backstage-plugin-flux/README.md
AlinaGoaga marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ You can also add cards for resources with the following components, each of thes
- EntityFluxOCIRepositoriesCard
- EntityFluxHelmRepositoriesCard
- EntityFluxImagePoliciesCard
- FluxRuntimeCard

As with other Backstage plugins, you can compose the UI you need.

Expand Down Expand Up @@ -277,6 +278,70 @@ kubernetes:
caData: LS0tLS1CRUdJTiBDRVJUSUZJQ0...
```

6. [Optional] Add a Card to a Page

- Create a page: An example of a basic page can be found at [Flux Runtime Page](https://github.com/weaveworks/weaveworks-backstage/plugins/backstage-plugin-flux/src/components/FluxRuntimePage/index.tsx/).

- Add the page to the plugin exports:

```tsx
// In plugins/backstage-plugin-flux/src/plugin.ts

/**
* Page used to show Flux Controllers / Deployments in Flux Runtime
* @public
*/
export const FluxRuntimePage = weaveworksFluxPlugin.provide(
createRoutableExtension({
name: 'FluxRuntimePage',
component: () =>
import('./components/FluxRuntimePage').then(m => m.FluxRuntimePage),
mountPoint: rootRouteRef,
}),
);
```
AlinaGoaga marked this conversation as resolved.
Show resolved Hide resolved

```tsx
// In plugins/backstage-plugin-flux/src/index.ts
AlinaGoaga marked this conversation as resolved.
Show resolved Hide resolved

export {
....
FluxRuntimePage,
} from './plugin';
```

- Add the page to the `App.tsx` file at the root of the project:

```tsx
// In packages/app/src/App.tsx

const routes = (
<FlatRoutes>
...
<Route path="/flux-runtime" element={<FluxRuntimePage >} />
</FlatRoutes>
);
```

- Add the page to the navigation bar:

```tsx
// In packages/app/src/components/Root/Root.tsx

AlinaGoaga marked this conversation as resolved.
Show resolved Hide resolved
export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarPage>
<Sidebar>
<SidebarGroup label="Menu" icon={<MenuIcon />}>
...
<SidebarScrollWrapper>
<SidebarItem icon={FluxIcon} to="flux-runtime" text="Flux Runtime" />
</SidebarScrollWrapper>
</SidebarGroup>
</Sidebar>
{children}
</SidebarPage>
```

## Verification

For the resources where we display a Verification status, if the Flux resource
Expand All @@ -302,4 +367,3 @@ Request failed with 401 Unauthorized, {"error":{"name":"AuthenticationError","me
This is likely caused by this issue in [Backstage](https://github.com/backstage/backstage/issues/12394).

The simplest thing to do is put some sort of authentication in front of your Backstage setup, for example using the [GitHub Authentication Provider](https://backstage.io/docs/auth/github/provider/) this will ensure there's an authentication token available.

23 changes: 23 additions & 0 deletions plugins/backstage-plugin-flux/dev/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,26 @@ export const newTestImagePolicy = (
},
};
};

export const newTestFluxController = (
name: string,
namespace: string,
labels: { [name: string]: string },
) => {
return {
apiVersion: 'meta.k8s.io/v1',
kind: 'PartialObjectMetadata',
metadata: {
name,
namespace,
uid: 'b062d329-538d-4bb3-b4df-b2ac4b06dba8',
resourceVersion: '1001263',
generation: 1,
creationTimestamp: '2023-10-19T16:34:14Z',
labels,
annotations: {
'deployment.kubernetes.io/revision': '1',
},
},
};
};
160 changes: 157 additions & 3 deletions plugins/backstage-plugin-flux/dev/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,16 @@ import {
newTestKustomization,
newTestHelmRepository,
newTestImagePolicy,
newTestFluxController,
} from './helpers';
import { ReconcileRequestAnnotation } from '../src/hooks';
import { EntityFluxSourcesCard } from '../src/components/EntityFluxSourcesCard';
import { FluxRuntimeCard } from '../src/components/FluxRuntimeCard';
import {
NAMESPACES_PATH,
getDeploymentsPath,
} from '../src/hooks/useGetDeployments';
import { Namespace } from '../src/objects';

const fakeEntity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
Expand Down Expand Up @@ -72,7 +79,10 @@ class StubKubernetesClient implements KubernetesApi {

async getClusters(): Promise<{ name: string; authProvider: string }[]> {
await new Promise(resolve => setTimeout(resolve, 100));
return [{ name: 'mock-cluster', authProvider: 'serviceAccount' }];
return [
{ name: 'mock-cluster-1', authProvider: 'serviceAccount1' },
{ name: 'mock-cluster-2', authProvider: 'serviceAccount2' },
];
}

getWorkloadsByEntity(
Expand Down Expand Up @@ -117,12 +127,12 @@ class StubKubernetesClient implements KubernetesApi {
};
}

// this is only used by sync and suspend/resume
async proxy({
clusterName,
init,
path,
}: {
clusterName: string;
clusterName?: string;
path: string;
init?: RequestInit | undefined;
}): Promise<any> {
Expand Down Expand Up @@ -174,6 +184,93 @@ class StubKubernetesClient implements KubernetesApi {
} as Response;
}

if (!init?.method && path === NAMESPACES_PATH) {
if (clusterName === 'mock-cluster-1') {
return {
ok: true,
json: () =>
Promise.resolve({
kind: 'NamespacesList',
apiVersion: 'meta.k8s.io/v1',
items: [
{
metadata: {
name: 'flux-system',
labels: {
'app.kubernetes.io/instance': 'flux-system',
'app.kubernetes.io/part-of': 'flux',
'app.kubernetes.io/version': 'v2.0.0',
'kubernetes.io/metadata.name': 'flux-system',
'kustomize.toolkit.fluxcd.io/name': 'flux-system',
'kustomize.toolkit.fluxcd.io/namespace': 'flux-system',
'pod-security.kubernetes.io/warn': 'restricted',
'pod-security.kubernetes.io/warn-version': 'latest',
},
uid: '1dcca7cb-c651-4a86-93b4-ecf440df2353',
resourceVersion: '1583',
creationTimestamp: '2023-10-19T16:34:12Z',
},
} as Namespace,
],
}),
} as Response;
}
if (clusterName === 'mock-cluster-2') {
return {
ok: true,
json: () =>
Promise.resolve({
kind: 'NamespacesList',
apiVersion: 'meta.k8s.io/v1',
items: [
{
metadata: {
name: 'default',
uid: '1dcca7cb-c651-4a86-93b4-ecf440df2353',
resourceVersion: '1583',
creationTimestamp: '2023-10-19T16:34:12Z',
labels: {
'app.kubernetes.io/instance': 'default',
'app.kubernetes.io/part-of': 'flux',
'app.kubernetes.io/version': 'v2.0.0',
'kubernetes.io/metadata.name': 'default',
'kustomize.toolkit.fluxcd.io/name': 'default',
'kustomize.toolkit.fluxcd.io/namespace': 'default',
'pod-security.kubernetes.io/warn': 'restricted',
'pod-security.kubernetes.io/warn-version': 'latest',
},
},
} as Namespace,
],
}),
} as Response;
}
}

if (!init?.method && path === getDeploymentsPath('flux-system')) {
return {
ok: true,
json: () =>
Promise.resolve({
kind: 'DeploymentList',
apiVersion: 'apps/v1',
items: [this.resources[0], this.resources[1]],
}),
} as Response;
}

if (!init?.method && path === getDeploymentsPath('default')) {
return {
ok: true,
json: () =>
Promise.resolve({
kind: 'DeploymentList',
apiVersion: 'apps/v1',
items: [this.resources[2]],
}),
} as Response;
}

// very simple right now
if (this.mockResponses[path]?.length) {
// shift pops the [0]th element off the array
Expand Down Expand Up @@ -605,5 +702,62 @@ createDevApp()
</TestApiProvider>
),
})
.addPage({
title: 'Flux Runtime',
path: '/flux_runtime',
element: (
<TestApiProvider
apis={[
[
configApiRef,
new ConfigReader({
gitops: { baseUrl: 'https://example.com/wego' },
}),
],
[
kubernetesApiRef,
new StubKubernetesClient([
newTestFluxController('helm-controller', 'flux-system', {
'app.kubernetes.io/component': 'helm-controller',
'app.kubernetes.io/instance': 'flux-system',
'app.kubernetes.io/part-of': 'flux',
'app.kubernetes.io/version': 'v2.1.2',
'control-plane': 'controller',
'kustomize.toolkit.fluxcd.io/name': 'flux-system',
'kustomize.toolkit.fluxcd.io/namespace': 'flux-system',
}),
newTestFluxController(
'image-automation-controller',
'flux-system',
{
'app.kubernetes.io/component': 'image-automation-controller',
'app.kubernetes.io/instance': 'flux-system',
'app.kubernetes.io/part-of': 'flux',
'app.kubernetes.io/version': 'v2.1.2',
'control-plane': 'controller',
'kustomize.toolkit.fluxcd.io/name': 'flux-system',
'kustomize.toolkit.fluxcd.io/namespace': 'flux-system',
},
),
newTestFluxController('image-automation-controller', 'default', {
'app.kubernetes.io/component': 'image-automation-controller',
'app.kubernetes.io/instance': 'default',
'app.kubernetes.io/part-of': 'flux',
'app.kubernetes.io/version': 'v2.1.2',
'control-plane': 'controller',
'kustomize.toolkit.fluxcd.io/name': 'default',
'kustomize.toolkit.fluxcd.io/namespace': 'default',
}),
]),
],
[kubernetesAuthProvidersApiRef, new StubKubernetesAuthProvidersApi()],
]}
>
<Content>
<FluxRuntimeCard />
</Content>
</TestApiProvider>
),
})
.registerPlugin(weaveworksFluxPlugin)
.render();
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export function FluxEntityTable<T extends object = {}>({
emptyContent={
<div className={classes.empty}>
<Typography variant="body1">
No {title} found for this entity.
No {title} found
{title === 'flux controllers' ? '' : 'for this entity'}.
</Typography>
</div>
}
Expand Down
Loading
Loading