Skip to content

Commit

Permalink
feat(provider/kubernetes): Create manifest
Browse files Browse the repository at this point in the history
  • Loading branch information
Lars Wander committed Oct 5, 2017
1 parent 0bb6484 commit fa0eef5
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 0 deletions.
2 changes: 2 additions & 0 deletions app/scripts/modules/core/src/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -115,6 +116,7 @@ module(CORE_MODULE, [
require('./securityGroup/securityGroup.module').name,
SERVERGROUP_MODULE,
SUBNET_MODULE,
MANIFEST_MODULE,

require('./task/task.module').name,

Expand Down
Original file line number Diff line number Diff line change
@@ -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,
]);
26 changes: 26 additions & 0 deletions app/scripts/modules/core/src/manifest/manifestWriter.service.ts
Original file line number Diff line number Diff line change
@@ -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<ITask> {
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);
15 changes: 15 additions & 0 deletions app/scripts/modules/kubernetes/v2/kubernetes.v2.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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$/);
Expand All @@ -14,12 +19,22 @@ 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',
providerVersion: 'v2',
logo: {
path: require('../logo/kubernetes.icon.svg'),
},
serverGroup: {
commandBuilder: 'kubernetesV2ServerGroupCommandBuilder',
cloneServerGroupController: 'kubernetesManifestWizardCtrl',
cloneServerGroupTemplateUrl: require('./manifest/wizard/manifestWizard.html'),
}
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
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);
delete command.backingData;
command.manifest = load(command.manifestText);
return command;
}

public buildNewManifestCommand(app: Application): IPromise<IKubernetesManifestCommand> {
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);
Original file line number Diff line number Diff line change
@@ -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 = `
<div class="container-fluid form-horizontal">
<ng-form name="basicSettings">
<div class="form-group">
<div class="col-md-3 sm-label-right">
Account
</div>
<div class="col-md-7">
<account-select-field component="ctrl.command"
field="account"
accounts="ctrl.command.backingData.accounts"
provider="'kubernetes'"></account-select-field>
</div>
</div>
<div class="form-group">
<div class="col-md-3 sm-label-right">
Application
</div>
<div class="col-md-7"><input readonly="true"
type="text"
class="form-control input-sm no-spel"
name="cluster"
ng-model="ctrl.command.moniker.app"/></div>
</div>
<div class="form-group">
<div class="col-md-3 sm-label-right">
Cluster
</div>
<div class="col-md-7"><input type="text"
class="form-control input-sm no-spel"
name="cluster"
ng-required="true"
ng-model="ctrl.command.moniker.cluster"/></div>
</div>
</ng-form>
</div>
`;
}

export const KUBERNETES_MANIFEST_BASIC_SETTINGS = 'spinnaker.kubernetes.v2.kubernetes.manifest.basicSettings.component';
module(KUBERNETES_MANIFEST_BASIC_SETTINGS, [])
.component('kubernetesManifestBasicSettings', new KubernetesManifestBasicSettingsComponent());
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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 = `
<div class="container-fluid form-horizontal">
<ng-form name="manifest">
<div>
<div class="form-group">
<textarea class="code form-control kubernetes-manifest-entry" ng-model="ctrl.command.manifestText" rows="40"></textarea>
</div>
</div>
</ng-form>
</div>
`;
}

export const KUBERNETES_MANIFEST_ENTRY = 'spinnaker.kubernetes.v2.kubernetes.manifest.entry.component';
module(KUBERNETES_MANIFEST_ENTRY, [])
.component('kubernetesManifestEntry', new KubernetesManifestEntryComponent());
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.kubernetes-manifest-entry {
resize: vertical
}
Original file line number Diff line number Diff line change
@@ -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);
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<form name="form" class="container-fluid form-horizontal" style="padding: 0;">
<div>
<div ng-if="!ctrl.state.loaded" style="height: 200px">
<h3 us-spinner="{radius:30, width:8, length: 16}"></h3>
</div>
<v2-modal-wizard ng-if="ctrl.state.loaded"
heading="Deploy Manifest"
task-monitor="ctrl.taskMonitor"
dismiss="$dismiss()">
<v2-wizard-page key="basicSettings" label="Basic Settings" mark-complete-on-view="false">
<kubernetes-manifest-basic-settings command="ctrl.command"> </kubernetes-manifest-basic-settings>
</v2-wizard-page>
<v2-wizard-page key="manifest" label="Manifest" mark-complete-on-view="false">
<kubernetes-manifest-entry command="ctrl.command"> </kubernetes-manifest-entry>
</v2-wizard-page>
</v2-modal-wizard>
</div>
<div class="modal-footer" ng-if="ctrl.state.loaded">
<button ng-disabled="ctrl.taskMonitor.submitting" class="btn btn-default btn-cancel" ng-click="ctrl.cancel()">Cancel</button>
<submit-button ng-if="ctrl.showSubmitButton()" is-disabled="!ctrl.isValid() || ctrl.taskMonitor.submitting"
label="Deploy"
submitting="ctrl.taskMonitor.submitting" on-click="ctrl.submit()" is-new="true"></submit-button>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { IPromise, module } from 'angular';

import { Application } from '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<IKubernetesManifestCommand> {
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);

0 comments on commit fa0eef5

Please sign in to comment.