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

Updates sync command #215

Merged
merged 1 commit into from
Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions src/api/kubectl/config-map.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {AbstractKubernetesResourceManager, KubeResource, ListOptions, Props} from './kubernetes-resource-manager';
import {AbstractKubernetesNamespacedResource, KubeResource, ListOptions, Props} from './kubernetes-resource-manager';
import {BuildContext, Factory, ObjectFactory} from 'typescript-ioc';
import {AsyncKubeClient} from './client';

Expand All @@ -15,7 +15,7 @@ const factory: ObjectFactory = (context: BuildContext) => {
};

@Factory(factory)
export class KubeConfigMap extends AbstractKubernetesResourceManager<ConfigMap> {
export class KubeConfigMap extends AbstractKubernetesNamespacedResource<ConfigMap> {
constructor(props: Props) {
super(props);
}
Expand Down
4 changes: 2 additions & 2 deletions src/api/kubectl/deployment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {BuildContext, Factory, Inject, ObjectFactory} from 'typescript-ioc';
import {AsyncKubeClient} from './client';
import {AbstractKubernetesResourceManager, KubeResource, Props} from './kubernetes-resource-manager';
import {AbstractKubernetesNamespacedResource, KubeResource, Props} from './kubernetes-resource-manager';
import {timer} from '../../util/timer';
import {Logger} from '../../util/logger';

Expand All @@ -25,7 +25,7 @@ const factory: ObjectFactory = (context: BuildContext) => {
};

@Factory(factory)
export class KubeDeployment extends AbstractKubernetesResourceManager<Deployment> {
export class KubeDeployment extends AbstractKubernetesNamespacedResource<Deployment> {
@Inject logger: Logger;

constructor(props: Props) {
Expand Down
4 changes: 2 additions & 2 deletions src/api/kubectl/ingress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {BuildContext, Factory, ObjectFactory} from 'typescript-ioc';
import * as _ from 'lodash';

import {AsyncKubeClient, KubeClient} from './client';
import {AbstractKubernetesResourceManager, KubeResource, Props} from './kubernetes-resource-manager';
import {AbstractKubernetesNamespacedResource, KubeResource, Props} from './kubernetes-resource-manager';

export interface Ingress extends KubeResource {
spec: {
Expand Down Expand Up @@ -36,7 +36,7 @@ const factory: ObjectFactory = (context: BuildContext) => {
};

@Factory(factory)
export class KubeIngress extends AbstractKubernetesResourceManager<Ingress> {
export class KubeIngress extends AbstractKubernetesNamespacedResource<Ingress> {
constructor(props: Props) {
super(props);
}
Expand Down
8 changes: 4 additions & 4 deletions src/api/kubectl/kubernetes-resource-manager.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
AbstractKubernetesResourceManager,
AbstractKubernetesNamespacedResource,
KubeBody,
KubeResource,
KubeResourceList,
Expand Down Expand Up @@ -30,7 +30,7 @@ export const testV1Provider: ObjectFactory = (context: BuildContext) => {
};

@Factory(testV1Provider)
class TestV1KubernetesResource extends AbstractKubernetesResourceManager<TestResource> {
class TestV1KubernetesResource extends AbstractKubernetesNamespacedResource<TestResource> {
}


Expand All @@ -45,7 +45,7 @@ export const testV1Beta1Provider: ObjectFactory = (context: BuildContext) => {
};

@Factory(testV1Beta1Provider)
class TestV1Beta1KubernetesResource extends AbstractKubernetesResourceManager<TestResource> {
class TestV1Beta1KubernetesResource extends AbstractKubernetesNamespacedResource<TestResource> {
constructor(props: Props) {
super(props);
}
Expand All @@ -56,7 +56,7 @@ describe('kubernetes-resource-manager', () => {
expect(true).toEqual(true);
});

let classUnderTest: AbstractKubernetesResourceManager<TestResource>;
let classUnderTest: AbstractKubernetesNamespacedResource<TestResource>;
let mockClient: KubeClient;
beforeEach(() => {
mockClient = buildMockKubeClient();
Expand Down
200 changes: 198 additions & 2 deletions src/api/kubectl/kubernetes-resource-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,21 @@ export interface QueryString {
pretty?: boolean;
}

export abstract class KubernetesResourceManager<T extends KubeResource> {
export abstract class KubernetesClusterResource<T extends KubeResource> {
abstract list(options?: ListOptions<T>): Promise<Array<T>>;

abstract createOrUpdate(name: string, body: KubeBody<T>): Promise<T>;

abstract create(name: string, body: KubeBody<T>): Promise<T>;

abstract update(name: string, body: KubeBody<T>): Promise<T>;

abstract exists(name: string): Promise<boolean>;

abstract 'get'(name: string): Promise<T>;
}

export abstract class KubernetesNamespacedResource<T extends KubeResource> {
abstract list(options?: ListOptions<T>): Promise<Array<T>>;

abstract createOrUpdate(name: string, body: KubeBody<T>, namespace?: string): Promise<T>;
Expand Down Expand Up @@ -117,7 +131,189 @@ async function registerCrdSchema(wrappedClient: AsyncKubeClient, name: string):
}
}

export class AbstractKubernetesResourceManager<T extends KubeResource> implements KubernetesResourceManager<T> {

export class AbstractKubernetesClusterResource<T extends KubeResource> implements KubernetesClusterResource<T> {
public client: AsyncKubeClient;
public group?: string;
version: string;
name: string;
kind: string;
crdPromise: Promise<boolean>;

constructor(props: Props) {
this.client = props.client;
this.group = props.group;
this.version = props.version || 'v1';
this.name = props.name;
this.kind = props.kind;

if (!this.name || !this.kind) {
throw new Error('kind must be defined');
}

if (props.crd) {
this.crdPromise = registerCrdSchema(this.client, `${this.name}.${this.group}`);
} else {
this.crdPromise = Promise.resolve(true);
}
}

async list(options: ListOptions<T> = {}): Promise<Array<T>> {

const getOptions: Query<T> = this.buildQuery(options);

const kubeResource: any = await this.resourceNode(this.group, this.version, this.name);

if (kubeResource) {
const result: KubeBody<KubeResourceList<T>> = await kubeResource.get(getOptions);

const items: T[] = _.get(result, 'body.items', [])
.filter(options.filter || (() => true))
.map(options.map || (val => val));

return items;
} else {
return [];
}
}

buildQuery(options: ListOptions<T>): Query<T> {
return {qs: options.qs};
}

async createOrUpdate(name: string, input: KubeBody<T>): Promise<T> {

const kubeResource = await this.resourceNode(this.group, this.version, this.name);

if (kubeResource) {
const processedName = this.processName(name);

if (await this.exists(processedName)) {
const current: T = await this.get(processedName);

const processedBody = this.processInputs(processedName, input.body, current);

return kubeResource(processedName).put(processedBody).then(result => result.body);
} else {
const processedBody = this.processInputs(processedName, input.body);

return kubeResource.post(processedBody).then(result => result.body);
}
} else {
return {} as any;
}
}

async create(name: string, input: KubeBody<T>): Promise<T> {

const kubeResource = await this.resourceNode(this.group, this.version, this.name);

const processedName = this.processName(name);
const processedBody = this.processInputs(processedName, input.body);

const result: KubeBody<T> = await kubeResource.post(processedBody);

return result.body;
}

async update(name: string, input: KubeBody<T>): Promise<T> {

const kubeResource = await this.resourceNode(this.group, this.version, this.name);

const current: T = await this.get(name);

const processedName = this.processName(name);
const processedBody = this.processInputs(processedName, input.body, current);

const result: KubeBody<T> = await kubeResource(processedName).put(processedBody);

return result.body;
}

async exists(name: string): Promise<boolean> {
const kubeResource = await this.resourceNode(this.group, this.version, this.name);

try {
const result = await kubeResource(name).get();

if (result) {
return true;
}
} catch (err) {
}

return false;
}

async get(name: string): Promise<T> {
const kubeResource = await this.resourceNode(this.group, this.version, this.name);

const result = await kubeResource(name).get();

return _.get(result, 'body');
}

async getLabel(name: string, labelName: string): Promise<string> {
const resource = await this.get(name);

const labels: string[] = Object.keys(resource.metadata.labels || {})
.filter(name => name === labelName)
.map(name => resource.metadata.labels[name]);

return labels.length > 0 ? labels[0] : undefined;
}

async resourceNode(group: string | undefined, version: string, kind: string) {

await this.crdPromise;

const versionPath: string[] = !group
? ['api', version]
: ['apis', group, version];

const client: KubeClient = await this.client.get();

const versionNode = _.get(client, versionPath);

if (versionNode) {
return _.get(versionNode, kind);
}
}

processName(name: string): string {
return name.toLowerCase().replace(new RegExp('_', 'g'), '-');
}

processInputs(name: string, input: T, current?: T): KubeBody<T> {

const processedBody: KubeBody<T> = {
body: Object.assign(
{
kind: this.kind,
apiVersion: this.group ? `${this.group}/${this.version}` : this.version,
},
current,
input,
{
metadata: Object.assign(
{},
input.metadata,
{
name,
} as KubeMetadata,
current
? {resourceVersion: current.metadata.resourceVersion} as KubeMetadata
: {},
),
},
),
};

return processedBody;
}
}

export class AbstractKubernetesNamespacedResource<T extends KubeResource> implements KubernetesNamespacedResource<T> {
public client: AsyncKubeClient;
public group?: string;
version: string;
Expand Down
4 changes: 2 additions & 2 deletions src/api/kubectl/pod.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {AbstractKubernetesResourceManager, KubeResource, Props} from './kubernetes-resource-manager';
import {AbstractKubernetesNamespacedResource, KubeResource, Props} from './kubernetes-resource-manager';
import {BuildContext, Factory, ObjectFactory} from 'typescript-ioc';
import {AsyncKubeClient} from './client';

Expand All @@ -15,7 +15,7 @@ const factory: ObjectFactory = (context: BuildContext) => {
};

@Factory(factory)
export class KubePod extends AbstractKubernetesResourceManager<Pod> {
export class KubePod extends AbstractKubernetesNamespacedResource<Pod> {
constructor(props: Props) {
super(props);
}
Expand Down
4 changes: 2 additions & 2 deletions src/api/kubectl/role-binding.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {BuildContext, Factory, ObjectFactory} from 'typescript-ioc';
import {AsyncKubeClient} from './client';
import {AbstractKubernetesResourceManager, KubeResource, Props} from './kubernetes-resource-manager';
import {AbstractKubernetesNamespacedResource, KubeResource, Props} from './kubernetes-resource-manager';

export interface RoleRef {
apiGroup: string;
Expand Down Expand Up @@ -30,7 +30,7 @@ const factory: ObjectFactory = (context: BuildContext) => {
};

@Factory(factory)
export class KubeRoleBinding extends AbstractKubernetesResourceManager<RoleBinding> {
export class KubeRoleBinding extends AbstractKubernetesNamespacedResource<RoleBinding> {
constructor(props: Props) {
super(props);
}
Expand Down
6 changes: 3 additions & 3 deletions src/api/kubectl/role.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {BuildContext, Container, Factory, ObjectFactory} from 'typescript-ioc';
import {AsyncKubeClient} from './client';
import {AbstractKubernetesResourceManager, KubeResource, Props} from './kubernetes-resource-manager';
import {AbstractKubernetesNamespacedResource, KubeResource, Props} from './kubernetes-resource-manager';

export interface RoleRule {
apiGroups: string[];
Expand Down Expand Up @@ -29,7 +29,7 @@ const factory: ObjectFactory = (context: BuildContext) => {
};

@Factory(factory)
export class KubeRole extends AbstractKubernetesResourceManager<Role> {
export class KubeRole extends AbstractKubernetesNamespacedResource<Role> {
constructor(props: Props) {
super(props);
}
Expand Down Expand Up @@ -89,4 +89,4 @@ function reconcileVerbsInPlace(rule: RoleRule, verbs: string[]): string[] {
rule.verbs = rule.verbs.concat(verbs).filter(distinct);

return rule.verbs;
}
}
4 changes: 2 additions & 2 deletions src/api/kubectl/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {BuildContext, Factory, ObjectFactory} from 'typescript-ioc';
import * as _ from 'lodash';

import {AsyncOcpClient} from './client';
import {AbstractKubernetesResourceManager, KubeResource, Props} from './kubernetes-resource-manager';
import {AbstractKubernetesNamespacedResource, KubeResource, Props} from './kubernetes-resource-manager';

export interface Route extends KubeResource {
spec: {
Expand Down Expand Up @@ -35,7 +35,7 @@ const factory: ObjectFactory = (context: BuildContext) => {
};

@Factory(factory)
export class OcpRoute extends AbstractKubernetesResourceManager<Route> {
export class OcpRoute extends AbstractKubernetesNamespacedResource<Route> {
constructor(props: Props) {
super(props);
}
Expand Down
4 changes: 2 additions & 2 deletions src/api/kubectl/secrets.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {BuildContext, Factory, ObjectFactory} from 'typescript-ioc';
import {AsyncKubeClient} from './client';
import {AbstractKubernetesResourceManager, KubeResource, ListOptions, Props} from './kubernetes-resource-manager';
import {AbstractKubernetesNamespacedResource, KubeResource, ListOptions, Props} from './kubernetes-resource-manager';
import {decode as base64decode} from '../../util/base64';

export interface Secret<T = any> extends KubeResource {
Expand All @@ -18,7 +18,7 @@ const factory: ObjectFactory = (context: BuildContext) => {
};

@Factory(factory)
export class KubeSecret extends AbstractKubernetesResourceManager<Secret> {
export class KubeSecret extends AbstractKubernetesNamespacedResource<Secret> {
constructor(props: Props) {
super(props);
}
Expand Down
Loading