UNPKG

@spotinst/spinnaker-deck

Version:

Spinnaker-Deck service, forked with support to Spotinst

542 lines (480 loc) 18.8 kB
import UIROUTER_ANGULARJS, { StateService } from '@uirouter/angularjs'; import { IController, module } from 'angular'; import ANGULAR_UI_BOOTSTRAP, { IModalServiceInstance } from 'angular-ui-bootstrap'; import { cloneDeep, trimEnd } from 'lodash'; import { AccountService, Application, IAccountDetails, ILoadBalancer, INetwork, IRegion, ISubnet, LoadBalancerWriter, NameUtils, NetworkReader, SubnetReader, TaskMonitor, } from '@spinnaker/core'; import { IOracleBackEndSet, IOracleListener, IOracleListenerCertificate, IOracleLoadBalancer, IOracleSubnet, LoadBalancingPolicy, } from 'oracle/domain/IOracleLoadBalancer'; import { ORACLE_LOAD_BALANCER_TRANSFORMER, OracleLoadBalancerTransformer } from '../loadBalancer.transformer'; export class OracleLoadBalancerController implements IController { public oracle = 'oracle'; public shapes: string[] = ['100Mbps', '400Mbps', '8000Mbps']; // TODO desagar use listShapes to get this from clouddriver later public loadBalancingPolicies: string[] = Object.keys(LoadBalancingPolicy).map((k) => (LoadBalancingPolicy as any)[k]); public pages: { [key: string]: any } = { properties: require('./createLoadBalancerProperties.html'), listeners: require('./listeners.html'), backendSets: require('./backendSets.html'), certificates: require('./certificates.html'), }; public state: { [key: string]: boolean } = { accountsLoaded: false, submitting: false, }; public allVnets: INetwork[]; public allSubnets: IOracleSubnet[]; public filteredVnets: INetwork[]; public filteredSubnets: ISubnet[]; public filteredSubnetsByType: ISubnet[]; public selectedVnet: INetwork; public selectedSubnets: IOracleSubnet[]; public numSubnetsAllowed = 1; public listeners: IOracleListener[] = []; public backendSets: IOracleBackEndSet[] = []; public certificates: IOracleListenerCertificate[] = []; public static $inject = [ '$scope', '$uibModalInstance', '$state', 'oracleLoadBalancerTransformer', 'application', 'loadBalancer', 'isNew', ]; constructor( private $scope: ng.IScope, private $uibModalInstance: IModalServiceInstance, private $state: StateService, private oracleLoadBalancerTransformer: OracleLoadBalancerTransformer, private application: Application, private loadBalancer: IOracleLoadBalancer, private isNew: boolean, ) { this.initializeController(); } public onApplicationRefresh() { // If the user has already closed the modal, do not navigate to the new details view if (this.$scope.$$destroyed) { return; } this.$uibModalInstance.close(); const newStateParams = { name: this.loadBalancer.name, accountId: this.loadBalancer.account, region: this.loadBalancer.region, provider: 'oracle', }; if (!this.$state.includes('**.loadBalancerDetails')) { this.$state.go('.loadBalancerDetails', newStateParams); } else { this.$state.go('^.loadBalancerDetails', newStateParams); } } public onTaskComplete() { this.application.loadBalancers.refresh(); this.application.loadBalancers.onNextRefresh(this.$scope, this.onApplicationRefresh); } public initializeCreateMode() { AccountService.listAccounts(this.oracle).then((accounts: IAccountDetails[]) => { this.$scope.accounts = accounts; // TODO desagar does this need to be in $scope? this.state.accountsLoaded = true; this.$scope.state = this.state; this.accountUpdated(); }); this.loadVnets(); this.loadSubnets(); } private initControllerFromLoadBalancerCmd() { this.numSubnetsAllowed = this.calcNumSubnetsAllowed(); if (this.$scope.loadBalancerCmd.listeners) { Object.keys(this.$scope.loadBalancerCmd.listeners).forEach((lis) => { this.listeners.push(this.$scope.loadBalancerCmd.listeners[lis]); }); } if (this.$scope.loadBalancerCmd.backendSets) { Object.keys(this.$scope.loadBalancerCmd.backendSets).forEach((b) => { this.backendSets.push(this.$scope.loadBalancerCmd.backendSets[b]); }); } if (this.$scope.loadBalancerCmd.certificates) { Object.keys(this.$scope.loadBalancerCmd.certificates).forEach((b) => { this.certificates.push(this.$scope.loadBalancerCmd.certificates[b]); }); } } public initializeController() { if (this.loadBalancer) { this.$scope.loadBalancerCmd = this.oracleLoadBalancerTransformer.convertLoadBalancerForEditing(this.loadBalancer); this.initControllerFromLoadBalancerCmd(); if (this.isNew) { const nameParts = NameUtils.parseLoadBalancerName(this.loadBalancer.name); this.$scope.loadBalancerCmd.stack = nameParts.stack; this.$scope.loadBalancerCmd.detail = nameParts.freeFormDetails; delete this.$scope.loadBalancerCmd.name; } } else { this.$scope.loadBalancerCmd = this.oracleLoadBalancerTransformer.constructNewLoadBalancerTemplate( this.application, ); } this.$scope.prevBackendSetNames = []; this.$scope.prevCertNames = []; if (this.isNew) { this.updateName(); this.updateLoadBalancerNames(); this.initializeCreateMode(); } this.$scope.taskMonitor = new TaskMonitor({ application: this.application, title: (this.isNew ? 'Creating ' : 'Updating ') + 'your load balancer', modalInstance: this.$uibModalInstance, onTaskComplete: this.onTaskComplete, }); } public updateLoadBalancerNames() { const account = this.$scope.loadBalancerCmd.credentials; const region = this.$scope.loadBalancerCmd.region; const accountLoadBalancerNamesByRegion: { [key: string]: string[] } = {}; this.application .getDataSource('loadBalancers') .refresh(true) .then(() => { const loadBalancers: ILoadBalancer[] = this.application.loadBalancers.data; loadBalancers.forEach((loadBalancer) => { if (loadBalancer.account === account) { accountLoadBalancerNamesByRegion[loadBalancer.region] = accountLoadBalancerNamesByRegion[loadBalancer.region] || []; accountLoadBalancerNamesByRegion[loadBalancer.region].push(loadBalancer.name); } }); this.$scope.existingLoadBalancerNames = accountLoadBalancerNamesByRegion[region] || []; }); } public validateBeforeSubmit() { return this.propertiesValid() && this.listenersValid(); } /** * Used to prevent form submission if listeners are invalid * Currently it calls the two validations applicable to listeners. * @returns {boolean} */ public listenersValid() { return this.listenersUniqueProtocolPort() && this.listenersBackendSetsExist() && this.listenersCertificatesExist(); } /** * Used to prevent form submission if the properties section is invalid * Current the only validation is for subnet count. */ public propertiesValid() { return this.selectedSubnets && this.selectedSubnets.length === this.calcNumSubnetsAllowed(); } public listenersUniqueProtocolPort() { // validate that listeners have unique protocol/port combination const countsMap: { [key: string]: number } = {}; this.listeners.reduce((counts, listener) => { const protocolPort = listener.protocol + '_' + listener.port; counts[protocolPort] = counts[protocolPort] ? counts[protocolPort] + 1 : 1; return counts; }, countsMap); // There should be no protocol/port combo in the countsMap with a count > 1 return ( Object.keys(countsMap).filter((key) => { return countsMap[key] > 1; }).length === 0 ); } public listenersBackendSetsExist() { // validate that the listeners' selected backend sets must exist. This is needed because Angular // does not clear the selected backendSet from the drop down if the backend set is deleted. const listenersWithNonExistentBackendSet: IOracleListener[] = this.listeners.filter( (listener) => !this.backendSets.find((backendSet) => backendSet.name === listener.defaultBackendSetName), ); return listenersWithNonExistentBackendSet.length === 0; } public listenersCertificatesExist() { // validate that the listeners' selected certificate names exist. This is needed because Angular // does not clear the selected certificate from the drop down if the certificate is deleted. const listenersWithNonExistentCertificate: IOracleListener[] = this.listeners.filter( (listener) => listener.sslConfiguration && !this.certificates.find((cert) => cert.certificateName === listener.sslConfiguration.certificateName), ); return listenersWithNonExistentCertificate.length === 0; } public updateName() { this.$scope.loadBalancerCmd.name = this.getName(); } public getName() { const lb = this.$scope.loadBalancerCmd; const lbName = [this.application.name, lb.stack || '', lb.detail || ''].join('-'); return trimEnd(lbName, '-'); } public accountUpdated() { this.loadRegionsForAccount(); } public regionUpdated() { this.updateLoadBalancerNames(); this.updateVnets(); } public loadRegionsForAccount() { AccountService.getRegionsForAccount(this.$scope.loadBalancerCmd.credentials).then((regions: IRegion[]) => { this.$scope.regions = regions; // TODO desagar does this need to be in $scope? if (regions.length === 1) { this.$scope.loadBalancerCmd.region = regions[0].name; this.regionUpdated(); } }); } public loadVnets() { NetworkReader.listNetworksByProvider(this.oracle).then((vnets: INetwork[]) => { this.allVnets = vnets || []; if (this.$scope.loadBalancerCmd.region) { this.updateVnets(); } }); } public loadSubnets() { SubnetReader.listSubnetsByProvider(this.oracle).then((subnets: IOracleSubnet[]) => { this.allSubnets = subnets || []; }); } public updateVnets() { const account = this.$scope.loadBalancerCmd.credentials; const region = this.$scope.loadBalancerCmd.region; this.filteredVnets = this.allVnets.filter((vnet: INetwork) => { return vnet.account === account && vnet.region === region; }); } public updateSubnets(network: INetwork) { this.selectedSubnets = []; this.$scope.loadBalancerCmd.subnetIds = []; this.filteredSubnets = this.allSubnets.filter((subnet: IOracleSubnet) => { return subnet.vcnId === network.id; }); this.filteredSubnetsByType = cloneDeep(this.filteredSubnets); } public selectedVnetChanged(network: INetwork) { this.selectedVnet = network; this.$scope.loadBalancerCmd.vpcId = network.id; this.updateSubnets(network); } public selectedSubnetsChanged(selectedSubnet: IOracleSubnet) { if (selectedSubnet.availabilityDomain) { this.filteredSubnetsByType = this.filteredSubnets.filter((subnet: IOracleSubnet) => { return !!subnet.availabilityDomain; }); } else { this.filteredSubnetsByType = []; } } public selectedSubnetRemoved() { if (this.selectedSubnets.length === 0) { this.filteredSubnetsByType = cloneDeep(this.filteredSubnets); } if (this.selectedSubnets.length === 1 && this.selectedSubnets[0].availabilityDomain) { this.filteredSubnetsByType = this.filteredSubnets.filter((subnet: IOracleSubnet) => { return !!subnet.availabilityDomain; }); } } public isPrivateChanged() { this.numSubnetsAllowed = this.calcNumSubnetsAllowed(); } public listenerIsSslChanged(listener: IOracleListener) { if (listener.isSsl) { listener.sslConfiguration = this.oracleLoadBalancerTransformer.constructNewSSLConfiguration(); } else { listener.sslConfiguration = undefined; } } public calcNumSubnetsAllowed() { if (this.$scope.loadBalancerCmd.isPrivate) { return 1; } if (this.selectedSubnets && this.selectedSubnets.length === 1 && !this.selectedSubnets[0].availabilityDomain) { return 1; } return 2; } public getSubnetLimit() {} public removeListener(idx: number) { this.listeners.splice(idx, 1); } public addListener() { this.listeners.push(this.oracleLoadBalancerTransformer.constructNewListenerTemplate()); } public removeBackendSet(idx: number) { const backendSet = this.backendSets[idx]; this.backendSets.splice(idx, 1); this.$scope.prevBackendSetNames.splice(idx, 1); // Also clear the defaultBackendSetName field of any listeners who are using this backendSet this.listeners.forEach((lis) => { if (lis.defaultBackendSetName === backendSet.name) { lis.defaultBackendSetName = undefined; } }); } public isBackendSetRemovable(idx: number): boolean { const backendSet = this.backendSets[idx]; if (backendSet && backendSet.backends && backendSet.backends.length > 0) { return false; } let hasListener = false; this.listeners.forEach((lis) => { if (lis.defaultBackendSetName === backendSet.name) { hasListener = true; } }); return !hasListener; } public addBackendSet() { const nameSuffix: number = this.backendSets.length + 1; const name: string = 'backendSet' + nameSuffix; this.$scope.prevBackendSetNames.push(name); this.backendSets.push(this.oracleLoadBalancerTransformer.constructNewBackendSetTemplate(name)); } public backendSetNameChanged(idx: number) { const prevName = this.$scope.prevBackendSetNames && this.$scope.prevBackendSetNames[idx]; if (prevName && prevName !== this.backendSets[idx].name) { this.listeners .filter((lis) => lis.defaultBackendSetName === prevName) .forEach((lis) => { lis.defaultBackendSetName = this.backendSets[idx].name; }); } } public isCertRemovable(idx: number): boolean { const cert = this.certificates[idx]; let hasListener = false; this.listeners.forEach((lis) => { if (lis.isSsl && lis.sslConfiguration && lis.sslConfiguration.certificateName === cert.certificateName) { hasListener = true; } }); return !hasListener; } public removeCert(idx: number) { const cert = this.certificates[idx]; this.certificates.splice(idx, 1); this.$scope.prevCertNames.splice(idx, 1); // Also clear the certificateName field of any listeners who are using this certificate this.listeners.forEach((lis) => { if (lis.sslConfiguration && lis.sslConfiguration.certificateName === cert.certificateName) { lis.sslConfiguration.certificateName = undefined; } }); } public addCert() { const nameSuffix: number = this.certificates.length + 1; const name: string = 'certificate' + nameSuffix; this.$scope.prevCertNames.push(name); this.certificates.push(this.oracleLoadBalancerTransformer.constructNewCertificateTemplate(name)); } public certNameChanged(idx: number) { const prevName = this.$scope.prevCertNames && this.$scope.prevCertNames[idx]; if (prevName && prevName !== this.certificates[idx].certificateName) { this.listeners .filter((lis) => lis.sslConfiguration && lis.sslConfiguration.certificateName === prevName) .forEach((lis) => { lis.sslConfiguration.certificateName = this.certificates[idx].certificateName; }); } } public submit() { const descriptor = this.isNew ? 'Create' : 'Update'; this.$scope.taskMonitor.submit(() => { const params = { cloudProvider: 'oracle', application: this.application.name, clusterName: this.$scope.loadBalancerCmd.clusterName, resourceGroupName: this.$scope.loadBalancerCmd.clusterName, loadBalancerName: this.$scope.loadBalancerCmd.name, loadBalancerId: null as string, }; if (this.loadBalancer && this.loadBalancer.id) { params.loadBalancerId = this.loadBalancer.id; } if (this.selectedVnet) { this.$scope.loadBalancerCmd.vpcId = this.selectedVnet.id; } if (this.selectedSubnets && this.selectedSubnets.length > 0) { this.$scope.loadBalancerCmd.subnetIds = this.selectedSubnets.map((subnet: IOracleSubnet) => { return subnet.id; }); for (const subnet of this.selectedSubnets) { if (!this.$scope.loadBalancerCmd.subnetTypeMap) { this.$scope.loadBalancerCmd.subnetTypeMap = { [subnet.id]: !subnet.availabilityDomain ? 'Regional' : 'AD', }; } else { this.$scope.loadBalancerCmd.subnetTypeMap[subnet.id] = !subnet.availabilityDomain ? 'Regional' : 'AD'; } } } if (this.backendSets) { this.$scope.loadBalancerCmd.backendSets = this.backendSets.reduce( (backendSetsMap: { [name: string]: IOracleBackEndSet }, backendSet: IOracleBackEndSet) => { backendSetsMap[backendSet.name] = backendSet; return backendSetsMap; }, {}, ); } if (this.listeners) { this.$scope.loadBalancerCmd.listeners = this.listeners.reduce( (listenersMap: { [name: string]: IOracleListener }, listener: IOracleListener) => { listener.name = listener.protocol + '_' + listener.port; listenersMap[listener.name] = listener; return listenersMap; }, {}, ); } if (this.certificates) { this.$scope.loadBalancerCmd.certificates = this.certificates.reduce( (certMap: { [name: string]: IOracleListenerCertificate }, cert: IOracleListenerCertificate) => { certMap[cert.certificateName] = cert; if (!cert.isNew) { // existing certificate sends only the name certMap[cert.certificateName].publicCertificate = null; } return certMap; }, {}, ); } this.$scope.loadBalancerCmd.type = 'upsertLoadBalancer'; if (!this.$scope.loadBalancerCmd.vnet && !this.$scope.loadBalancerCmd.subnetType) { this.$scope.loadBalancerCmd.securityGroups = null; } return LoadBalancerWriter.upsertLoadBalancer(this.$scope.loadBalancerCmd, this.application, descriptor, params); }); } public cancel() { this.$uibModalInstance.dismiss(); } } export const ORACLE_LOAD_BALANCER_CREATE_CONTROLLER = 'spinnaker.oracle.loadBalancer.create.controller'; module(ORACLE_LOAD_BALANCER_CREATE_CONTROLLER, [ ANGULAR_UI_BOOTSTRAP as any, UIROUTER_ANGULARJS, ORACLE_LOAD_BALANCER_TRANSFORMER, ]).controller('oracleCreateLoadBalancerCtrl', OracleLoadBalancerController);