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

feat(rrb): Allow for specifying pipelines to run before disable #4308

Merged
merged 2 commits into from
Oct 23, 2017
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import './strategies/redblack/redblack.strategy';
import './strategies/rollingredblack/rollingredblack.strategy';

import { CUSTOM_STRATEGY_SELECTOR_COMPONENT } from './strategies/custom/customStrategySelector.component';
import { PIPELINE_SELECTOR_COMPONENT } from './strategies/rollingredblack/pipelineSelector.component';
import { DEPLOYMENT_STRATEGY_SELECTOR_COMPONENT } from './deploymentStrategySelector.component';

export const DEPLOYMENT_STRATEGY_MODULE = 'spinnaker.core.deploymentStrategy';
module(DEPLOYMENT_STRATEGY_MODULE, [
CUSTOM_STRATEGY_SELECTOR_COMPONENT,
PIPELINE_SELECTOR_COMPONENT,
DEPLOYMENT_STRATEGY_SELECTOR_COMPONENT,
]);
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
<div class="form-group">
<div class="col-md-6">
<label>
<div class="col-md-6" style="margin-top: 15px">
<h4>
Percentages
<help-field key="strategy.rollingRedBlack.targetPercentages"></help-field>
</label>
</h4>
<number-list model="$ctrl.command.targetPercentages" label="percentage"/>
</div>

<div class="col-md-12" style="margin-top: 15px">
<h4>Before Disable</h4>
</div>

<div class="col-md-12 form-inline">
<label>Wait Before Disable
<label>Wait
<help-field
content="Time to wait before disabling instances in old server group"></help-field>
</label>
Expand All @@ -19,4 +24,11 @@
placeholder="0">
seconds
</div>
<div class="col-md-12" style="margin-top: 5px">
<label>Run a Pipeline
<help-field
content="Pipeline to run before disabling instances in old server group"></help-field>
</label>
<pipeline-selector command="$ctrl.command.pipelineBeforeCleanup"></pipeline-selector>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<div class="form-group">
<div class="form-horizontal">
<div class="form-group">
<label class="col-md-2 col-md-offset-1 sm-label-right">Application</label>
<div class="col-md-6">
<ui-select ng-model="$ctrl.command.application"
class="form-control input-sm"
ng-change="$ctrl.initializePipelines()">
<ui-select-match allow-clear placeholder="None">{{$select.selected}}</ui-select-match>
<ui-select-choices
repeat="application in $ctrl.state.applications | filter: $select.search | limitTo: $ctrl.state.currentApplicationCount"
infinite-scroll="$ctrl.addMoreApplications()"
infinite-scroll-distance="2">
<div ng-bind-html="application | highlight: $select.search"></div>
</ui-select-choices>
</ui-select>
</div>
</div>

<div class="form-group" ng-if="$ctrl.command.application && $ctrl.state.pipelinesLoaded">
<label class="col-md-2 col-md-offset-1 sm-label-right">Pipeline</label>
<div class="col-md-6">
<div>
<ui-select class="form-control input-sm"
ng-model="$ctrl.command.pipelineId"
ng-change="$ctrl.updatePipelineConfig()">
<ui-select-match allow-clear placeholder="Select a pipeline...">{{$select.selected.name}}</ui-select-match>
<ui-select-choices
repeat="pipeline.id as pipeline in $ctrl.state.pipelines | filter: $select.search | orderBy: 'index'"><span
ng-bind-html="pipeline.name | highlight: $select.search"></span></ui-select-choices>
</ui-select>
</div>
</div>
</div>

<div class="well well-sm clearfix ng-scope col-md-12" ng-if="$ctrl.state.pipelineParameters.length">
<strong class="text-left">Parameters</strong>
<div class="form-group" ng-repeat="parameter in $ctrl.state.pipelineParameters | orderBy:'name' ">
<div class="col-md-3 sm-label-right">
<span ng-if="!parameter.description">{{parameter.name}}</span>
<help-field content="{{parameter.description}}" label="{{parameter.name}}" ng-if="parameter.description"></help-field>
</div>
<div class="col-md-6">
<input disabled ng-if="$ctrl.state.useDefaultParameters[parameter.name]" type="text" class="form-control input-sm"
value="{{parameter.default}}"/>
<input ng-if="!$ctrl.state.useDefaultParameters[parameter.name] && !parameter.hasOptions" type="text" class="form-control input-sm"
ng-model="$ctrl.state.userSuppliedParameters[parameter.name]" ng-change="$ctrl.updateParam(parameter.name)"/>
<ui-select style="width:100%"
ng-if="!$ctrl.state.useDefaultParameters[parameter.name] && parameter.hasOptions"
ng-model="$ctrl.state.userSuppliedParameters[parameter.name]" ng-change="$ctrl.updateParam(parameter.name)"
class="form-control input-sm">
<ui-select-match>
<strong>{{$select.selected.value}}</strong>
</ui-select-match>
<ui-select-choices repeat="option.value as option in parameter.options">
<div><strong>{{option.value}}</strong></div>
</ui-select-choices>
</ui-select>
</div>
<div class="checkbox col-md-3" ng-if="parameter.default !== null && parameter.default !== undefined">
<label>
<input type="checkbox" ng-model="$ctrl.state.useDefaultParameters[parameter.name]"
ng-change="$ctrl.updateParam(parameter.name)">Use default
</label>
</div>
</div>

</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { IController, IComponentOptions, module } from 'angular';

import { APPLICATION_READ_SERVICE, ApplicationReader } from 'core/application/service/application.read.service';
import { PIPELINE_CONFIG_SERVICE, PipelineConfigService } from 'core/pipeline/config/services/pipelineConfig.service';
import { IParameter, IPipeline } from 'core/domain';

interface IPipelineSelectorState {
pipelinesLoaded: boolean;
applications: string[];
pipelines: IPipeline[];
pipelineParameters?: IParameter[];
useDefaultParameters: { [key: string]: boolean };
userSuppliedParameters: { [key: string]: any };
currentApplicationCount: number;
}

interface IPipelineSelectorCommand {
application?: string;
pipelineId?: string;
pipelineParameters?: { [key: string]: any };
}

class PipelineSelectorController implements IController {

public command: IPipelineSelectorCommand;
public state: IPipelineSelectorState = {
pipelinesLoaded: false,
applications: [],
pipelines: [],
pipelineParameters: [],
useDefaultParameters: {},
userSuppliedParameters: {},
currentApplicationCount: 20,
};

constructor(private applicationReader: ApplicationReader, private pipelineConfigService: PipelineConfigService) {
'ngInject';
}

public $onInit() {
this.applicationReader.listApplications().then((applications) => {
this.state.applications = applications.map(a => a.name).sort();
this.initializePipelines();
});
}

public addMoreApplications(): void {
this.state.currentApplicationCount += 20;
}

public initializePipelines(): void {
if (this.command.application) {
this.pipelineConfigService.getPipelinesForApplication(this.command.application).then((pipelines) => {
this.state.pipelines = pipelines;
console.log(pipelines);
if (pipelines.every(p => p.id !== this.command.pipelineId)) {
this.command.pipelineId = null;
}
this.state.pipelinesLoaded = true;
this.updatePipelineConfig();
});
}
}

public updatePipelineConfig(): void {
if (this.command && this.command.application && this.command.pipelineId) {
const config = this.state.pipelines.find(p => p.id === this.command.pipelineId);
if (config && config.parameterConfig) {
if (!this.command.pipelineParameters) {
this.command.pipelineParameters = {};
}
this.state.pipelineParameters = config.parameterConfig;
this.state.userSuppliedParameters = this.command.pipelineParameters;
this.state.useDefaultParameters = {};
this.configureParamDefaults();
} else {
this.clearParams();
}
} else {
this.clearParams();
}
}

public updateParam(parameter: string): void {
if (this.state.useDefaultParameters[parameter] === true) {
delete this.state.userSuppliedParameters[parameter];
delete this.command.pipelineParameters[parameter];
} else if (this.state.userSuppliedParameters[parameter]) {
this.command.pipelineParameters[parameter] = this.state.userSuppliedParameters[parameter];
}
}

private configureParamDefaults(): void {
this.state.pipelineParameters.forEach((param: any) => {
const defaultValue = param.default;
if (defaultValue !== null && defaultValue !== undefined) {
const configuredParamValue = this.command.pipelineParameters[param.name];
if (configuredParamValue === undefined || configuredParamValue === defaultValue) {
this.state.useDefaultParameters[param.name] = true;
this.command.pipelineParameters[param.name] = defaultValue;
}
}
});
}

private clearParams(): void {
this.state.pipelineParameters = [];
this.state.useDefaultParameters = {};
this.state.userSuppliedParameters = {};
}
}

const pipelineSelectorComponent: IComponentOptions = {
bindings: {
command: '=',
},
templateUrl: require('./pipelineSelector.component.html'),
controller: PipelineSelectorController,
};

export const PIPELINE_SELECTOR_COMPONENT = 'spinnaker.core.deploymentStrategy.rollingredblack.pipelineSelector';
module(PIPELINE_SELECTOR_COMPONENT, [
APPLICATION_READ_SERVICE,
PIPELINE_CONFIG_SERVICE,
]).component('pipelineSelector', pipelineSelectorComponent);
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,11 @@ DeploymentStrategyRegistry.registerStrategy({
if (!command.targetPercentages) {
command.targetPercentages = [50, 100];
}

if (!command.pipelineBeforeCleanup) {
command.beforeCleanupPipeline = {
application: command.application
}
}
}
});