From 52d87b1a669582fb954c83718a3159c53cc5bf02 Mon Sep 17 00:00:00 2001 From: Lars Wander Date: Tue, 3 Oct 2017 15:10:54 -0400 Subject: [PATCH] feat(provider/kubernetes): Create manifest --- app/scripts/modules/core/src/core.module.ts | 2 + .../src/manifest/manifestWriter.module.ts | 7 ++ .../src/manifest/manifestWriter.service.ts | 26 +++++ .../kubernetes/v2/kubernetes.v2.module.ts | 15 +++ .../manifestCommandBuilder.service.ts | 98 +++++++++++++++++++ .../wizard/basicSettings.component.ts | 56 +++++++++++ .../wizard/manifestEntry.component.ts | 28 ++++++ .../v2/manifest/wizard/manifestEntry.less | 3 + .../wizard/manifestWizard.controller.ts | 72 ++++++++++++++ .../v2/manifest/wizard/manifestWizard.html | 24 +++++ .../serverGroupCommandBuilder.service.ts | 24 +++++ 11 files changed, 355 insertions(+) create mode 100644 app/scripts/modules/core/src/manifest/manifestWriter.module.ts create mode 100644 app/scripts/modules/core/src/manifest/manifestWriter.service.ts create mode 100644 app/scripts/modules/kubernetes/v2/manifest/manifestCommandBuilder.service.ts create mode 100644 app/scripts/modules/kubernetes/v2/manifest/wizard/basicSettings.component.ts create mode 100644 app/scripts/modules/kubernetes/v2/manifest/wizard/manifestEntry.component.ts create mode 100644 app/scripts/modules/kubernetes/v2/manifest/wizard/manifestEntry.less create mode 100644 app/scripts/modules/kubernetes/v2/manifest/wizard/manifestWizard.controller.ts create mode 100644 app/scripts/modules/kubernetes/v2/manifest/wizard/manifestWizard.html create mode 100644 app/scripts/modules/kubernetes/v2/serverGroup/serverGroupCommandBuilder.service.ts diff --git a/app/scripts/modules/core/src/core.module.ts b/app/scripts/modules/core/src/core.module.ts index 7e803c9a2af..58dab4c905f 100644 --- a/app/scripts/modules/core/src/core.module.ts +++ b/app/scripts/modules/core/src/core.module.ts @@ -50,6 +50,7 @@ import { SUBNET_MODULE } from './subnet/subnet.module'; import { WHATS_NEW_MODULE } from './whatsNew/whatsNew.module'; import { WIDGETS_MODULE } from './widgets/widgets.module'; import { STYLEGUIDE_MODULE } from './styleguide/styleguide.module'; +import { MANIFEST_MODULE } from 'core/manifest/manifestWriter.module'; // load all templates into the $templateCache @@ -115,6 +116,7 @@ module(CORE_MODULE, [ require('./securityGroup/securityGroup.module').name, SERVERGROUP_MODULE, SUBNET_MODULE, + MANIFEST_MODULE, require('./task/task.module').name, diff --git a/app/scripts/modules/core/src/manifest/manifestWriter.module.ts b/app/scripts/modules/core/src/manifest/manifestWriter.module.ts new file mode 100644 index 00000000000..3924f15c5d9 --- /dev/null +++ b/app/scripts/modules/core/src/manifest/manifestWriter.module.ts @@ -0,0 +1,7 @@ +import { module } from 'angular'; +import { MANIFEST_WRITER } from 'core/manifest/manifestWriter.service'; + +export const MANIFEST_MODULE = 'spinnaker.core.manifest'; +module(MANIFEST_MODULE, [ + MANIFEST_WRITER, +]); diff --git a/app/scripts/modules/core/src/manifest/manifestWriter.service.ts b/app/scripts/modules/core/src/manifest/manifestWriter.service.ts new file mode 100644 index 00000000000..e3295b64589 --- /dev/null +++ b/app/scripts/modules/core/src/manifest/manifestWriter.service.ts @@ -0,0 +1,26 @@ +import { IPromise, module } from 'angular'; + +import { Application } from 'core/application/application.model'; +import { ITask } from 'core/domain'; +import { TASK_EXECUTOR, TaskExecutor } from 'core/task/taskExecutor'; + +export class ManifestWriter { + constructor(private taskExecutor: TaskExecutor) { + 'ngInject'; + } + + public deployManifest(command: any, application: Application): IPromise { + const description = 'Deploy manifest'; + command.type = 'deployManifest'; + return this.taskExecutor.executeTask({ + job: [command], + application, + description + }); + } +} + +export const MANIFEST_WRITER = 'spinnaker.core.manifest.write.service'; +module(MANIFEST_WRITER, [ + TASK_EXECUTOR, +]).service('manifestWriter', ManifestWriter); diff --git a/app/scripts/modules/kubernetes/v2/kubernetes.v2.module.ts b/app/scripts/modules/kubernetes/v2/kubernetes.v2.module.ts index 1239830b94f..e9c27af0372 100644 --- a/app/scripts/modules/kubernetes/v2/kubernetes.v2.module.ts +++ b/app/scripts/modules/kubernetes/v2/kubernetes.v2.module.ts @@ -3,6 +3,11 @@ import { module } from 'angular'; import { CLOUD_PROVIDER_REGISTRY, CloudProviderRegistry } from '@spinnaker/core'; import '../logo/kubernetes.logo.less'; +import { KUBERNETES_MANIFEST_COMMAND_BUILDER } from './manifest/manifestCommandBuilder.service'; +import { KUBERNETES_MANIFEST_BASIC_SETTINGS } from './manifest/wizard/basicSettings.component'; +import { KUBERNETES_V2_SERVER_GROUP_COMMAND_BUILDER } from './serverGroup/serverGroupCommandBuilder.service'; +import { KUBERNETES_MANIFEST_CTRL } from './manifest/wizard/manifestWizard.controller'; +import { KUBERNETES_MANIFEST_ENTRY } from './manifest/wizard/manifestEntry.component'; // load all templates into the $templateCache const templates = require.context('./', true, /\.html$/); @@ -14,6 +19,11 @@ export const KUBERNETES_V2_MODULE = 'spinnaker.kubernetes.v2'; module(KUBERNETES_V2_MODULE, [ CLOUD_PROVIDER_REGISTRY, + KUBERNETES_V2_SERVER_GROUP_COMMAND_BUILDER, + KUBERNETES_MANIFEST_BASIC_SETTINGS, + KUBERNETES_MANIFEST_COMMAND_BUILDER, + KUBERNETES_MANIFEST_CTRL, + KUBERNETES_MANIFEST_ENTRY, ]).config((cloudProviderRegistryProvider: CloudProviderRegistry) => { cloudProviderRegistryProvider.registerProvider('kubernetes', { name: 'Kubernetes', @@ -21,5 +31,10 @@ module(KUBERNETES_V2_MODULE, [ logo: { path: require('../logo/kubernetes.icon.svg'), }, + serverGroup: { + commandBuilder: 'kubernetesV2ServerGroupCommandBuilder', + cloneServerGroupController: 'kubernetesManifestWizardCtrl', + cloneServerGroupTemplateUrl: require('./manifest/wizard/manifestWizard.html'), + } }); }); diff --git a/app/scripts/modules/kubernetes/v2/manifest/manifestCommandBuilder.service.ts b/app/scripts/modules/kubernetes/v2/manifest/manifestCommandBuilder.service.ts new file mode 100644 index 00000000000..3a20a4bba1a --- /dev/null +++ b/app/scripts/modules/kubernetes/v2/manifest/manifestCommandBuilder.service.ts @@ -0,0 +1,98 @@ +import { copy, IPromise, IQService, module } from 'angular'; + +import { load } from 'js-yaml' + +import { IMoniker } from 'core/naming/IMoniker'; +import { ACCOUNT_SERVICE, AccountService, Application } from 'core'; + +export interface IKubernetesManifestCommand { + account: string; + provider: string; + manifest: any; + manifestText: string; + relationships: IKubernetesManifestSpinnakerRelationships; + moniker: IMoniker; + backingData: any; +} + +export interface IKubernetesManifestSpinnakerRelationships { + loadBalancers?: string[]; + securityGroups?: string[]; +} + +export class KubernetesManifestCommandBuilder { + constructor(private $q: IQService, private accountService: AccountService) { + 'ngInject'; + } + + // TODO(lwander) add explanatory error messages + public manifestCommandIsValid(command: IKubernetesManifestCommand): boolean { + if (!command.moniker) { + return false; + } + + if (!command.moniker.app) { + return false; + } + + if (!command.moniker.cluster) { + return false; + } + + if (!command.manifestText) { + return false; + } + + return true; + } + + public copyAndCleanCommand(input: IKubernetesManifestCommand): IKubernetesManifestCommand { + const command = copy(input); + command.manifest = load(command.manifestText); + delete command.manifestText; + delete command.backingData; + return command; + } + + public buildNewManifestCommand(app: Application): IPromise { + const dataToFetch = { + accounts: this.accountService.getAllAccountDetailsForProvider('kubernetes', 'v2'), + }; + + return this.$q.all(dataToFetch) + .then((backingData: any) => { + const accountData = backingData.accounts[0]; + let account: string = null; + if (accountData) { + account = accountData.name; + } + + const manifest = {}; + const manifestText = ''; + const provider = 'kubernetes'; + const moniker = { + app: app.name, + }; + const relationships = { + loadBalancers: [] as string[], + securityGroups: [] as string[], + }; + + return { + backingData, + provider, + manifest, + manifestText, + relationships, + moniker, + account, + } as IKubernetesManifestCommand; + }); + } +} + +export const KUBERNETES_MANIFEST_COMMAND_BUILDER = 'spinnaker.kubernetes.v2.manifestBuilder.service'; + +module(KUBERNETES_MANIFEST_COMMAND_BUILDER, [ + ACCOUNT_SERVICE, +]).service('kubernetesManifestCommandBuilder', KubernetesManifestCommandBuilder); diff --git a/app/scripts/modules/kubernetes/v2/manifest/wizard/basicSettings.component.ts b/app/scripts/modules/kubernetes/v2/manifest/wizard/basicSettings.component.ts new file mode 100644 index 00000000000..56dc7d4aaf1 --- /dev/null +++ b/app/scripts/modules/kubernetes/v2/manifest/wizard/basicSettings.component.ts @@ -0,0 +1,56 @@ +import { IComponentOptions, IController, module } from 'angular'; + +import { IKubernetesManifestCommand } from '../manifestCommandBuilder.service'; + +class KubernetesManifestBasicSettingsCtrl implements IController { + public command: IKubernetesManifestCommand; +} + +class KubernetesManifestBasicSettingsComponent implements IComponentOptions { + public bindings: any = {command: '='}; + public controller: any = KubernetesManifestBasicSettingsCtrl; + public controllerAs = 'ctrl'; + public template = ` +
+ +
+
+ Account +
+
+ +
+
+ +
+
+ Application +
+
+
+ +
+
+ Cluster +
+
+
+
+
+ `; +} + +export const KUBERNETES_MANIFEST_BASIC_SETTINGS = 'spinnaker.kubernetes.v2.kubernetes.manifest.basicSettings.component'; +module(KUBERNETES_MANIFEST_BASIC_SETTINGS, []) + .component('kubernetesManifestBasicSettings', new KubernetesManifestBasicSettingsComponent()); diff --git a/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestEntry.component.ts b/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestEntry.component.ts new file mode 100644 index 00000000000..c278fc33020 --- /dev/null +++ b/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestEntry.component.ts @@ -0,0 +1,28 @@ +import { IComponentOptions, IController, module } from 'angular'; + +import { IKubernetesManifestCommand } from '../manifestCommandBuilder.service'; + +import './manifestEntry.less' + +class KubernetesManifestCtrl implements IController { + public command: IKubernetesManifestCommand; +} + +class KubernetesManifestEntryComponent implements IComponentOptions { + public bindings: any = {command: '='}; + public controller: any = KubernetesManifestCtrl; + public controllerAs = 'ctrl'; + public template = ` +
+ +
+ +
+
+
+ `; +} + +export const KUBERNETES_MANIFEST_ENTRY = 'spinnaker.kubernetes.v2.kubernetes.manifest.entry.component'; +module(KUBERNETES_MANIFEST_ENTRY, []) + .component('kubernetesManifestEntry', new KubernetesManifestEntryComponent()); diff --git a/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestEntry.less b/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestEntry.less new file mode 100644 index 00000000000..def7b99306c --- /dev/null +++ b/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestEntry.less @@ -0,0 +1,3 @@ +.kubernetes-manifest-entry { + resize: vertical +} diff --git a/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestWizard.controller.ts b/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestWizard.controller.ts new file mode 100644 index 00000000000..4edfb1511c8 --- /dev/null +++ b/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestWizard.controller.ts @@ -0,0 +1,72 @@ +import { IController, module } from 'angular'; +import { IModalInstanceService } from 'angular-ui-bootstrap'; + +import { + Application, + SERVER_GROUP_WRITER, + TASK_MONITOR_BUILDER, + TaskMonitor, + TaskMonitorBuilder +} from '@spinnaker/core'; + +import { + IKubernetesManifestCommand, + KUBERNETES_MANIFEST_COMMAND_BUILDER, + KubernetesManifestCommandBuilder +} from '../manifestCommandBuilder.service'; +import { ManifestWriter } from 'core/manifest/manifestWriter.service'; + +class KubernetesManifestWizardCtrl implements IController { + public state = { + loaded: false, + }; + public taskMonitor: TaskMonitor; + public command: IKubernetesManifestCommand; + + constructor(private $uibModalInstance: IModalInstanceService, + private application: Application, + private manifestWriter: ManifestWriter, + private taskMonitorBuilder: TaskMonitorBuilder, + private kubernetesManifestCommandBuilder: KubernetesManifestCommandBuilder) { + 'ngInject'; + this.kubernetesManifestCommandBuilder.buildNewManifestCommand(application) + .then((builtCommand) => { + this.command = builtCommand; + this.initialize(); + this.state.loaded = true; + }); + } + + public cancel(): void { + this.$uibModalInstance.dismiss(); + } + + public submit(): void { + const command = this.kubernetesManifestCommandBuilder.copyAndCleanCommand(this.command); + const submitMethod = () => this.manifestWriter.deployManifest(command, this.application); + this.taskMonitor.submit(submitMethod); + } + + private initialize(): void { + this.taskMonitor = this.taskMonitorBuilder.buildTaskMonitor({ + application: this.application, + title: 'Deploying your manifest', + modalInstance: this.$uibModalInstance, + }); + } + + public showSubmitButton(): boolean { + return true; + } + + public isValid(): boolean { + return this.kubernetesManifestCommandBuilder.manifestCommandIsValid(this.command); + } +} + +export const KUBERNETES_MANIFEST_CTRL = 'spinnaker.kubernetes.v2.manifest.wizard.controller'; +module(KUBERNETES_MANIFEST_CTRL, [ + SERVER_GROUP_WRITER, + TASK_MONITOR_BUILDER, + KUBERNETES_MANIFEST_COMMAND_BUILDER, +]).controller('kubernetesManifestWizardCtrl', KubernetesManifestWizardCtrl); diff --git a/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestWizard.html b/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestWizard.html new file mode 100644 index 00000000000..3f13cb67742 --- /dev/null +++ b/app/scripts/modules/kubernetes/v2/manifest/wizard/manifestWizard.html @@ -0,0 +1,24 @@ +
+
+
+

+
+ + + + + + + + +
+ +
diff --git a/app/scripts/modules/kubernetes/v2/serverGroup/serverGroupCommandBuilder.service.ts b/app/scripts/modules/kubernetes/v2/serverGroup/serverGroupCommandBuilder.service.ts new file mode 100644 index 00000000000..7638eb4f302 --- /dev/null +++ b/app/scripts/modules/kubernetes/v2/serverGroup/serverGroupCommandBuilder.service.ts @@ -0,0 +1,24 @@ +import { IPromise, module } from 'angular'; + +import { Application } from '@spinnaker/core'; +import { + IKubernetesManifestCommand, + KUBERNETES_MANIFEST_COMMAND_BUILDER, + KubernetesManifestCommandBuilder +} from '../manifest/manifestCommandBuilder.service'; + +export class KubernetesV2ServerGroupCommandBuilder { + constructor(private kubernetesManifestCommandBuilder: KubernetesManifestCommandBuilder) { + 'ngInject'; + } + + public buildNewServerGroupCommand(app: Application): IPromise { + return this.kubernetesManifestCommandBuilder.buildNewManifestCommand(app); + } +} + +export const KUBERNETES_V2_SERVER_GROUP_COMMAND_BUILDER = 'spinnaker.kubernetes.v2.serverGroup.commandBuilder.service'; + +module(KUBERNETES_V2_SERVER_GROUP_COMMAND_BUILDER, [ + KUBERNETES_MANIFEST_COMMAND_BUILDER, +]).service('kubernetesV2ServerGroupCommandBuilder', KubernetesV2ServerGroupCommandBuilder);