From 19e67ffdcc2e4e63463bc867f398993c37b8621d Mon Sep 17 00:00:00 2001 From: Phil Kunz Date: Thu, 12 Sep 2019 14:45:36 +0200 Subject: [PATCH] fix(core): update --- package-lock.json | 25 ++++++++++ package.json | 2 + test/test.ts | 29 ++++++++++- ts/docker.classes.image.ts | 1 + ts/docker.classes.secret.ts | 73 ++++++++++++++++++++++++++++ ts/docker.classes.service.ts | 94 +++++++++++++++++++++++++----------- ts/docker.plugins.ts | 4 +- ts/index.ts | 1 + ts/interfaces/index.ts | 1 + ts/interfaces/secret.ts | 7 +++ ts/interfaces/service.ts | 2 + 11 files changed, 209 insertions(+), 30 deletions(-) create mode 100644 ts/docker.classes.secret.ts create mode 100644 ts/interfaces/secret.ts diff --git a/package-lock.json b/package-lock.json index 647d8ca..3153608 100644 --- a/package-lock.json +++ b/package-lock.json @@ -180,6 +180,16 @@ "vinyl-file": "^3.0.0" } }, + "@pushrocks/smartjson": { + "version": "3.0.8", + "resolved": "https://verdaccio.lossless.one/@pushrocks%2fsmartjson/-/smartjson-3.0.8.tgz", + "integrity": "sha512-EjC3611RSZaZmK+nXxXrYDBxdxYWtrxjOrZtQzbYn0yM33KSCH0sLIAG8B2wYZVAOj4A2pC8mVxFSJ1w3iRFHg==", + "requires": { + "@types/fast-json-stable-stringify": "^2.0.0", + "fast-json-stable-stringify": "^2.0.0", + "lodash.clonedeep": "^4.5.0" + } + }, "@pushrocks/smartlog": { "version": "2.0.19", "resolved": "https://verdaccio.lossless.one/@pushrocks%2fsmartlog/-/smartlog-2.0.19.tgz", @@ -379,6 +389,11 @@ "resolved": "https://verdaccio.lossless.one/@types%2fdefault-gateway/-/default-gateway-3.0.0.tgz", "integrity": "sha512-Pg0Vygi/mDsW+jAlknUf9ECJAcF6GyluMzXofb7hs4iLlichbdQLveweUN0SLb4TI6drRvaMoINcMzPQb0XB+w==" }, + "@types/fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://verdaccio.lossless.one/@types%2ffast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha512-mky/O83TXmGY39P1H9YbUpjV6l6voRYlufqfFCvel8l1phuy8HRjdWc1rrPuN53ITBJlbyMSV6z3niOySO5pgQ==" + }, "@types/figures": { "version": "3.0.1", "resolved": "https://verdaccio.lossless.one/@types%2ffigures/-/figures-3.0.1.tgz", @@ -923,6 +938,11 @@ "strip-eof": "^1.0.0" } }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://verdaccio.lossless.one/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, "figures": { "version": "3.0.0", "resolved": "https://verdaccio.lossless.one/figures/-/figures-3.0.0.tgz", @@ -1214,6 +1234,11 @@ "resolved": "https://verdaccio.lossless.one/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://verdaccio.lossless.one/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, "lodash.isfinite": { "version": "3.3.2", "resolved": "https://verdaccio.lossless.one/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", diff --git a/package.json b/package.json index d2cbca4..525bade 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,12 @@ "homepage": "https://gitlab.com/pushrocks/dockersock#README", "dependencies": { "@pushrocks/lik": "^3.0.11", + "@pushrocks/smartjson": "^3.0.8", "@pushrocks/smartlog": "^2.0.19", "@pushrocks/smartnetwork": "^1.1.14", "@pushrocks/smartpromise": "^3.0.2", "@pushrocks/smartrequest": "^1.1.26", + "@pushrocks/smartstring": "^3.0.10", "@pushrocks/smartversion": "^2.0.4", "rxjs": "^6.5.3" }, diff --git a/test/test.ts b/test/test.ts index 201f463..933b9b5 100644 --- a/test/test.ts +++ b/test/test.ts @@ -57,6 +57,22 @@ tap.test('should return a change Observable', async tools => { subscription.unsubscribe(); }); +// SECRETS +tap.test('should create a secret', async () => { + const mySecret = await docker.DockerSecret.createSecret(testDockerHost, { + name: 'testSecret', + contentArg: `{ "hi": "wow"}`, + labels: {} + }); + console.log(mySecret); +}); + +tap.test('should remove a secret by name', async () => { + const mySecret = await docker.DockerSecret.getSecretByName(testDockerHost, 'testSecret'); + await mySecret.remove(); +}); + + // SERVICES tap.test('should activate swarm mode', async () => { await testDockerHost.activateSwarm(); @@ -71,6 +87,11 @@ tap.test('should create a service', async () => { const testNetwork = await docker.DockerNetwork.createNetwork(testDockerHost, { Name: 'testNetwork' }); + const testSecret = await docker.DockerSecret.createSecret(testDockerHost, { + name: 'serviceSecret', + labels: {}, + contentArg: '{"hi": "wow"}' + }); const testService = await DockerService.createService(testDockerHost, { Image: 'nginx:latest', Labels: { @@ -78,10 +99,16 @@ tap.test('should create a service', async () => { }, Name: 'testService', networks: [testNetwork], - networkAlias: 'testService' + networkAlias: 'testService', + secrets: [testSecret] }); + + await testSecret.update(`{"updated": "socool"}`); + await testService.update(); + await testService.remove(); await testNetwork.remove(); + await testSecret.remove(); }); tap.start(); diff --git a/ts/docker.classes.image.ts b/ts/docker.classes.image.ts index 54f0842..88fbbf5 100644 --- a/ts/docker.classes.image.ts +++ b/ts/docker.classes.image.ts @@ -45,6 +45,7 @@ export class DockerImage { } because it is already tagged with ${imageTag}` ); } else { + imageUrlObject.imageUrl = imageUrl; imageUrlObject.imageTag = imageTag; } } else if (!imageUrlObject.imageTag) { diff --git a/ts/docker.classes.secret.ts b/ts/docker.classes.secret.ts new file mode 100644 index 0000000..7bb3e90 --- /dev/null +++ b/ts/docker.classes.secret.ts @@ -0,0 +1,73 @@ +import * as plugins from './docker.plugins'; +import { DockerHost } from './docker.classes.host'; + +// interfaces +import * as interfaces from './interfaces'; + +export class DockerSecret { + // STATIC + public static async getSecrets(dockerHostArg: DockerHost) { + const response = await dockerHostArg.request('GET', '/secrets'); + const secrets: DockerSecret[] = []; + for (const secret of response.body) { + const dockerSecretInstance = new DockerSecret(dockerHostArg); + Object.assign(dockerSecretInstance, secret); + secrets.push(dockerSecretInstance); + } + return secrets; + } + + public static async getSecretByID (dockerHostArg: DockerHost, idArg: string) { + const secrets = await this.getSecrets(dockerHostArg); + return secrets.find(secret => secret.ID === idArg); + } + + public static async getSecretByName (dockerHostArg: DockerHost, nameArg: string) { + const secrets = await this.getSecrets(dockerHostArg); + return secrets.find(secret => secret.Spec.Name === nameArg); + } + + public static async createSecret(dockerHostArg: DockerHost, secretDescriptor: interfaces.ISecretCreationDescriptor) { + const response = await dockerHostArg.request('POST', '/secrets/create', { + Name: secretDescriptor.name, + Labels: secretDescriptor.labels, + Data: plugins.smartstring.base64.encode(secretDescriptor.contentArg) + }); + + const newSecretInstance = new DockerSecret(dockerHostArg); + Object.assign(newSecretInstance, response.body); + Object.assign (newSecretInstance, await DockerSecret.getSecretByID(dockerHostArg, newSecretInstance.ID)); + return newSecretInstance; + } + + // INSTANCE + public ID: string; + public Spec: { + Name: string; + Labels: interfaces.TLabels; + }; + Version: { + Index:string; + } + + public dockerHost: DockerHost; + constructor(dockerHostArg: DockerHost) { + this.dockerHost = dockerHostArg; + } + + /** + * updates a secret + */ + public async update (contentArg: string) { + const route = `/secrets/${this.ID}/update?=version=${this.Version.Index}`; + const response = await this.dockerHost.request('POST', `/secrets/${this.ID}/update?version=${this.Version.Index}`, { + Name: this.Spec.Name, + Labels: this.Spec.Labels, + Data: plugins.smartstring.base64.encode(contentArg) + }); + } + + public async remove () { + await this.dockerHost.request('DELETE', `/secrets/${this.ID}`); + } +} \ No newline at end of file diff --git a/ts/docker.classes.service.ts b/ts/docker.classes.service.ts index 5402239..e329c7f 100644 --- a/ts/docker.classes.service.ts +++ b/ts/docker.classes.service.ts @@ -3,6 +3,7 @@ import * as interfaces from './interfaces'; import { DockerHost } from './docker.classes.host'; import { DockerImage } from './docker.classes.image'; +import { DockerSecret } from './docker.classes.secret'; export class DockerService { // STATIC @@ -17,7 +18,10 @@ export class DockerService { return services; } - public static async getServiceByName(dockerHost: DockerHost, networkName: string): Promise { + public static async getServiceByName( + dockerHost: DockerHost, + networkName: string + ): Promise { const allServices = await DockerService.getServices(dockerHost); const wantedService = allServices.find(service => { return service.Spec.Name === networkName; @@ -33,7 +37,10 @@ export class DockerService { serviceCreationDescriptor: interfaces.IServiceCreationDescriptor ): Promise { // lets get the image - plugins.smartlog.defaultLogger.log('info', `downloading image for service ${serviceCreationDescriptor.Name}`); + plugins.smartlog.defaultLogger.log( + 'info', + `downloading image for service ${serviceCreationDescriptor.Name}` + ); const serviceImage = await DockerImage.createFromRegistry(dockerHost, { imageUrl: serviceCreationDescriptor.Image }); @@ -49,12 +56,34 @@ export class DockerService { }); } + const secretArray: any[] = []; + for (const secret of serviceCreationDescriptor.secrets) { + secretArray.push({ + File: { + Name: 'secret.json', + UID: '33', + GID: '33', + Mode: 384 + }, + SecretID: secret.ID, + SecretName: secret.Spec.Name + }); + } + const response = await dockerHost.request('POST', '/services/create', { Name: serviceCreationDescriptor.Name, TaskTemplate: { ContainerSpec: { Image: serviceCreationDescriptor.Image, - Labels: serviceCreationDescriptor.Labels + Labels: serviceCreationDescriptor.Labels, + Secrets: secretArray + }, + UpdateConfig: { + Parallelism: 0, + Delay: 0, + FailureAction: 'pause', + Monitor: 15000000000, + MaxFailureRatio: 0.15 }, ForceUpdate: 1 }, @@ -62,13 +91,16 @@ export class DockerService { Networks: networkArray }); - const createdService = await DockerService.getServiceByName(dockerHost, serviceCreationDescriptor.Name); + const createdService = await DockerService.getServiceByName( + dockerHost, + serviceCreationDescriptor.Name + ); return createdService; } // INSTANCE public dockerHostRef: DockerHost; - + public ID: string; public Version: { Index: number }; public CreatedAt: string; @@ -80,14 +112,23 @@ export class DockerService { ContainerSpec: { Image: string; Isolation: string; - } + Secrets: Array<{ + File: { + Name: string; + UID: string; + GID: string; + Mode: number; + }; + SecretID: string; + SecretName: string; + }>; + }; ForceUpdate: 0; - }, + }; Mode: {}; - Networks: [any[]] + Networks: [any[]]; }; - public Endpoint: { Spec: {}, VirtualIPs: [any[]] }; - + public Endpoint: { Spec: {}; VirtualIPs: [any[]] }; constructor(dockerHostArg: DockerHost) { this.dockerHostRef = dockerHostArg; @@ -96,19 +137,19 @@ export class DockerService { public async update() { const labels: interfaces.TLabels = { ...this.Spec.Labels, - + version: 'x.x.x' }; - const dockerData = await this.dockerHostRef.request('POST', `/servces/${this.ID}/update?version=${this.Version.Index}`, { - Name: this.Spec.Name, - TaskTemplate: { - ContainerSpec: { - Image: this.Spec.TaskTemplate.ContainerSpec.Image, - Labels: labels - }, - ForceUpdate: 1 - }, - Labels: labels, - }); + + const dockerData = await this.dockerHostRef.request( + 'POST', + `/services/${this.ID}/update?version=${this.Version.Index + 1}`, + { + Name: this.Spec.Name, + TaskTemplate: this.Spec.TaskTemplate, + Labels: labels, + Networks: this.Spec.Networks + } + ); Object.assign(this, dockerData); } @@ -116,17 +157,17 @@ export class DockerService { await this.dockerHostRef.request('DELETE', `/services/${this.ID}`); } - public async reReadFromDockerEngine () { + public async reReadFromDockerEngine() { const dockerData = await this.dockerHostRef.request('GET', `/services/${this.ID}`); Object.assign(this, dockerData); } - public async updateFromRegistry () { + public async updateFromRegistry() { // TODO: implement digest based update recognition await this.reReadFromDockerEngine(); const dockerImage = await DockerImage.createFromRegistry(this.dockerHostRef, { - imageUrl: this.Spec.TaskTemplate.ContainerSpec.Image + imageUrl: this.Spec.TaskTemplate.ContainerSpec.Image }); const imageVersion = new plugins.smartversion.SmartVersion(dockerImage.Labels.version); @@ -135,8 +176,5 @@ export class DockerService { console.log('service needs to be updated'); this.update(); } - - - } } diff --git a/ts/docker.plugins.ts b/ts/docker.plugins.ts index 637bd4b..952ad68 100644 --- a/ts/docker.plugins.ts +++ b/ts/docker.plugins.ts @@ -1,14 +1,16 @@ // @pushrocks scope import * as lik from '@pushrocks/lik'; +import * as smartjson from '@pushrocks/smartjson'; import * as smartlog from '@pushrocks/smartlog'; import * as smartnetwork from '@pushrocks/smartnetwork'; import * as smartpromise from '@pushrocks/smartpromise'; import * as smartrequest from '@pushrocks/smartrequest'; +import * as smartstring from '@pushrocks/smartstring' import * as smartversion from '@pushrocks/smartversion'; smartlog.defaultLogger.enableConsole(); -export { lik, smartlog, smartnetwork, smartpromise, smartrequest, smartversion }; +export { lik, smartjson, smartlog, smartnetwork, smartpromise, smartrequest, smartstring, smartversion }; // third party import * as rxjs from 'rxjs'; diff --git a/ts/index.ts b/ts/index.ts index 1afa57d..3b2ae59 100644 --- a/ts/index.ts +++ b/ts/index.ts @@ -2,4 +2,5 @@ export * from './docker.classes.host'; export * from './docker.classes.container'; export * from './docker.classes.image'; export * from './docker.classes.network'; +export * from './docker.classes.secret'; export * from './docker.classes.service'; diff --git a/ts/interfaces/index.ts b/ts/interfaces/index.ts index 0bf2e33..e52b05d 100644 --- a/ts/interfaces/index.ts +++ b/ts/interfaces/index.ts @@ -3,4 +3,5 @@ export * from './image'; export * from './label'; export * from './network'; export * from './port'; +export * from './secret'; export * from './service'; diff --git a/ts/interfaces/secret.ts b/ts/interfaces/secret.ts new file mode 100644 index 0000000..d191f53 --- /dev/null +++ b/ts/interfaces/secret.ts @@ -0,0 +1,7 @@ +import * as interfaces from './'; + +export interface ISecretCreationDescriptor { + name: string; + contentArg: any; + labels: interfaces.TLabels; +} \ No newline at end of file diff --git a/ts/interfaces/service.ts b/ts/interfaces/service.ts index 92a72cd..779fcdc 100644 --- a/ts/interfaces/service.ts +++ b/ts/interfaces/service.ts @@ -1,5 +1,6 @@ import * as interfaces from './'; import { DockerNetwork } from '../docker.classes.network'; +import { DockerSecret } from '../docker.classes.secret'; export interface IServiceCreationDescriptor { Name: string; @@ -7,4 +8,5 @@ export interface IServiceCreationDescriptor { Labels: interfaces.TLabels; networks: DockerNetwork[]; networkAlias: string; + secrets: DockerSecret[]; }