-
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 (#5868)
- Loading branch information
1 parent
57b1e49
commit 2f3ca8d
Showing
20 changed files
with
1,635 additions
and
3 deletions.
There are no files selected for viewing
104 changes: 104 additions & 0 deletions
104
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,104 @@ | ||
import { ILoadBalancer, ILoadBalancerDeleteCommand, ILoadBalancerUpsertCommand, ISubnet } from '@spinnaker/core'; | ||
|
||
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 | ||
} | ||
|
||
// This is created from loadBalancer/loadBalancer.states.ts | ||
export interface ILoadBalancerDetails { | ||
name: string; | ||
accountId: string; | ||
region: string; | ||
vpcId: string; | ||
} | ||
|
||
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 - | ||
* Command objects are the shape of data sent to gate. | ||
*/ | ||
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 }; | ||
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> |
155 changes: 155 additions & 0 deletions
155
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,155 @@ | ||
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.