Skip to content

Commit

Permalink
Updates sync command (#215)
Browse files Browse the repository at this point in the history
- Adds `--tekton` flag to add privileged scc to tekton pipeline service account
- Adds SCC kube api to support SCC interactions

Signed-off-by: Sean Sundberg <seansund@us.ibm.com>
  • Loading branch information
seansund authored Sep 17, 2021
1 parent 56b3505 commit b778448
Show file tree
Hide file tree
Showing 22 changed files with 296 additions and 40 deletions.
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

0 comments on commit b778448

Please sign in to comment.