Skip to content

Commit

Permalink
feat(core/managed): add Managed Resources section to app config, allo…
Browse files Browse the repository at this point in the history
…w opting out (#7409)
  • Loading branch information
Erik Munson committed Sep 18, 2019
1 parent d0ceddb commit f8267a4
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CHAOS_MONKEY_CONFIG_COMPONENT } from 'core/chaosMonkey/chaosMonkeyConfi
import { TRAFFIC_GUARD_CONFIG_COMPONENT } from './trafficGuard/trafficGuardConfig.component';
import { SETTINGS } from 'core/config/settings';
import { ApplicationWriter } from 'core/application/service/ApplicationWriter';
import { ManagedReader } from 'core/managed';

const angular = require('angular');

Expand Down Expand Up @@ -64,5 +65,14 @@ module.exports = angular
this.notifications = notifications;
});
};

if (this.feature.managedResources) {
this.hasManagedResources = false;
ManagedReader.getApplicationSummary(this.application.name).then(({ hasManagedResources }) => {
$scope.$applyAsync(() => {
this.hasManagedResources = hasManagedResources;
});
});
}
},
]);
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
<page-section key="location" label="Application Attributes">
<application-attributes application="config.application"></application-attributes>
</page-section>
<page-section
key="managed-resources"
label="Managed Resources"
visible="(config.feature.managedResources && config.hasManagedResources) || false"
>
<managed-resource-config application="config.application"> </managed-resource-config>
</page-section>
<page-section key="notifications" label="Notifications">
<application-notifications
application="config.application"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.ManagedResourceConfig .rainbow-icon {
text-shadow: 0px 1px 4px rgba(0, 0, 0, 0.5);
}

.ManagedResourceConfig .paused-warning {
background-color: var(--color-warning-light);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import * as React from 'react';
import { module } from 'angular';
import { react2angular } from 'react2angular';
import * as ReactGA from 'react-ga';
import * as classNames from 'classnames';

import { NgReact } from 'core/reactShims';
import { Application } from 'core/application';
import { useData } from 'core/presentation';
import { ValidationMessage } from 'core/validation';
import { Spinner } from 'core/widgets';
import { ManagedReader, ManagedWriter } from 'core/managed';

import './ManagedResourceConfig.less';

const { useState, useEffect } = React;
const { ButtonBusyIndicator } = NgReact;

export interface IManagedResourceConfigProps {
application: Application;
}

const logClick = (label: string, application: string) =>
ReactGA.event({
category: 'Managed Resource Config',
action: `${label} clicked`,
label: application,
});

const getManagementStatus = (paused: boolean) => {
if (paused) {
return (
<>
<div className="sp-padding-m sp-margin-m-bottom paused-warning">
<i className="fa fa-pause sp-margin-xs-right" /> <b>Continuous management of resources is paused.</b>
</div>
<p className="sp-margin-l-bottom">
Spinnaker is configured to continuously manage some of this application's resources, but management has been
paused. When resumed, Spinnaker will take action to make each resource match its declarative configuration.
</p>
</>
);
} else {
return (
<>
<p>
<span className="rainbow-icon">🌈</span> <b>Spinnaker is continuously managing some resources.</b>
</p>
<p className="sp-margin-l-bottom">
If you need to temporarily stop Spinnaker from managing resources — for example, if something is wrong and
manual intervention is required — you can pause management and resume it later. Pausing affects all managed
resources within this application.
</p>
</>
);
}
};

const ManagedResourceConfig = ({ application }: IManagedResourceConfigProps) => {
const [pausePending, setPausePending] = useState(false);
const [pauseFailed, setPauseFailed] = useState(false);
const [paused, setPaused] = useState(false);
const { status: vetoStatus, result: vetos, refresh } = useData(() => ManagedReader.getApplicationVetos(), [], []);

const isRejected = vetos && vetos.includes(application.name);
useEffect(() => {
setPaused(isRejected);
}, [isRejected]);

const pauseManagement = () => {
setPausePending(true);
setPauseFailed(false);
logClick('Pause Management', application.name);

ManagedWriter.pauseResourceManagement(application.name)
.then(() => setPaused(true))
.catch(() => setPauseFailed(true))
.finally(() => setPausePending(false));
};

const resumeManagement = () => {
setPausePending(true);
setPauseFailed(false);
logClick('Resume Management', application.name);

ManagedWriter.resumeResourceManagement(application.name)
.then(() => setPaused(false))
.catch(() => setPauseFailed(true))
.finally(() => setPausePending(false));
};

if (['NONE', 'PENDING'].includes(vetoStatus)) {
return <Spinner size="medium" />;
} else if (vetoStatus === 'REJECTED') {
return (
<div className="alert alert-danger">
Something went wrong.{' '}
<button className="btn btn-link" onClick={refresh}>
Try again
</button>
</div>
);
}

const iconClass = paused ? 'fa-play' : 'fa-pause';

return (
<div className="ManagedResourceConfig">
{getManagementStatus(paused)}
<button
className="btn btn-primary"
disabled={pausePending}
onClick={paused ? resumeManagement : pauseManagement}
type="button"
>
{(!pausePending && <i className={classNames('fa sp-margin-xs-right', iconClass)} />) || <ButtonBusyIndicator />}{' '}
{paused ? 'Resume Management' : 'Pause Management'}
</button>
{pauseFailed && (
<div className="sp-margin-l-top">
<ValidationMessage type="error" message="Saving failed." />
</div>
)}
<div className="color-text-caption sp-margin-l-top">
Not sure what this means?{' '}
<a
target="_blank"
onClick={() => logClick('Documentation', application.name)}
href="https://www.spinnaker.io/reference/managed-delivery"
>
Check out our documentation
</a>
</div>
</div>
);
};

export const MANAGED_RESOURCE_CONFIG = 'spinnaker.core.managedResourceConfig.component';
module(MANAGED_RESOURCE_CONFIG, []).component(
'managedResourceConfig',
react2angular(ManagedResourceConfig, ['application']),
);
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 @@ -50,6 +50,7 @@ export interface IFeatures {
jobs?: boolean;
managedPipelineTemplatesV2UI?: boolean;
managedServiceAccounts?: boolean;
managedResources?: boolean;
notifications?: boolean;
pagerDuty?: boolean;
pipelines?: boolean;
Expand Down
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 @@ -45,6 +45,7 @@ import { HELP_MODULE } from './help/help.module';
import { INSIGHT_MODULE } from './insight/insight.module';
import { INTERCEPTOR_MODULE } from './interceptor/interceptor.module';
import { LOAD_BALANCER_MODULE } from './loadBalancer/loadBalancer.module';
import { MANAGED_RESOURCE_CONFIG } from './application/config/managedResources/ManagedResourceConfig';

import { NETWORK_INTERCEPTOR } from './api/network.interceptor';

Expand Down Expand Up @@ -114,6 +115,7 @@ module(CORE_MODULE, [
LABEL_FILTER_COMPONENT,
LOAD_BALANCER_MODULE,

MANAGED_RESOURCE_CONFIG,
require('./modal/modal.module').name,

NETWORK_INTERCEPTOR,
Expand Down
23 changes: 23 additions & 0 deletions app/scripts/modules/core/src/managed/ManagedReader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { IPromise } from 'angular';

import { API } from 'core/api';

export interface IManagedApplicationSummary {
hasManagedResources: boolean;
}

export class ManagedReader {
public static getApplicationSummary(app: string): IPromise<IManagedApplicationSummary> {
return API.one('managed')
.one('application', app)
.get();
}

public static getApplicationVetos(): IPromise<string[]> {
return API.one('managed')
.all('vetos')
.one('ApplicationVeto')
.all('rejections')
.get();
}
}
21 changes: 21 additions & 0 deletions app/scripts/modules/core/src/managed/ManagedWriter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IPromise } from 'angular';

import { API } from 'core/api';

export class ManagedWriter {
public static pauseResourceManagement(application: string): IPromise<void> {
return API.one('managed')
.all('vetos')
.one('ApplicationVeto')
.data({ application, optedOut: true })
.post();
}

public static resumeResourceManagement(application: string): IPromise<void> {
return API.one('managed')
.all('vetos')
.one('ApplicationVeto')
.data({ application, optedOut: false })
.post();
}
}
2 changes: 2 additions & 0 deletions app/scripts/modules/core/src/managed/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './ManagedReader';
export * from './ManagedWriter';
export * from './ManagedResourceDetailsIndicator';
export * from './managedResourceDetailsIndicator.component';
2 changes: 2 additions & 0 deletions settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var iapRefresherEnabled = process.env.IAP_REFRESHER_ENABLED === 'true' ? true :
var infrastructureEnabled = process.env.INFRA_ENABLED === 'true' ? true : false;
var managedPipelineTemplatesV2UIEnabled = process.env.MANAGED_PIPELINE_TEMPLATES_V2_UI_ENABLED === 'true';
var managedServiceAccountsEnabled = process.env.MANAGED_SERVICE_ACCOUNTS_ENABLED === 'true';
var managedResourcesEnabled = process.env.MANAGED_RESOURCES_ENABLED === 'true';
var onDemandClusterThreshold = process.env.ON_DEMAND_CLUSTER_THRESHOLD || '350';
var reduxLoggerEnabled = process.env.REDUX_LOGGER === 'true';
var templatesEnabled = process.env.TEMPLATES_ENABLED === 'true';
Expand Down Expand Up @@ -73,6 +74,7 @@ window.spinnakerSettings = {
jobs: false,
managedPipelineTemplatesV2UI: managedPipelineTemplatesV2UIEnabled,
managedServiceAccounts: managedServiceAccountsEnabled,
managedResources: managedResourcesEnabled,
notifications: false,
pagerDuty: false,
pipelineTemplates: false,
Expand Down

0 comments on commit f8267a4

Please sign in to comment.