Skip to content

Commit

Permalink
feat(cf): Share/Unshare services (#6685)
Browse files Browse the repository at this point in the history
  • Loading branch information
stuart-pollock authored and jkschneider committed Mar 15, 2019
1 parent 88c8b5d commit e2940b4
Show file tree
Hide file tree
Showing 16 changed files with 435 additions and 96 deletions.
5 changes: 3 additions & 2 deletions app/scripts/modules/cloudfoundry/src/cf.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ import 'cloudfoundry/pipeline/config/validation/cfTargetImpedance.validator';
import { CLOUD_FOUNDRY_CLONE_SERVER_GROUP_STAGE } from './pipeline/stages/cloneServerGroup/cloudfoundryCloneServerGroupStage.module';
import './pipeline/stages/deployService/cloudfoundryDeployServiceStage.module';
import { CLOUD_FOUNDRY_DESTROY_ASG_STAGE } from './pipeline/stages/destroyAsg/cloudfoundryDestroyAsgStage.module';
import { CLOUD_FOUNDRY_DESTROY_SERVICE_STAGE } from './pipeline/stages/destroyService/cloudfoundryDestroyServiceStage.module';
import './pipeline/stages/destroyService/cloudfoundryDestroyServiceStage.module';
import { CLOUD_FOUNDRY_DISABLE_ASG_STAGE } from './pipeline/stages/disableAsg/cloudfoundryDisableAsgStage.module';
import { CLOUD_FOUNDRY_ENABLE_ASG_STAGE } from './pipeline/stages/enableAsg/cloudfoundryEnableAsgStage.module';
import { CLOUD_FOUNDRY_MAP_LOAD_BALANCERS_STAGE } from './pipeline/stages/mapLoadBalancers/cloudfoundryMapLoadBalancersStage.module';
import { CLOUD_FOUNDRY_UNMAP_LOAD_BALANCERS_STAGE } from './pipeline/stages/unmapLoadBalancers/cloudfoundryUnmapLoadBalancersStage.module';
import { CLOUD_FOUNDRY_RESIZE_ASG_STAGE } from './pipeline/stages/resizeAsg/cloudfoundryResizeAsgStage.module';
import { CLOUD_FOUNDRY_ROLLBACK_CLUSTER_STAGE } from './pipeline/stages/rollbackCluster/cloudfoundryRollbackClusterStage.module';
import './pipeline/stages/shareService/cloudfoundryShareServiceStage.module';
import './pipeline/stages/unshareService/cloudfoundryUnshareServiceStage.module';
import { CloudFoundryCreateServerGroupModal } from 'cloudfoundry/serverGroup/configure/wizard/CreateServerGroupModal';
import { CLOUD_FOUNDRY_INSTANCE_DETAILS } from 'cloudfoundry/instance/details/cloudfoundryInstanceDetails.module';

Expand All @@ -48,7 +50,6 @@ templates.keys().forEach(function(key) {
export const CLOUD_FOUNDRY_MODULE = 'spinnaker.cloudfoundry';
module(CLOUD_FOUNDRY_MODULE, [
CLOUD_FOUNDRY_CLONE_SERVER_GROUP_STAGE,
CLOUD_FOUNDRY_DESTROY_SERVICE_STAGE,
CLOUD_FOUNDRY_DESTROY_ASG_STAGE,
CLOUD_FOUNDRY_DISABLE_ASG_STAGE,
CLOUD_FOUNDRY_ENABLE_ASG_STAGE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class CloudfoundryDeployServiceStageConfig extends React.Component<

constructor(props: IStageConfigProps) {
super(props);
this.props.stage.cloudProvider = 'cloudfoundry';
this.props.updateStageField({ cloudProvider: 'cloudfoundry' });
this.state = {
accounts: [],
regions: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import { AccountService, IAccount, IRegion, IStageConfigProps, StageConfigField

export interface ICloudfoundryDestroyServiceStageConfigState {
accounts: IAccount[];
cloudProvider: string;
credentials: string;
region: string;
regions: IRegion[];
serviceInstanceName: string;
}

export class CloudfoundryDestroyServiceStageConfig extends React.Component<
Expand All @@ -22,52 +18,43 @@ export class CloudfoundryDestroyServiceStageConfig extends React.Component<
props.stage.cloudProvider = 'cloudfoundry';
this.state = {
accounts: [],
cloudProvider: 'cloudfoundry',
credentials: props.stage.credentials,
region: props.stage.region,
regions: [],
serviceInstanceName: props.stage.serviceInstanceName,
};
}

public componentDidMount = (): void => {
AccountService.listAccounts('cloudfoundry').then(accounts => {
this.setState({ accounts: accounts });
const { credentials } = this.props.stage;
if (credentials) {
public componentDidMount = () => {
AccountService.listAccounts('cloudfoundry').then((accounts: IAccount[]) => {
this.setState({ accounts });
if (this.props.stage.credentials) {
this.clearAndReloadRegions();
}
});
this.props.stageFieldUpdated();
};

private clearAndReloadRegions = (): void => {
private clearAndReloadRegions = () => {
this.setState({ regions: [] });
AccountService.getRegionsForAccount(this.props.stage.credentials).then(regions => this.setState({ regions }));
AccountService.getRegionsForAccount(this.props.stage.credentials).then((regions: IRegion[]) =>
this.setState({ regions }),
);
};

private accountUpdated = (option: Option<string>): void => {
private accountUpdated = (option: Option<string>) => {
const credentials = option.value;
this.props.stage.credentials = credentials;
this.props.stage.region = '';
this.props.stageFieldUpdated();
this.props.updateStageField({
credentials,
region: '',
});
if (credentials) {
this.clearAndReloadRegions();
}
};

private regionUpdated = (option: Option<string>): void => {
const region = option.value;
this.setState({ region });
this.props.stage.region = region;
this.props.stageFieldUpdated();
private regionUpdated = (option: Option<string>) => {
this.props.updateStageField({ region: option.value });
};

private serviceInstanceNameUpdated = (event: React.ChangeEvent<HTMLInputElement>): void => {
const serviceInstanceName = event.target.value;
this.setState({ serviceInstanceName });
this.props.stage.serviceInstanceName = serviceInstanceName;
this.props.stageFieldUpdated();
private serviceInstanceNameUpdated = (event: React.ChangeEvent<HTMLInputElement>) => {
this.props.updateStageField({ serviceInstanceName: event.target.value });
};

public render() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,21 @@
import { IController, IScope, module } from 'angular';
import { react2angular } from 'react2angular';

import { CloudfoundryDestroyServiceStageConfig } from './CloudfoundryDestroyServiceStageConfig';
import { ExecutionDetailsTasks, IStage, Registry } from '@spinnaker/core';
import { CloudfoundryServiceExecutionDetails } from 'cloudfoundry/presentation';

class CloudFoundryDestroyServiceStageCtrl implements IController {
public static $inject = ['$scope'];
constructor(public $scope: IScope) {}
}

export const CLOUD_FOUNDRY_DESTROY_SERVICE_STAGE = 'spinnaker.cloudfoundry.pipeline.stage.deleteServiceStage';
module(CLOUD_FOUNDRY_DESTROY_SERVICE_STAGE, [])
.config(function() {
Registry.pipeline.registerStage({
accountExtractor: (stage: IStage) => stage.context.credentials,
configAccountExtractor: (stage: IStage) => [stage.credentials],
provides: 'destroyService',
key: 'destroyService',
cloudProvider: 'cloudfoundry',
templateUrl: require('./cloudfoundryDestroyServiceStage.html'),
controller: 'cfDestroyServiceStageCtrl',
executionDetailsSections: [CloudfoundryServiceExecutionDetails, ExecutionDetailsTasks],
defaultTimeoutMs: 30 * 60 * 1000,
validators: [
{ type: 'requiredField', fieldName: 'region' },
{ type: 'requiredField', fieldName: 'serviceInstanceName', preventSave: true },
{ type: 'requiredField', fieldName: 'credentials', fieldLabel: 'account' },
],
});
})
.component(
'cfDestroyServiceStage',
react2angular(CloudfoundryDestroyServiceStageConfig, ['stage', 'stageFieldUpdated']),
)
.controller('cfDestroyServiceStageCtrl', CloudFoundryDestroyServiceStageCtrl);
Registry.pipeline.registerStage({
accountExtractor: (stage: IStage) => stage.context.credentials,
configAccountExtractor: (stage: IStage) => [stage.credentials],
provides: 'destroyService',
key: 'destroyService',
cloudProvider: 'cloudfoundry',
component: CloudfoundryDestroyServiceStageConfig,
templateUrl: require('./cloudfoundryDestroyServiceStage.html'),
controller: 'cfDestroyServiceStageCtrl',
executionDetailsSections: [CloudfoundryServiceExecutionDetails, ExecutionDetailsTasks],
defaultTimeoutMs: 30 * 60 * 1000,
validators: [
{ type: 'requiredField', fieldName: 'region' },
{ type: 'requiredField', fieldName: 'serviceInstanceName', preventSave: true },
{ type: 'requiredField', fieldName: 'credentials', fieldLabel: 'account' },
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import * as React from 'react';

import Select, { Option } from 'react-select';

import {
AccountService,
IAccount,
IRegion,
IStageConfigProps,
ReactSelectInput,
StageConfigField,
TextInput,
} from '@spinnaker/core';

interface ICloudfoundryShareServiceStageConfigState {
accounts: IAccount[];
regions: string[];
shareToRegionsList: string[];
}

export class CloudfoundryShareServiceStageConfig extends React.Component<
IStageConfigProps,
ICloudfoundryShareServiceStageConfigState
> {
constructor(props: IStageConfigProps) {
super(props);
props.stage.cloudProvider = 'cloudfoundry';
this.state = {
accounts: [],
regions: [],
shareToRegionsList: [],
};
}

public componentDidMount = () => {
AccountService.listAccounts('cloudfoundry').then((accounts: IAccount[]) => {
this.setState({ accounts });
});
if (this.props.stage.credentials) {
this.clearAndReloadRegions();
}
};

private clearAndReloadRegions = () => {
this.setState({ regions: [] });
AccountService.getRegionsForAccount(this.props.stage.credentials).then((regionList: IRegion[]) => {
const { region } = this.props.stage;
const regions = regionList.map(r => r.name);
regions.sort((a, b) => a.localeCompare(b));
this.setState({ regions });
if (region) {
this.clearAndResetShareToRegionList(region, regions);
}
});
};

private serviceInstanceNameUpdated = (event: React.ChangeEvent<HTMLInputElement>) => {
this.props.updateStageField({ serviceInstanceName: event.target.value });
};

private clearAndResetShareToRegionList = (region: string, regions: string[]) => {
this.setState({ shareToRegionsList: regions.filter(r => r !== region) });
};

private accountUpdated = (option: Option<string>) => {
const credentials = option.target.value;
this.setState({
regions: [],
shareToRegionsList: [],
});
this.props.updateStageField({
credentials,
region: '',
shareToRegions: [],
});
if (credentials) {
this.clearAndReloadRegions();
}
};

private regionUpdated = (option: Option<string>) => {
const region = option.target.value;
this.setState({ shareToRegionsList: [] });
this.props.updateStageField({
region,
shareToRegions: [],
});
this.clearAndResetShareToRegionList(region, this.state.regions);
};

private shareToRegionsUpdated = (option: Option<string>) => {
this.props.updateStageField({ shareToRegions: option.map((o: Option) => o.value) });
};

public render() {
const { credentials, region, serviceInstanceName, shareToRegions } = this.props.stage;
const { accounts, regions, shareToRegionsList } = this.state;

return (
<div className="form-horizontal">
<StageConfigField label="Account">
<ReactSelectInput
clearable={false}
onChange={this.accountUpdated}
value={credentials}
stringOptions={accounts.map(it => it.name)}
/>
</StageConfigField>
<StageConfigField label="Region">
<ReactSelectInput clearable={false} onChange={this.regionUpdated} value={region} stringOptions={regions} />
</StageConfigField>
<StageConfigField label="Service Instance Name">
<TextInput
type="text"
className="form-control"
onChange={this.serviceInstanceNameUpdated}
value={serviceInstanceName}
/>
</StageConfigField>
<StageConfigField label="Share To Regions">
<Select
options={
shareToRegionsList &&
shareToRegionsList.map((r: string) => ({
label: r,
value: r,
}))
}
multi={true}
clearable={false}
value={shareToRegions}
onChange={this.shareToRegionsUpdated}
/>
</StageConfigField>
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { CloudfoundryShareServiceStageConfig } from './CloudfoundryShareServiceStageConfig';
import { ExecutionDetailsTasks, IStage, Registry } from '@spinnaker/core';
import { CloudfoundryServiceExecutionDetails } from 'cloudfoundry/presentation';

Registry.pipeline.registerStage({
accountExtractor: (stage: IStage) => stage.context.credentials,
configAccountExtractor: (stage: IStage) => [stage.credentials],
provides: 'shareService',
key: 'shareService',
cloudProvider: 'cloudfoundry',
component: CloudfoundryShareServiceStageConfig,
executionDetailsSections: [CloudfoundryServiceExecutionDetails, ExecutionDetailsTasks],
defaultTimeoutMs: 30 * 60 * 1000,
validators: [
{ type: 'requiredField', fieldName: 'credentials', fieldLabel: 'account' },
{ type: 'requiredField', fieldName: 'region' },
{ type: 'requiredField', fieldName: 'serviceInstanceName', preventSave: true },
],
});
Loading

0 comments on commit e2940b4

Please sign in to comment.