Skip to content

Commit

Permalink
feat(infrastructure/buttons): Add a new property configurable on sett… (
Browse files Browse the repository at this point in the history
#7822)

* feat(infrastructure/buttons): Add a new property configurable on settings-local.yml to enable/disable the create Kubernetes infrastructure buttons (Create: Server Group, Load Balancer and Firewall).

* feat(infrastructure/buttons): Hide buttons instead of disable them, Added same behavior for the Edit dropdown options in both Kubernetes versions; V1 Clusters: (the Edit option does not exist) added on Load Balancer & Firewall, V2 added in all.

* feat(infrastructure/buttons): Global flag, configurable by settings-local.js, by default is disabled unless the property is true, applies to create, edit and delete. Discard changes for v1 this feature only applies for v2.

* feat(infrastructure/buttons): Add properties by provider and by infrastructure object (Cluster, LoadBalancer and Firewall)

* feat(infrastructure/buttons): remove console logs and comments.

* feat(infrastructure/buttons): remove console logs and comments.

* feat(infrastructure/buttons): Unit Test modifications in order to add the infra flag

* feat(infrastructure/buttons): Add a Functional Test in order to support the new behavior: by default the flags are set to false therefore the Create buttons are not shown. Also add infra properties for GCE.

* feat(infrastructure/buttons): Use one single flag to enable/disable kubernetes creation buttons, all the other providers are have not been affected. Block the edition/deletion of the objects already created if the flag is set to false.

* feat(infrastructure/buttons): revert changes on ProviderSelectionService.spec.ts

* change method isDisabled on ProviderSelectionService to return a promise instead a boolean

* feat(infrastructure/buttons): CloudProviderRegistry add method to determine if the provider should be disabled in case the 'infraWritesEnabled' property is set to false or undefined, add unit tests

* feat(infrastructure/buttons): CloudProviderRegistry add method to determine if the provider should be d
isabled in case the 'infraWritesEnabled' property is set to false or undefined, add unit tests

* feat(k8s/infra-flag): Add a new property configurable on settings-local.yml to enable/disable the create Kubernetes infrastructure buttons

* config(jfrog/repository): rename the property name on the ProviderSelectionService.spec.ts file

* feat(k8s/infra): remove kubernetes v2 folder and skin selection

Co-authored-by: Jorge Dominguez <jorge.dominguez@armory.io>
Co-authored-by: Jorge <jorgebee65@gmail.com>
Co-authored-by: Kevin Woo <kevinawoo@gmail.com>
  • Loading branch information
4 people committed Apr 6, 2021
1 parent f4c21d0 commit 0bb9263
Show file tree
Hide file tree
Showing 21 changed files with 203 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* tslint:disable: no-console */
import { cloneDeep, uniq, without } from 'lodash';
import { cloneDeep, uniq, without, isNil } from 'lodash';

import { SETTINGS } from 'core/config/settings';

Expand Down Expand Up @@ -105,4 +105,15 @@ export class CloudProviderRegistry {
}
return current;
}

//If the flag kubernetesAdHocInfraWritesEnabled is set to "false" then is disabled
public static isDisabled(cloudProvider: string) {
if (cloudProvider !== 'kubernetes') {
return false;
}
return (
isNil(CloudProviderRegistry.getValue(cloudProvider, 'kubernetesAdHocInfraWritesEnabled')) ||
CloudProviderRegistry.getValue(cloudProvider, 'kubernetesAdHocInfraWritesEnabled') === false
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,95 @@ describe('ProviderSelectionService: API', () => {
$scope.$digest();
expect(provider).toBe('titus');
});

it('should return k8s provider in case the kubernetesAdHocInfraWritesEnabled is set to true and is the only provider configured', () => {
let provider = '';
hasValue = true;
const k8s = fakeAccount('kubernetes');
k8s.type = 'kubernetes';
accounts = [k8s];
let configuration = {
name: 'Kubernetes',
kubernetesAdHocInfraWritesEnabled: true,
};
CloudProviderRegistry.registerProvider('kubernetes', configuration);
ProviderSelectionService.selectProvider(application, 'securityGroup').then((_provider) => {
provider = _provider;
});
$scope.$digest();
expect(provider).toBe('kubernetes');
});

it('should use "aws" as the default provider in case the only provider is k8s and the kubernetesAdHocInfraWritesEnabled is set to false', () => {
let provider = '';
hasValue = true;
const k8s = fakeAccount('kubernetes');
k8s.type = 'kubernetes';
accounts = [k8s];
let configuration = {
name: 'Kubernetes',
kubernetesAdHocInfraWritesEnabled: false,
};
CloudProviderRegistry.registerProvider('kubernetes', configuration);
ProviderSelectionService.selectProvider(application, 'securityGroup').then((_provider) => {
provider = _provider;
});
$scope.$digest();
expect(provider).toBe('aws');
});

it('should use "aws" as the default provider in case the only provider is k8s and the kubernetesAdHocInfraWritesEnabled is not specified', () => {
let provider = '';
hasValue = true;
const k8s = fakeAccount('kubernetes');
k8s.type = 'kubernetes';
accounts = [k8s];
let configuration = {
name: 'Kubernetes',
};
CloudProviderRegistry.registerProvider('kubernetes', configuration);
ProviderSelectionService.selectProvider(application, 'securityGroup').then((_provider) => {
provider = _provider;
});
$scope.$digest();
expect(provider).toBe('aws');
});

it('should not use "k8s" as an option for the modal when the k8s kubernetesAdHocInfraWritesEnabled is set to false and there are others providers', () => {
let provider = '';
hasValue = true;
const k8s = fakeAccount('kubernetes');
k8s.type = 'kubernetes';
accounts = [k8s, fakeAccount('gce')];
let configuration = {
name: 'Kubernetes',
kubernetesAdHocInfraWritesEnabled: false,
};
CloudProviderRegistry.registerProvider('kubernetes', configuration);
CloudProviderRegistry.registerProvider('gce', config);
ProviderSelectionService.selectProvider(application, 'securityGroup').then((_provider) => {
provider = _provider;
});
$scope.$digest();
expect(provider).toBe('gce');
});

it('should use "modalProvider" when the k8s kubernetesAdHocInfraWritesEnabled is set to true and there are others providers', () => {
let provider = '';
hasValue = true;
const k8s = fakeAccount('kubernetes');
k8s.type = 'kubernetes';
accounts = [k8s, fakeAccount('gce')];
let configuration = {
name: 'Kubernetes',
kubernetesAdHocInfraWritesEnabled: true,
};
CloudProviderRegistry.registerProvider('kubernetes', configuration);
CloudProviderRegistry.registerProvider('gce', config);
ProviderSelectionService.selectProvider(application, 'securityGroup').then((_provider) => {
provider = _provider;
});
$scope.$digest();
expect(provider).toBe('modalProvider');
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

import { uniq } from 'lodash';
import { $q } from 'ngimport';

Expand Down Expand Up @@ -27,13 +28,16 @@ export class ProviderSelectionService {
return filterFn(application, acc, CloudProviderRegistry.getProvider(acc.cloudProvider));
});
}

// reduce the accounts to the smallest, unique collection taking into consideration the useProvider values
const providerOptions = uniq(
reducedAccounts.map((a) => {
const providerFeature = CloudProviderRegistry.getProvider(a.cloudProvider)[feature] || {};
return providerFeature.useProvider || a.cloudProvider;
}),
reducedAccounts
.filter((a) => {
return !CloudProviderRegistry.isDisabled(a.cloudProvider);
})
.map((a) => {
const providerFeature = CloudProviderRegistry.getProvider(a.cloudProvider)[feature] || {};
return providerFeature.useProvider || a.cloudProvider;
}),
);

let provider;
Expand All @@ -47,4 +51,20 @@ export class ProviderSelectionService {
return provider;
});
}

public static isDisabled(app: Application): PromiseLike<boolean> {
return AccountService.applicationAccounts(app).then((accounts: IAccountDetails[]) => {
let isDisable = false;
if (accounts.length === 1) {
accounts
.filter((a) => {
return CloudProviderRegistry.hasValue(a.cloudProvider, 'kubernetesAdHocInfraWritesEnabled');
})
.map((a) => {
isDisable = !CloudProviderRegistry.getValue(a.cloudProvider, 'kubernetesAdHocInfraWritesEnabled');
});
}
return isDisable;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ module(CORE_CLUSTER_ALLCLUSTERS_CONTROLLER, [
ClusterState.filterModel.activate();
this.initialized = false;
this.dataSource = app.getDataSource('serverGroups');
this.application = app;

$scope.filterModel = ClusterState.filterModel;

ProviderSelectionService.isDisabled(app).then((disabled) => {
$scope.isDisabled = disabled;
});
this.createLabel = 'Create Server Group';

app
Expand Down
2 changes: 1 addition & 1 deletion app/scripts/modules/core/src/cluster/allClusters.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
</div>
<div class="col-lg-3 col-md-2 col-sm-2">
<div class="application-actions">
<button class="btn btn-sm btn-default" ng-click="ctrl.createServerGroup()">
<button class="btn btn-sm btn-default" ng-click="ctrl.createServerGroup()" ng-hide="isDisabled">
<span class="glyphicon glyphicon-plus-sign visible-lg-inline"></span>
<span
class="glyphicon glyphicon-plus-sign visible-md-inline visible-sm-inline"
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 @@ -136,6 +136,7 @@ export interface ISpinnakerSettings {
searchVersion: 1 | 2;
triggerTypes: string[];
useClassicFirewallLabels: boolean;
kubernetesAdHocInfraWritesEnabled: boolean;
}

export const SETTINGS: ISpinnakerSettings = (window as any).spinnakerSettings || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,19 @@ export interface ICreateLoadBalancerButtonProps {
app: Application;
}

export class CreateLoadBalancerButton extends React.Component<ICreateLoadBalancerButtonProps> {
export class CreateLoadBalancerButton extends React.Component<ICreateLoadBalancerButtonProps, { isDisabled: boolean }> {
constructor(props: ICreateLoadBalancerButtonProps) {
super(props);
this.state = { isDisabled: false };
}

componentDidMount() {
const { app } = this.props;
ProviderSelectionService.isDisabled(app).then((val) => {
this.setState({
isDisabled: val,
});
});
}

private createLoadBalancerProviderFilterFn = (
Expand Down Expand Up @@ -77,16 +87,20 @@ export class CreateLoadBalancerButton extends React.Component<ICreateLoadBalance
};

public render() {
return (
<div>
<button className="btn btn-sm btn-default" onClick={this.createLoadBalancer}>
<span className="glyphicon glyphicon-plus-sign visible-lg-inline" />
<Tooltip value="Create Load Balancer">
<span className="glyphicon glyphicon-plus-sign visible-md-inline visible-sm-inline" />
</Tooltip>
<span className="visible-lg-inline"> Create Load Balancer</span>
</button>
</div>
);
if (!this.state.isDisabled) {
return (
<div>
<button className="btn btn-sm btn-default" onClick={this.createLoadBalancer}>
<span className="glyphicon glyphicon-plus-sign visible-lg-inline" />
<Tooltip value="Create Load Balancer">
<span className="glyphicon glyphicon-plus-sign visible-md-inline visible-sm-inline" />
</Tooltip>
<span className="visible-lg-inline"> Create Load Balancer</span>
</button>
</div>
);
} else {
return <div></div>;
}
}
}
11 changes: 6 additions & 5 deletions app/scripts/modules/core/src/securityGroup/SecurityGroups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Spinner } from 'core/widgets/spinners/Spinner';

import { CreateSecurityGroupButton } from './CreateSecurityGroupButton';
import { SecurityGroupPod } from './SecurityGroupPod';
import { ProviderSelectionService } from '../cloudProvider/providerSelection/ProviderSelectionService';
import { FirewallLabels } from './label/FirewallLabels';

const { useEffect, useState } = React;
Expand Down Expand Up @@ -83,7 +84,7 @@ const Filters = () => {
export const SecurityGroups = ({ app }: ISecurityGroupsProps) => {
const [filterModel, setFilterModel] = useState<IFilterModel>({ groups: [], tags: [] });
const [initialized, setInitialized] = useState(false);

const [buttonDisable, setButtonDisable] = useState(false);
const groupsUpdated = () => {
setFilterModel({
groups: SecurityGroupState.filterModel.asFilterModel.groups,
Expand Down Expand Up @@ -121,7 +122,9 @@ export const SecurityGroups = ({ app }: ISecurityGroupsProps) => {
});
app.setActiveState(app.securityGroups);
SecurityGroupState.filterModel.asFilterModel.activate();

ProviderSelectionService.isDisabled(app).then((val) => {
setButtonDisable(val);
});
return () => {
groupsUpdatedListener.unsubscribe();
securityGroupsRefreshUnsubscribe();
Expand All @@ -141,9 +144,7 @@ export const SecurityGroups = ({ app }: ISecurityGroupsProps) => {
<div className="header row header-clusters">
<Filters />
<div className="col-lg-4 col-md-2">
<div className="application-actions">
<CreateSecurityGroupButton app={app} />
</div>
<div className="application-actions">{buttonDisable ? <div /> : <CreateSecurityGroupButton app={app} />}</div>
</div>
<FilterTags tags={filterModel.tags} tagCleared={updateSecurityGroupGroups} clearFilters={clearFilters} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@
</div>

<div class="form-group" ng-if="$ctrl.capacityProviderState.useCapacityProviders">
<ecs-capacity-provider-react command="$ctrl.command"
notify-angular="$ctrl.notifyAngular"
configure-command="$ctrl.configureCommand"/>
<ecs-capacity-provider-react
command="$ctrl.command"
notify-angular="$ctrl.notifyAngular"
configure-command="$ctrl.configureCommand"
></ecs-capacity-provider-react>
</div>

<div class="form-group" ng-if="!$ctrl.capacityProviderState.useCapacityProviders" style="padding-top: 10px">
Expand Down
1 change: 1 addition & 0 deletions app/scripts/modules/kubernetes/src/kubernetes.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ if (SETTINGS.feature.kubernetesRawResources) {
module(KUBERNETES_MODULE, requires).config(() => {
CloudProviderRegistry.registerProvider('kubernetes', {
name: 'Kubernetes',
kubernetesAdHocInfraWritesEnabled: SETTINGS.kubernetesAdHocInfraWritesEnabled,
logo: {
path: kubernetesLogo,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { StateService } from '@uirouter/angularjs';
import { IController, IScope, module } from 'angular';
import { IModalService } from 'angular-ui-bootstrap';

import { Application, ILoadBalancer, IManifest, ManifestReader } from '@spinnaker/core';
import { Application, ILoadBalancer, IManifest, ManifestReader, SETTINGS } from '@spinnaker/core';

import { IKubernetesLoadBalancer } from '../../interfaces';
import { KubernetesManifestCommandBuilder } from '../../manifest/manifestCommandBuilder.service';
Expand Down Expand Up @@ -32,6 +32,7 @@ class KubernetesLoadBalancerDetailsController implements IController {
.ready()
.then(() => {
this.extractLoadBalancer(loadBalancer);
this.$scope.isDisabled = !SETTINGS.kubernetesAdHocInfraWritesEnabled;
dataSource.onRefresh(this.$scope, () => this.extractLoadBalancer(loadBalancer));
})
.catch(() => this.autoClose());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ <h3 class="horizontal middle space-between flex-1" select-on-dbl-click>
</div>
<div class="actions">
<div class="dropdown" uib-dropdown dropdown-append-to-body>
<button type="button" class="btn btn-sm btn-primary dropdown-toggle" uib-dropdown-toggle>
<button type="button" class="btn btn-sm btn-primary dropdown-toggle" uib-dropdown-toggle ng-hide="isDisabled">
{{ctrl.loadBalancer.kind | robotToHuman}} Actions <span class="caret"></span>
</button>
<ul class="dropdown-menu" uib-dropdown-menu role="menu">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
ManifestReader,
SECURITY_GROUP_READER,
SecurityGroupReader,
SETTINGS,
} from '@spinnaker/core';

import { IKubernetesSecurityGroup } from '../../interfaces';
Expand Down Expand Up @@ -49,6 +50,7 @@ class KubernetesSecurityGroupDetailsController implements IController {
.ready()
.then(() => {
this.extractSecurityGroup(resolvedSecurityGroup);
this.$scope.isDisabled = !SETTINGS.kubernetesAdHocInfraWritesEnabled;
dataSource.onRefresh(this.$scope, () => this.extractSecurityGroup(resolvedSecurityGroup));
})
.catch(() => this.autoClose());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ <h3 class="horizontal middle space-between flex-1" select-on-dbl-click>
</div>
<div class="actions">
<div class="dropdown" uib-dropdown dropdown-append-to-body>
<button type="button" class="btn btn-sm btn-primary dropdown-toggle" uib-dropdown-toggle>
<button type="button" class="btn btn-sm btn-primary dropdown-toggle" uib-dropdown-toggle ng-hide="isDisabled">
<firewall-label label="{{ctrl.securityGroup.kind | robotToHuman}}"></firewall-label> Actions
<span class="caret"></span>
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
ManifestReader,
SERVER_GROUP_WRITER,
ServerGroupReader,
SETTINGS,
} from '@spinnaker/core';

import { IKubernetesServerGroup } from '../../interfaces';
Expand Down Expand Up @@ -45,6 +46,7 @@ class KubernetesServerGroupDetailsController implements IController {
.ready()
.then(() => {
this.extractServerGroup(serverGroup);
this.$scope.isDisabled = !SETTINGS.kubernetesAdHocInfraWritesEnabled;
dataSource.onRefresh(this.$scope, () => this.extractServerGroup(serverGroup));
})
.catch(() => this.autoClose());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ <h3 class="horizontal middle space-between flex-1" select-on-dbl-click>
</div>
<div class="actions">
<div class="dropdown" uib-dropdown dropdown-append-to-body>
<button type="button" class="btn btn-sm btn-primary dropdown-toggle" uib-dropdown-toggle>
<button type="button" class="btn btn-sm btn-primary dropdown-toggle" uib-dropdown-toggle ng-hide="isDisabled">
{{ctrl.serverGroup.kind | robotToHuman}} Actions <span class="caret"></span>
</button>
<ul class="dropdown-menu" uib-dropdown-menu role="menu">
Expand Down
Loading

0 comments on commit 0bb9263

Please sign in to comment.