Skip to content

Commit

Permalink
fix(kubernetes-actions): support adding labels while creating namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
rohitkrai03 committed Feb 16, 2024
1 parent 3046014 commit 0eca24d
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 11 deletions.
18 changes: 10 additions & 8 deletions plugins/kubernetes-actions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ input:
token: TOKEN
skipTLSVerify: false
caData: Zm9v
labels: app.io/type=ns; app.io/managed-by=org;
```
## Usage
Expand All @@ -108,14 +109,15 @@ input:
#### Input
| Parameter Name | Type | Required | Description | Example |
| -------------- | :-----: | :------: | --------------------------------------------------- | --------------------------------- |
| namespace | string | Yes | Kubernetes namespace name | foo |
| clusterRef | string | No | Cluster resource entity reference from the catalog | bar |
| url | string | No | API url of the kubernetes cluster | <https://api.foo.redhat.com:6443> |
| token | string | No | Kubernetes API bearer token used for authentication | |
| skipTLSVerify | boolean | No | If true, certificate verification is skipped | false |
| caData | string | No | Base64 encoded certificate data | |
| Parameter Name | Type | Required | Description | Example |
| -------------- | :-----: | :------: | --------------------------------------------------- | -------------------------------------- |
| namespace | string | Yes | Kubernetes namespace name | foo |
| clusterRef | string | No | Cluster resource entity reference from the catalog | bar |
| url | string | No | API url of the kubernetes cluster | <https://api.foo.redhat.com:6443> |
| token | string | No | Kubernetes API bearer token used for authentication | |
| skipTLSVerify | boolean | No | If true, certificate verification is skipped | false |
| caData | string | No | Base64 encoded certificate data | |
| label | string | No | Labels that will be applied to the namespace | app.io/type=ns; app.io/managed-by=org; |
#### Output
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ spec:
title: CA data
type: string
description: Certificate Authority base64 encoded certificate
labels:
title: Labels
type: string
description: Labels to be applied to the namespace
ui:widget: textarea
ui:options:
rows: 3
ui:help: 'Hint: Separate multiple labels with a semicolon!'
ui:placeholder: 'kubernetes.io/type=namespace; app.io/managed-by=org'


steps:
- id: create-kubernetes-namespace
Expand All @@ -51,3 +61,4 @@ spec:
token: ${{ parameters.token }}
skipTLSVerify: ${{ parameters.skipTLSVerify }}
caData: ${{ parameters.caData }}
labels: ${{ parameters.labels }}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import { setupServer } from 'msw/node';
import os from 'os';
import { PassThrough } from 'stream';

import { createKubernetesNamespaceAction } from './createKubernetesNamespace';
import {
convertLabelsToObject,
createKubernetesNamespaceAction,
} from './createKubernetesNamespace';

const LOCAL_ADDR = 'http://localhost:5000';
const FIXTURES_DIR = `${__dirname}/../../__fixtures__/cluster-entities`;
Expand Down Expand Up @@ -224,3 +227,31 @@ describe('kubernetes:create-namespace', () => {
}).rejects.toThrow('Cluster reference or url are required');
});
});

describe('convertLabelsToObject', () => {
test('converts labels string to object', () => {
const labelsString = 'key1=value1;key2=value2;key3=value3';
const expectedObject = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
};
expect(convertLabelsToObject(labelsString)).toEqual(expectedObject);
});

test('handles empty string', () => {
expect(convertLabelsToObject('')).toEqual({});
});

test('handles invalid input', () => {
// No '=' in the string
expect(convertLabelsToObject('key1value1;')).toEqual({});
});

test('handles invalid labels', () => {
// Label without '='
expect(convertLabelsToObject('key1value1;key2=value2;=value3')).toEqual({
key2: 'value2',
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type TemplateActionParameters = {
token: string;
skipTLSVerify?: boolean;
caData?: string;
labels?: string;
};

const getUrlFromClusterRef = async (
Expand Down Expand Up @@ -74,6 +75,38 @@ const validateUrl = (url: string | undefined = '') => {
}
};

export const convertLabelsToObject = (
labelsString: string | undefined,
): { [key: string]: string } => {
const result: { [key: string]: string } = {};

if (!labelsString || labelsString.indexOf('=') === -1) {
console.error(
"Invalid label string. Label string must contain at least one label separated by '=' character.",
);
return result;
}

const labelsArray = labelsString.split(';');

labelsArray.forEach(label => {
const separatorIndex = label.indexOf('=');
if (separatorIndex !== -1) {
const key = label.slice(0, separatorIndex).trim();
const value = label.slice(separatorIndex + 1).trim();
if (key && value) {
result[key] = value;
}
} else {
console.error(
`Invalid label: '${label}'. Label must contain at least one '=' character.`,
);
}
});

return result;
};

export function createKubernetesNamespaceAction(catalogClient: CatalogClient) {
return createTemplateAction<TemplateActionParameters>({
id: 'kubernetes:create-namespace',
Expand Down Expand Up @@ -118,12 +151,24 @@ export function createKubernetesNamespaceAction(catalogClient: CatalogClient) {
description: 'Certificate Authority base64 encoded certificate',
type: 'string',
},
labels: {
title: 'Labels',
description: 'Labels that will be applied to the namespace.',
type: 'string',
},
},
},
},
async handler(ctx) {
const { namespace, clusterRef, token, url, skipTLSVerify, caData } =
ctx.input;
const {
namespace,
clusterRef,
token,
url,
skipTLSVerify,
caData,
labels,
} = ctx.input;
const kubeConfig = new KubeConfig();
const name = 'backstage';
const cluster = {
Expand Down Expand Up @@ -168,10 +213,13 @@ export function createKubernetesNamespaceAction(catalogClient: CatalogClient) {
currentContext: name,
});

const namespaceLabels = convertLabelsToObject(labels);

const api = kubeConfig.makeApiClient(CoreV1Api);
const k8sNamespace: V1Namespace = {
metadata: {
name: namespace,
labels: namespaceLabels,
},
};
await api.createNamespace(k8sNamespace).catch((e: HttpError) => {
Expand Down

0 comments on commit 0eca24d

Please sign in to comment.