Skip to content

Commit

Permalink
Merge branch 'master' into feature/display-lots-of-parameters
Browse files Browse the repository at this point in the history
* master: (28 commits)
  feat(kubernetes): feature-flagged support for kubernetes traffic management strategies (spinnaker#6816)
  feat(cf): Create Service Key pipeline stage (spinnaker#6821)
  feat(core): Create pipeline from v2 template list
  fix(provider/cf): Clone model so Orca monitors the correct foundation for up instances (spinnaker#6817)
  chore(kubernetes): refactor BasicSettings component to be usable in stages (spinnaker#6820)
  fix(triggers): Remove RunAsUser if pipeline permissions enabled for react triggers. (spinnaker#6818)
  feat(provider/azure): Add redblack strategy for azure (spinnaker#6801)
  fix(mptv2): clicking a view link on template list screen throws exception (spinnaker#6815)
  fix(artifacts): helm artifact, replace object assignw with object spread (spinnaker#6814)
  fix(provider/cf): Fix provider selection for resize stage in pipeline (spinnaker#6754)
  fix(artifacts): default helm artifact editor is broken (spinnaker#6811)
  fix(google): revert "select all zones by default when deploying a regional gce server group (spinnaker#6751)" (spinnaker#6808)
  fix(google): GCE create server group and load balancer fixes (spinnaker#6806)
  Bump package core to 0.0.350 and amazon to 0.0.184 (spinnaker#6807)
  fix(amazon): hide security groups on NLBs (spinnaker#6803)
  refactor(core): de-angularize ApplicationModelBuilder, fix project executions (spinnaker#6802)
  fix(google): fix autohealing health checks in deploy stages (spinnaker#6804)
  fix(kubernetes): show Deployment clusters in Find Artifacts from Resource stages (spinnaker#6794)
  fix(triggers): Add lastSuccessfulBuild as a build option in Jenkins default artifact (spinnaker#6797)
  fix(provider/cf): Make expected artifacts selectable as clone manifests (spinnaker#6796)
  ...
  • Loading branch information
kevinawoo committed Apr 8, 2019
2 parents 9084435 + 2d7f388 commit e9cb1d0
Show file tree
Hide file tree
Showing 28 changed files with 793 additions and 67 deletions.
1 change: 1 addition & 0 deletions app/scripts/modules/cloudfoundry/src/cf.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import 'cloudfoundry/pipeline/config/validation/cfTargetImpedance.validator';
import 'cloudfoundry/pipeline/config/validation/instanceSize.validator';
import 'cloudfoundry/pipeline/config/validation/requiredRoutes.validator';
import { CLOUD_FOUNDRY_CLONE_SERVER_GROUP_STAGE } from './pipeline/stages/cloneServerGroup/cloudfoundryCloneServerGroupStage.module';
import './pipeline/stages/createServiceKey/cloudfoundryCreateServiceKeyStage.module';
import './pipeline/stages/deployService/cloudfoundryDeployServiceStage.module';
import { CLOUD_FOUNDRY_DESTROY_ASG_STAGE } from './pipeline/stages/destroyAsg/cloudfoundryDestroyAsgStage.module';
import './pipeline/stages/destroyService/cloudfoundryDestroyServiceStage.module';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class CloudfoundryCloneServerGroupStageConfig extends React.Component<
private handleResult = (command: any) => {
this.props.stage.credentials = command.credentials;
this.props.stage.capacity = command.capacity;
this.props.stage.account = command.account;
this.props.stage.destination = command.destination;
this.props.stage.delayBeforeDisableSec = command.delayBeforeDisableSec;
this.props.stage.freeFormDetails = command.freeFormDetails;
Expand Down Expand Up @@ -99,7 +100,7 @@ export class CloudfoundryCloneServerGroupStageConfig extends React.Component<
</thead>
<tbody>
<tr>
<td>{stage.destination ? stage.destination.account : ''}</td>
<td>{stage.account || ''}</td>
<td>{stage.destination ? stage.destination.region : ''}</td>
</tr>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react';
import { get } from 'lodash';

import {
AccountTag,
ExecutionDetailsSection,
IExecutionDetailsSectionProps,
StageExecutionLogs,
StageFailureMessage,
} from '@spinnaker/core';

export function CloudfoundryCreateServiceKeyExecutionDetails(props: IExecutionDetailsSectionProps) {
const { stage } = props;
const { context } = stage;
const account = get(context, 'service.account', undefined);
const region = get(context, 'service.region', undefined);
const serviceInstanceName = get(context, 'serviceInstanceName', undefined);
const serviceKeyName = get(context, 'serviceKeyName', undefined);
return (
<ExecutionDetailsSection name={props.name} current={props.current}>
<div className="step-section-details">
<div className="row">
<div className="col-md-12">
<dl className="dl-horizontal">
<dt>Account</dt>
<dd>
<AccountTag account={account} />
</dd>
<dt>Region</dt>
<dd>
{region}
<br />
</dd>
<dt>Service Instance Name</dt>
<dd>
{serviceInstanceName}
<br />
</dd>
<dt>Service Key Name</dt>
<dd>
{serviceKeyName}
<br />
</dd>
</dl>
</div>
</div>
</div>
<StageFailureMessage stage={props.stage} message={props.stage.failureMessage} />
<StageExecutionLogs stage={props.stage} />
</ExecutionDetailsSection>
);
}

// TODO: refactor this to not use namespace
// eslint-disable-next-line
export namespace CloudfoundryCreateServiceKeyExecutionDetails {
export const title = 'cloudfoundryCreateServiceKeyConfig';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import * as React from 'react';

import { Option } from 'react-select';

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

interface ICloudfoundryCreateServiceKeyStageConfigState {
accounts: string[];
regions: string[];
}

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

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

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

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

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

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

private regionUpdated = (option: Option<string>) => {
const region = option.target.value;
this.props.updateStageField({
region,
});
};

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

return (
<div className="form-horizontal">
<StageConfigField label="Account">
<ReactSelectInput
clearable={false}
onChange={this.accountUpdated}
value={credentials}
stringOptions={accounts}
/>
</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="Service Key Name">
<TextInput
type="text"
className="form-control"
onChange={this.serviceKeyNameUpdated}
value={serviceKeyName}
/>
</StageConfigField>
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { CloudfoundryCreateServiceKeyStageConfig } from './CloudfoundryCreateServiceKeyStageConfig';
import { ExecutionDetailsTasks, IStage, Registry } from '@spinnaker/core';
import { CloudfoundryCreateServiceKeyExecutionDetails } from './CloudfoundryCreateServiceKeyExecutionDetails';

Registry.pipeline.registerStage({
accountExtractor: (stage: IStage) => stage.context.credentials,
configAccountExtractor: (stage: IStage) => [stage.credentials],
cloudProvider: 'cloudfoundry',
component: CloudfoundryCreateServiceKeyStageConfig,
controller: 'BaseProviderStageCtrl as baseProviderStageCtrl',
description: 'Create a service key',
executionDetailsSections: [CloudfoundryCreateServiceKeyExecutionDetails, ExecutionDetailsTasks],
key: 'createServiceKey',
label: 'Create Service Key',
validators: [
{ type: 'requiredField', fieldName: 'credentials', fieldLabel: 'account' },
{ type: 'requiredField', fieldName: 'region', preventSave: true },
{ type: 'requiredField', fieldName: 'serviceInstanceName', preventSave: true },
{ type: 'requiredField', fieldName: 'serviceKeyName', preventSave: true },
],
});
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export class CloudFoundryServerGroupCommandBuilder {
}).then(command => {
command.credentials = stage.credentials;
command.capacity = stage.capacity;
command.account = stage.account;
command.destination = stage.destination;
command.delayBeforeDisableSec = stage.delayBeforeDisableSec;
command.freeFormDetails = stage.freeFormDetails || command.freeFormDetails;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ICloudFoundryEnvVar } from 'cloudfoundry/domain';

export interface ICloudFoundryCreateServerGroupCommand extends IServerGroupCommand {
// clone server group model
account?: string;
destination?: ICloudFoundryDestination;
source?: ICloudFoundrySource;
rollback?: boolean;
Expand Down Expand Up @@ -38,7 +39,6 @@ export interface ICloudFoundrySource {

export interface ICloudFoundryDestination {
region: string;
account: string;
}

export interface ICloudFoundryManifestDirectSource {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class CloudFoundryServerGroupBasicSettings
};

private updateRegionList = (): void => {
const accountField = this.props.isPipelineClone ? 'destination.account' : 'credentials';
const accountField = this.props.isPipelineClone ? 'account' : 'credentials';
const credentials = get(this.props.formik.values, accountField, undefined);
if (credentials) {
AccountService.getRegionsForAccount(credentials).then(regions => {
Expand All @@ -74,7 +74,7 @@ export class CloudFoundryServerGroupBasicSettings
const { formik, isPipelineClone } = this.props;
const { accounts, regions } = this.state;
const { values } = formik;
const accountField = isPipelineClone ? 'destination.account' : 'credentials';
const accountField = isPipelineClone ? 'account' : 'credentials';
const regionField = isPipelineClone ? 'destination.region' : 'region';
return (
<div className="form-group">
Expand Down
1 change: 1 addition & 0 deletions app/scripts/modules/core/src/config/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export interface IFeatures {
// whether stages affecting infrastructure (like "Create Load Balancer") should be enabled or not
infrastructureStages?: boolean;
jobs?: boolean;
kubernetesRolloutStrategies?: boolean;
managedPipelineTemplatesV2UI?: boolean;
managedServiceAccounts?: boolean;
notifications?: boolean;
Expand Down
13 changes: 13 additions & 0 deletions app/scripts/modules/core/src/domain/IPipelineTemplateConfigV2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { IPipeline } from 'core/domain';

export interface IPipelineTemplateConfigV2 extends IPipeline {
inherit?: string[];
schema: string;
template: {
artifactAccount: string;
reference: string;
type: string;
};
type: string;
variables?: { [key: string]: any };
}
1 change: 1 addition & 0 deletions app/scripts/modules/core/src/domain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export * from './IOrchestratedItem';

export * from './IPipeline';
export * from './IPipelineTemplateV2';
export * from './IPipelineTemplateConfigV2';
export * from './IProject';
export * from './IPubsubSubscription';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,27 @@ export class PipelineTemplateReader {
});
}

public static getPipelineTemplateConfig({
name,
application,
source,
}: {
name: string;
application: string;
source: string;
}): Partial<IPipelineTemplateConfig> {
return {
config: {
schema: '1',
pipeline: {
name,
application,
template: { source },
},
},
};
}

public static getV2PipelineTemplateList(): IPromise<IPipelineTemplateV2[]> {
return API.one('pipelineTemplates')
.get()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import Select, { Option } from 'react-select';

import { IApplicationSummary } from 'core/application';

interface IApplicatonSelectorProps {
applications: IApplicationSummary[];
applicationSelectCallback: (selection: Option) => void;
selectedApplication: IApplicationSummary;
}

export default class ApplicationSelector extends React.Component<IApplicatonSelectorProps> {
public render() {
const { applications, applicationSelectCallback, selectedApplication } = this.props;

const selectedApplicationOption: Option = selectedApplication
? { label: selectedApplication.name, value: selectedApplication.name }
: null;

return (
<div className="form-group clearfix">
<div className="col-md-3 sm-label-right">
<b>Application</b>
</div>
<div className="col-md-7">
<Select
options={applications.map(({ name }: IApplicationSummary): Option => ({ label: name, value: name }))}
clearable={true}
value={selectedApplicationOption}
onChange={applicationSelectCallback}
onSelectResetsInput={false}
/>
</div>
</div>
);
}
}
Loading

0 comments on commit e9cb1d0

Please sign in to comment.