diff --git a/podman-desktop-extension/packages/backend/src/api-impl.ts b/podman-desktop-extension/packages/backend/src/api-impl.ts index 581aa3b28..1560418de 100644 --- a/podman-desktop-extension/packages/backend/src/api-impl.ts +++ b/podman-desktop-extension/packages/backend/src/api-impl.ts @@ -42,6 +42,7 @@ export class StreamshubImpl implements StreamshubApi { } async listConsoles(): Promise { + console.group('listConsoles'); const consoles: Record = {}; const { storagePath } = this.extensionContext; try { @@ -105,11 +106,15 @@ export class StreamshubImpl implements StreamshubApi { }; } }); - } catch {} + } catch { + console.log('storagePath empty'); + } console.log({ containers, consoleContainers, consoles }); } catch (err) { await podmanDesktopApi.window.showErrorMessage(`Error listing containers: ${err}`); console.error('Error listing containers: ', err); + } finally { + console.groupEnd(); } return Object.values(consoles); } @@ -154,7 +159,7 @@ export class StreamshubImpl implements StreamshubApi { } async getKubernetesClusters(): Promise<{ context: string; server: string; clusters: KubernetesCluster[] }> { - console.log('getKubernetesClusters'); + console.group('getKubernetesClusters'); try { const { stdout: context } = await podmanDesktopApi.process.exec('kubectl', ['config', 'current-context']); console.log('getKubernetesClusters', { context }); @@ -218,10 +223,13 @@ export class StreamshubImpl implements StreamshubApi { } catch (e) { console.error(e); throw e; + } finally { + console.groupEnd(); } } async containerChanges() { + console.log('containerChanges'); return this.notify(Messages.MSG_CONTAINERS_UPDATE); } @@ -254,6 +262,7 @@ async function getServerFromMinikube() { } async function getToken(namespace: string): Promise { + console.group('getToken'); try { const { stdout: tokenRaw } = await podmanDesktopApi.process.exec('kubectl', [ 'describe', @@ -280,56 +289,70 @@ async function getToken(namespace: string): Promise { `--duration=${365 * 24}h`, ]); return token; + } finally { + console.groupEnd(); } } async function getNamespaceJaasConfigurations(namespace: string): Promise> { - const { stdout: usersRaw } = await podmanDesktopApi.process.exec('kubectl', [ - 'get', - 'kafkausers', - '-n', - namespace, - '-o', - 'json', - ]); - const users = JSON.parse(usersRaw) as { - items: { - metadata: { - labels: { - 'strimzi.io/cluster': string; + console.group('getNamespaceJaasConfigurations'); + try { + const { stdout: usersRaw } = await podmanDesktopApi.process.exec('kubectl', [ + 'get', + 'kafkausers', + '-n', + namespace, + '-o', + 'json', + ]); + const users = JSON.parse(usersRaw) as { + items: { + metadata: { + labels: { + 'strimzi.io/cluster': string; + }; }; - }; - status: { - username: string; - secret: string; - }; - }[]; - }; - const usersList = users.items.map(u => u.status.username); - const { stdout: secretsRaw } = await podmanDesktopApi.process.exec('kubectl', [ - 'get', - 'secrets', - '-n', - namespace, - '-o', - 'json', - ...usersList, - ]); - const secrets = JSON.parse(secretsRaw) as { - items: { + status: { + username: string; + secret: string; + }; + }[]; + }; + const usersList = users.items.map(u => u.status.username); + const { stdout: secretsRaw } = await podmanDesktopApi.process.exec('kubectl', [ + 'get', + 'secrets', + '-n', + namespace, + '-o', + 'json', + ...usersList, + ]); + type Secret = { data: { 'sasl.jaas.config': string; }; metadata: { name: string; }; - }[]; - }; - const jaasConfigurations: Record = Object.fromEntries( - users.items.map(u => [ - u.metadata.labels['strimzi.io/cluster'], - secrets.items.filter(s => s.metadata.name === u.status.secret).map(s => atob(s.data['sasl.jaas.config'])), - ]), - ); - return jaasConfigurations; + }; + type Secrets = { + items: Secret[]; + }; + const secretsObj = JSON.parse(secretsRaw) as Secrets | Secret; + const secrets = 'items' in secretsObj ? secretsObj : { items: [secretsObj] }; + console.log('secrets', secrets); + const jaasConfigurations: Record = Object.fromEntries( + users.items.map(u => [ + u.metadata.labels['strimzi.io/cluster'], + secrets.items.filter(s => s.metadata.name === u.status.secret).map(s => atob(s.data['sasl.jaas.config'])), + ]), + ); + return jaasConfigurations; + } catch (e) { + console.error('getNamespaceJaasConfigurations', e); + } finally { + console.groupEnd(); + } + return {}; } diff --git a/podman-desktop-extension/packages/backend/src/extension.ts b/podman-desktop-extension/packages/backend/src/extension.ts index f409dbd6d..897db6176 100644 --- a/podman-desktop-extension/packages/backend/src/extension.ts +++ b/podman-desktop-extension/packages/backend/src/extension.ts @@ -115,7 +115,7 @@ export async function activate(extensionContext: ExtensionContext): Promise { void streamshubApi.containerChanges(); - }, 1000); + }, 100); }), ); } diff --git a/podman-desktop-extension/packages/backend/src/utils.ts b/podman-desktop-extension/packages/backend/src/utils.ts index 52f32be97..b9fec9b86 100644 --- a/podman-desktop-extension/packages/backend/src/utils.ts +++ b/podman-desktop-extension/packages/backend/src/utils.ts @@ -87,7 +87,15 @@ services: NEXTAUTH_URL: http://localhost:3000 BACKEND_URL: http://console-api:8080/ labels: - io.streamshub.console.container: ui`, + io.streamshub.console.container: ui + + console-registry: + image: quay.io/apicurio/apicurio-registry-mem:2.6.1.Final + ports: + - :8080 + labels: + io.streamshub.console.container: registry + `, ); } diff --git a/podman-desktop-extension/packages/backend/tsconfig.json b/podman-desktop-extension/packages/backend/tsconfig.json index 005fac1e1..709235852 100644 --- a/podman-desktop-extension/packages/backend/tsconfig.json +++ b/podman-desktop-extension/packages/backend/tsconfig.json @@ -7,6 +7,7 @@ "resolveJsonModule": true, "lib": [ "ES2017", + "ES2021", "webworker", "dom", ], @@ -28,4 +29,4 @@ "../shared/*.ts", "../shared/**/*.ts" ], -} \ No newline at end of file +} diff --git a/podman-desktop-extension/packages/frontend/src/Clusters.svelte b/podman-desktop-extension/packages/frontend/src/Clusters.svelte index 694cd95f0..a3767e7e5 100644 --- a/podman-desktop-extension/packages/frontend/src/Clusters.svelte +++ b/podman-desktop-extension/packages/frontend/src/Clusters.svelte @@ -5,79 +5,80 @@ import ClusterNameColumn from '/@/lib/ClusterNameColumn.svelte'; import ClusterNamespaceColumn from '/@/lib/ClusterNamespaceColumn.svelte'; import ClusterVersionColumn from '/@/lib/ClusterVersionColumn.svelte'; + import ConsoleActions from '/@/lib/ConsoleActions.svelte'; import NavPage from '/@/lib/upstream/NavPage.svelte'; import type {StreamshubConsoleInfo} from '/@shared/src/models/streamshub'; import {Table, TableColumn, TableRow} from '@podman-desktop/ui-svelte'; import {onMount} from 'svelte'; export let project: string; - let consoleObj: StreamshubConsoleInfo | undefined = undefined; - let clusters: ClusterListColumn[] | undefined = undefined; +let consoleObj: StreamshubConsoleInfo | undefined = undefined; +let clusters: ClusterListColumn[] | undefined = undefined; - type ClusterListColumn = ClusterList & { - selected: boolean; - project: string; - } - - onMount(async () => { - const consoles = await streamshubClient.listConsoles(); - consoleObj = consoles.find(c => c.project === project); - console.log({ project, consoles, object: consoleObj }); - clusters = (await getKafkaClusters()).map(c => ({ ...c, selected: false, project })); - }); +type ClusterListColumn = ClusterList & { + selected: boolean; + project: string; +}; +onMount(async () => { + const consoles = await streamshubClient.listConsoles(); + consoleObj = consoles.find(c => c.project === project); + console.log({ project, consoles, object: consoleObj }); + clusters = (await getKafkaClusters()).map(c => ({ ...c, selected: false, project })); +}); - async function getKafkaClusters(): Promise { - const sp = new URLSearchParams({ - 'fields[kafkas]': 'name,namespace,kafkaVersion', - sort: 'name', - }); - const kafkaClustersQuery = sp.toString(); - const url = `${consoleObj!.api.baseUrl}/api/kafkas?${kafkaClustersQuery}`; - try { - const res = await fetch(url); - const rawData = await res.json(); - console.log('getKafkaClusters', rawData); - return ClustersResponseSchema.parse(rawData).data; - } catch (err) { - console.error('getKafkaClusters', err); - return []; - } +async function getKafkaClusters(): Promise { + const sp = new URLSearchParams({ + 'fields[kafkas]': 'name,namespace,kafkaVersion', + sort: 'name', + }); + const kafkaClustersQuery = sp.toString(); + const url = `${consoleObj!.api.baseUrl}/api/kafkas?${kafkaClustersQuery}`; + try { + const res = await fetch(url); + const rawData = await res.json(); + console.log('getKafkaClusters', rawData); + return ClustersResponseSchema.parse(rawData).data; + } catch (err) { + console.error('getKafkaClusters', err); + return []; } +} - let selectedItemsNumber: number; - let table: Table; +let selectedItemsNumber: number; +let table: Table; - let nameColumn = new TableColumn('Cluster', { - renderer: ClusterNameColumn, - comparator: (a, b) => a.attributes.name.localeCompare(b.attributes.name), - }); +let nameColumn = new TableColumn('Cluster', { + renderer: ClusterNameColumn, + comparator: (a, b) => a.attributes.name.localeCompare(b.attributes.name), +}); - let namespaceColumn = new TableColumn('Kubernetes namespace', { - renderer: ClusterNamespaceColumn, - comparator: (a, b) => a.attributes.namespace.localeCompare(b.attributes.namespace), - }); +let namespaceColumn = new TableColumn('Kubernetes namespace', { + renderer: ClusterNamespaceColumn, + comparator: (a, b) => a.attributes.namespace.localeCompare(b.attributes.namespace), +}); - let versionColumn = new TableColumn('Kafka version', { - renderer: ClusterVersionColumn, - comparator: (a, b) => a.attributes.namespace.localeCompare(b.attributes.namespace), - }); +let versionColumn = new TableColumn('Kafka version', { + renderer: ClusterVersionColumn, + comparator: (a, b) => a.attributes.namespace.localeCompare(b.attributes.namespace), +}); - const columns: TableColumn[] = [ - nameColumn, - namespaceColumn, - versionColumn, - ]; +const columns: TableColumn[] = [nameColumn, namespaceColumn, versionColumn]; - const row = new TableRow({}); +const row = new TableRow({}); + title="{consoleObj?.project ?? ''}"> + + {#if consoleObj} + + {/if} + +
{#if clusters} - diff --git a/podman-desktop-extension/packages/frontend/src/ConsoleWizard.svelte b/podman-desktop-extension/packages/frontend/src/ConsoleWizard.svelte index 4b41cff22..ea5205fd8 100644 --- a/podman-desktop-extension/packages/frontend/src/ConsoleWizard.svelte +++ b/podman-desktop-extension/packages/frontend/src/ConsoleWizard.svelte @@ -1,13 +1,14 @@ - -
- -
-
- - - -
-

- This will be used to create a directory on your filesystem in this extension's storage path. -
-
* It must be a unique name. -
* Name must be at least 3 characters long. -
* Only characters and numbers allowed. -

-
- -
-
-

Kubernetes connection details

-
-
- - - -
-
- - - -
-
- -
-
-

Strimzi CR details

-
-
- - - - - - - - - - - -

Name of the Strimzi Kafka CR

-
-
- - - -

Namespace of the Strimzi Kafka CR

-
-
- - - - - - - - - - - + {#if state === 'ready'} + + +
+
+ + + +

- Name of the listener to use for connections from the console + This will be used to create a directory on your filesystem in this extension's storage path. +
+
* It must be a unique name. +
* Name must be at least 3 characters long. +
* Only characters and numbers allowed.

-
-
-
-

Kafka connection properties (optional)

-
-
- - - -

- If omitted the bootstrap servers from the Strimzi Kafka CR are used -

-
-
- - - + +
+
+

Kubernetes connection details

+
+
+ + + +
+
+ + + +
-
- - - + +
+
+

Strimzi CR details

+
+
+ + + + + + + + + + + +

Name of the Strimzi Kafka CR

+
+
+ + + +

Namespace of the Strimzi Kafka CR

+
+
+ + + + + + + + + + + +

+ Name of the listener to use for connections from the console +

+
-
- - - +
+
+

Kafka connection properties (optional)

+
+
+ + + +

+ If omitted the bootstrap servers from the Strimzi Kafka CR are used +

+
+
+ + + +
+
+ + + +
+
+ + + +
-
-
-
- -
-
- +
+
+ +
+
+ + {:else if state === 'creating'} + + Creating console... + {:else if state === 'created'} + + + + {/if} diff --git a/podman-desktop-extension/packages/frontend/src/lib/ConsoleActions.svelte b/podman-desktop-extension/packages/frontend/src/lib/ConsoleActions.svelte index d8d147bd4..a0b325833 100644 --- a/podman-desktop-extension/packages/frontend/src/lib/ConsoleActions.svelte +++ b/podman-desktop-extension/packages/frontend/src/lib/ConsoleActions.svelte @@ -6,6 +6,7 @@ import ListItemButtonIcon from './upstream/ListItemButtonIcon.svelte'; export let object: StreamshubConsoleInfo; + export let showManagedActions = true; // Delete the build async function openEmbeddedConsole(): Promise { @@ -37,7 +38,7 @@ onClick="{() => openConsole()}" title="Open console in an external browser" /> -{#if object.managed} +{#if object.managed && showManagedActions} {#if object.api.status === 'running'} ; - abstract getKubernetesClusters(): Promise<{ context: string; clusters: KubernetesCluster[] }>; + abstract getKubernetesClusters(): Promise<{ context: string; clusters: KubernetesCluster[]; server: string }>; abstract telemetryLogUsage(eventName: string, data?: Record | undefined): Promise;