-
Notifications
You must be signed in to change notification settings - Fork 900
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(provider/oracle): create/delete LoadBalancer
- Loading branch information
Showing
20 changed files
with
1,579 additions
and
3 deletions.
There are no files selected for viewing
99 changes: 99 additions & 0 deletions
99
app/scripts/modules/oracle/src/domain/IOracleLoadBalancer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { ILoadBalancer, ILoadBalancerDeleteCommand, ILoadBalancerUpsertCommand } from '@spinnaker/core'; | ||
import { ISubnet } from '../../../core/src/domain'; | ||
|
||
export type ListenerProtocol = 'HTTP' | 'HTTPS' | 'TCP' | 'SSL'; | ||
export enum LoadBalancingPolicy { | ||
ROUND_ROBIN = 'ROUND_ROBIN', | ||
IP_HASH = 'IP_HASH', | ||
LEAST_CONNECTIONS = 'LEAST_CONNECTIONS', | ||
} | ||
|
||
export interface IOracleSubnet extends ISubnet { | ||
id: string; | ||
name: string; | ||
availabilityDomain: string; | ||
securityListIds: string[]; | ||
vcnId: string; | ||
} | ||
|
||
export interface IOracleLoadBalancer extends ILoadBalancer { | ||
shape: string; // required | ||
isPrivate: boolean; // required | ||
subnets: IOracleSubnet[]; // required 1 for private LB, 2 for public LB | ||
certificates: IOracleListenerCertificate[]; | ||
listeners?: { [name: string]: IOracleListener }; // not required to create LB, but useless without it | ||
hostnames?: IOracleHostname[]; | ||
backendSets?: { [name: string]: IOracleBackEndSet }; // not required to create LB, but useless without it | ||
freeformTags?: { [tagName: string]: string }; | ||
id?: string; // not required to create LB | ||
// TODO support path route sets | ||
} | ||
|
||
export interface IOracleListener { | ||
name: string; | ||
protocol: ListenerProtocol; | ||
port: number; | ||
defaultBackendSetName: string; | ||
isSsl: boolean; | ||
sslConfiguration?: IOracleListenerSSLConfiguration; | ||
hostnames?: IOracleHostname[]; | ||
// TODO support pathRouteSets | ||
} | ||
|
||
export interface IOracleListenerSSLConfiguration { | ||
certificateName: string; | ||
verifyDepth: number; | ||
verifyPeerCertificates: boolean; | ||
} | ||
|
||
export interface IOracleHostname { | ||
name: string; | ||
hostname: string; | ||
} | ||
|
||
export interface IOracleBackEndSet { | ||
name: string; | ||
policy: LoadBalancingPolicy; | ||
healthChecker: IOracleBackendSetHealthCheck; | ||
// TODO desagar sessionPersistenceConfiguration?: IOracleLoadBalancerSessionPersistenceConfiguration; | ||
} | ||
|
||
export interface IOracleListenerCertificate { | ||
certificateName: string; | ||
publicCertificate: string; | ||
caCertificate: string; | ||
privateKey: string; | ||
passphrase: string; | ||
} | ||
|
||
export interface IOracleBackendSetHealthCheck { | ||
urlPath: string; // required | ||
protocol: 'HTTP' | 'TCP'; | ||
port: number; | ||
intervalMillis?: number; | ||
timeoutMillis?: number; | ||
retries?: number; | ||
returnCode?: number; | ||
responseBodyRegex?: string; | ||
} | ||
|
||
/** | ||
* IOracleLoadBalancerUpsertCommand is nearly identical to IOracleLoadBalancer - this object seems | ||
* to be used for sending info to the back end from the UI. | ||
*/ | ||
export interface IOracleLoadBalancerUpsertCommand extends ILoadBalancerUpsertCommand { | ||
shape: string; // required | ||
isPrivate: boolean; // required | ||
subnetIds: string[]; // required 1 for private LB, 2 for public LB | ||
listeners?: { [name: string]: IOracleListener }; // not required to create LB, but useless without it | ||
hostnames?: IOracleHostname[]; | ||
backendSets?: { [name: string]: IOracleBackEndSet }; // not required to create LB, but useless without it | ||
freeformTags?: { [tagName: string]: string }; | ||
loadBalancerType?: string; // is this needed because it is there in ILoadBalancer but not ILoadBalancerUpsertCommand?? | ||
securityGroups: string[]; // is this needed because it is there in ILoadBalancer but not ILoadBalancerUpsertCommand?? | ||
vpcId: string; | ||
} | ||
|
||
export interface IOracleLoadBalancerDeleteCommand extends ILoadBalancerDeleteCommand { | ||
loadBalancerId: string; | ||
} |
51 changes: 51 additions & 0 deletions
51
app/scripts/modules/oracle/src/loadBalancer/configure/backendSets.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<div class="container-fluid form-horizontal"> | ||
<div class="form-group"> | ||
<div class="col-md-12"> | ||
<table class="table table-condensed packed"> | ||
<thead> | ||
<tr> | ||
<th>Name</th> | ||
<th>Policy</th> | ||
<th>Health Check Protocol</th> | ||
<th>Health Check Port</th> | ||
<th>Health Check Path</th> | ||
<!-- TODO other nonrequired health check fields - do we need another popup for health check? --> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr ng-repeat="backendSet in ctrl.backendSets"> | ||
<td> | ||
<input class="form-control input-sm" ng-model="backendSet.name" required | ||
ng-focus="prevBackendSetNames[$index] = backendSet.name" | ||
ng-blur="ctrl.backendSetNameChanged($index)"/> | ||
</td> | ||
<td> | ||
<select class="form-control input-sm" ng-model="backendSet.policy" ng-options="policy for policy in ctrl.loadBalancingPolicies"></select> | ||
</td> | ||
<td> | ||
<input class="form-control input-sm" ng-model="backendSet.healthChecker.protocol" required/> | ||
</td> | ||
<td> | ||
<input class="form-control input-sm" ng-model="backendSet.healthChecker.port" required/> | ||
</td> | ||
<td> | ||
<input class="form-control input-sm" ng-model="backendSet.healthChecker.urlPath" required/> | ||
</td> | ||
<td><a href class="sm-label" ng-click="ctrl.removeBackendSet($index)"><span | ||
class="glyphicon glyphicon-trash"></span></a></td> | ||
</tr> | ||
</tbody> | ||
<tfoot> | ||
<tr> | ||
<td colspan="5"> | ||
<button class="add-new col-md-12" ng-click="ctrl.addBackendSet()"><span class="glyphicon glyphicon-plus-sign"></span> | ||
Add Backend Set | ||
</button> | ||
</td> | ||
</tr> | ||
</tfoot> | ||
</table> | ||
|
||
</div> | ||
</div> | ||
</div> |
54 changes: 54 additions & 0 deletions
54
app/scripts/modules/oracle/src/loadBalancer/configure/certificates.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<div class="container-fluid form-horizontal"> | ||
<div class="form-group"> | ||
<div class="col-md-12"> | ||
<table class="table table-condensed packed"> | ||
<thead> | ||
<tr> | ||
<th>Name</th> | ||
<th>Certificate</th> | ||
<th>CA Cert</th> | ||
<th>Private Key</th> | ||
<th>Passphrase</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr ng-repeat="cert in ctrl.certificates"> | ||
<td> | ||
<input class="form-control input-sm" ng-model="cert.certificateName" required | ||
ng-focus="prevCertNames[$index] = cert.name" | ||
ng-blur="ctrl.certNameChanged($index)"/> | ||
</td> | ||
<td> | ||
<textarea ng-model="cert.publicCertificate" required | ||
class="form-control input-sm"></textarea> | ||
</td> | ||
<td> | ||
<textarea ng-model="cert.caCertificate" | ||
class="form-control input-sm"></textarea> | ||
</td> | ||
<td> | ||
<textarea ng-model="cert.privateKey" required | ||
class="form-control input-sm"></textarea> | ||
</td> | ||
<td> | ||
<textarea ng-model="cert.passphrase" | ||
class="form-control input-sm"></textarea> | ||
</td> | ||
<td><a href class="sm-label" ng-click="ctrl.removeCert($index)"><span | ||
class="glyphicon glyphicon-trash"></span></a></td> | ||
</tr> | ||
</tbody> | ||
<tfoot> | ||
<tr> | ||
<td colspan="5"> | ||
<button class="add-new col-md-12" ng-click="ctrl.addCert()"><span class="glyphicon glyphicon-plus-sign"></span> | ||
Add Certificate | ||
</button> | ||
</td> | ||
</tr> | ||
</tfoot> | ||
</table> | ||
|
||
</div> | ||
</div> | ||
</div> |
157 changes: 157 additions & 0 deletions
157
app/scripts/modules/oracle/src/loadBalancer/configure/createLoadBalancer.controller.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
'use strict'; | ||
|
||
import { IControllerService, IRootScopeService, IScope, mock, noop } from 'angular'; | ||
import { StateService } from '@uirouter/core'; | ||
|
||
import { API, APPLICATION_MODEL_BUILDER } from '@spinnaker/core'; | ||
import { ORACLE_LOAD_BALANCER_CREATE_CONTROLLER, OracleLoadBalancerController } from './createLoadBalancer.controller'; | ||
import { ApplicationModelBuilder } from 'core'; | ||
import { | ||
IOracleLoadBalancer, | ||
IOracleLoadBalancerUpsertCommand, | ||
LoadBalancingPolicy, | ||
} from 'oracle/domain/IOracleLoadBalancer'; | ||
import { OracleProviderSettings } from 'oracle/oracle.settings'; | ||
|
||
describe('Controller: oracleCreateLoadBalancerCtrl', function() { | ||
let $http: ng.IHttpBackendService; | ||
let controller: OracleLoadBalancerController; | ||
const loadBalancer: IOracleLoadBalancer = null; | ||
let $scope: IScope; | ||
let $state: StateService; | ||
|
||
beforeEach(mock.module(APPLICATION_MODEL_BUILDER, ORACLE_LOAD_BALANCER_CREATE_CONTROLLER)); | ||
|
||
// Initialize the controller and a mock scope | ||
beforeEach( | ||
mock.inject( | ||
( | ||
$controller: IControllerService, | ||
$rootScope: IRootScopeService, | ||
_$state_: StateService, | ||
applicationModelBuilder: ApplicationModelBuilder, | ||
) => { | ||
$scope = $rootScope.$new(); | ||
$state = _$state_; | ||
const application = applicationModelBuilder.createApplicationForTests('app', { | ||
key: 'loadBalancers', | ||
lazy: true, | ||
}); | ||
|
||
const isNew = true; | ||
controller = $controller(OracleLoadBalancerController, { | ||
$scope, | ||
$uibModalInstance: { dismiss: noop, result: { then: noop } }, | ||
loadBalancer, | ||
application, | ||
$state, | ||
isNew, | ||
}); | ||
controller.addBackendSet(); | ||
controller.addListener(); | ||
controller.addCert(); | ||
|
||
controller.listeners[0].defaultBackendSetName = controller.backendSets[0].name; | ||
}, | ||
), | ||
); | ||
|
||
beforeEach( | ||
mock.inject(function($httpBackend: ng.IHttpBackendService) { | ||
// Set up the mock http service responses | ||
$http = $httpBackend; | ||
}), | ||
); | ||
|
||
function initListenerSslConfig() { | ||
controller.listeners[0].isSsl = true; | ||
controller.listenerIsSslChanged(controller.listeners[0]); | ||
} | ||
|
||
it('should have an instantiated controller', function() { | ||
expect(controller).toBeDefined(); | ||
}); | ||
|
||
it('correctly creates a default loadbalancer', function() { | ||
const lb: IOracleLoadBalancerUpsertCommand = $scope.loadBalancerCmd; | ||
expect(lb.cloudProvider).toEqual('oracle'); | ||
expect(lb.credentials).toEqual(OracleProviderSettings.defaults.account); | ||
expect(lb.region).toEqual(OracleProviderSettings.defaults.region); | ||
expect(lb.isPrivate).toEqual(false); | ||
expect($scope.existingLoadBalancerNames).toEqual(undefined); | ||
}); | ||
|
||
it('correctly creates default listener', function() { | ||
expect(controller.listeners).toBeDefined(); | ||
expect(controller.listeners.length).toEqual(1); | ||
expect(controller.listeners[0].name).toEqual('HTTP_80'); | ||
expect(controller.listeners[0].protocol).toEqual('HTTP'); | ||
expect(controller.listeners[0].port).toEqual(80); | ||
}); | ||
|
||
it('correctly creates default subnet', function() { | ||
expect(controller.backendSets).toBeDefined(); | ||
expect(controller.backendSets.length).toEqual(1); | ||
expect(controller.backendSets[0].name).toEqual('backendSet1'); | ||
expect(controller.backendSets[0].policy).toEqual(LoadBalancingPolicy.ROUND_ROBIN); | ||
expect(controller.backendSets[0].healthChecker.protocol).toEqual('HTTP'); | ||
expect(controller.backendSets[0].healthChecker.port).toEqual(80); | ||
expect(controller.backendSets[0].healthChecker.urlPath).toEqual('/healthZ'); | ||
}); | ||
|
||
it('correctly creates default certificate', function() { | ||
expect(controller.certificates).toBeDefined(); | ||
expect(controller.certificates.length).toEqual(1); | ||
expect(controller.certificates[0].certificateName).toEqual('certificate1'); | ||
}); | ||
|
||
it('changed backend set name updates listener', function() { | ||
expect(controller.listeners[0].defaultBackendSetName).toEqual('backendSet1'); | ||
controller.backendSets[0].name = 'UpdatedBackendSetName'; | ||
controller.backendSetNameChanged(0); | ||
expect(controller.listeners[0].defaultBackendSetName).toEqual('UpdatedBackendSetName'); | ||
}); | ||
|
||
it('remove backend set updates listener', function() { | ||
controller.removeBackendSet(0); | ||
expect(controller.listeners[0].defaultBackendSetName).not.toBeDefined(); | ||
}); | ||
|
||
it('sslConfiguration created on listener', function() { | ||
expect(controller.listeners[0].sslConfiguration).not.toBeDefined(); | ||
initListenerSslConfig(); | ||
expect(controller.listeners[0].sslConfiguration).toBeDefined(); | ||
}); | ||
|
||
it('sslConfiguration removed on listener when isSsl turned off', function() { | ||
initListenerSslConfig(); | ||
expect(controller.listeners[0].sslConfiguration).toBeDefined(); | ||
controller.listeners[0].isSsl = false; | ||
controller.listenerIsSslChanged(controller.listeners[0]); | ||
expect(controller.listeners[0].sslConfiguration).not.toBeDefined(); | ||
}); | ||
|
||
it('changed certificate name updates listener', function() { | ||
initListenerSslConfig(); | ||
controller.listeners[0].sslConfiguration.certificateName = controller.certificates[0].certificateName; | ||
expect(controller.listeners[0].sslConfiguration.certificateName).toEqual('certificate1'); | ||
controller.certificates[0].certificateName = 'someOtherCertName'; | ||
controller.certNameChanged(0); | ||
expect(controller.listeners[0].sslConfiguration.certificateName).toEqual('someOtherCertName'); | ||
}); | ||
|
||
it('remove certificate updates listener', function() { | ||
initListenerSslConfig(); | ||
controller.listeners[0].sslConfiguration.certificateName = controller.certificates[0].certificateName; | ||
controller.removeCert(0); | ||
expect(controller.listeners[0].sslConfiguration.certificateName).not.toBeDefined(); | ||
}); | ||
|
||
it('makes the expected REST calls for data for a new loadbalancer', function() { | ||
$http.expect('GET', API.baseUrl + '/networks/oracle').respond([]); | ||
$http.expect('GET', API.baseUrl + '/subnets/oracle').respond([]); | ||
$http.flush(); | ||
$http.verifyNoOutstandingExpectation(); | ||
$http.verifyNoOutstandingRequest(); | ||
}); | ||
}); |
Oops, something went wrong.