Skip to content

Commit

Permalink
feat(gce): select external ip for http(s) load balancers
Browse files Browse the repository at this point in the history
  • Loading branch information
danielpeach committed Apr 4, 2017
1 parent 1aeb53b commit 0fa0338
Show file tree
Hide file tree
Showing 18 changed files with 202 additions and 77 deletions.
23 changes: 12 additions & 11 deletions app/scripts/modules/core/help/helpContents.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 12 additions & 13 deletions app/scripts/modules/google/address/address.reader.ts
Expand Up @@ -12,18 +12,18 @@ interface IAddressSearchResults {
}

export interface IGceAddress {
account: string;
account?: string;
address: string;
creationTimestamp: string;
description: string;
id: number;
kind: string;
labelFingerprint: string;
name: string;
networkTier: string;
region: string;
selfLink: string;
status: string;
creationTimestamp?: string;
description?: string;
id?: number;
kind?: string;
labelFingerprint?: string;
name?: string;
networkTier?: string;
region?: string;
selfLink?: string;
status?: string;
}

class GceAddressReader {
Expand All @@ -44,8 +44,7 @@ class GceAddressReader {
.map(result => {
let address = JSON.parse(result.address) as IGceAddress;
address.account = result.account;
// An address's selfLink ends with its region.
address.region = address.selfLink.split('/').pop();
address.region = result.region;
return address;
});
} else {
Expand Down
26 changes: 17 additions & 9 deletions app/scripts/modules/google/cache/cacheRefresh.component.html
@@ -1,9 +1,17 @@
<p>
<span ng-if="$ctrl.refreshing"><span class="small glyphicon glyphicon-refresh glyphicon-spinning"></span></span>
{{::$ctrl.capitalizedKey}}
<span ng-if="!$ctrl.refreshing">last refreshed {{ $ctrl.getRefreshTime() | timestamp }}</span>
<span ng-if="$ctrl.refreshing"> refreshing...</span>
</p>
<p>If you're not finding a {{::$ctrl.depluralizedKey}} that was recently added,
<a href ng-click="$ctrl.refresh()">click here</a> to refresh the list.
</p>
<div ng-if="!$ctrl.renderCompact">
<p>
<span ng-if="$ctrl.refreshing"><span class="small glyphicon glyphicon-refresh glyphicon-spinning" ></span></span>
{{::$ctrl.capitalizedKey}}
<span ng-if="!$ctrl.refreshing">last refreshed {{ $ctrl.getRefreshTime() | timestamp }}</span>
<span ng-if="$ctrl.refreshing"> refreshing...</span>
</p>
<p>If you're not finding a {{::$ctrl.depluralizedKey}} that was recently added,
<a href ng-click="$ctrl.refresh()">click here</a> to refresh the list.
</p>
</div>
<div ng-if="$ctrl.renderCompact">
<a href uib-tooltip-template="$ctrl.tooltipTemplate">
<span class="small glyphicon glyphicon-refresh" ng-click="$ctrl.refresh()"
ng-class="{'glyphicon-spinning': $ctrl.refreshing}"></span>
</a>
</div>
32 changes: 0 additions & 32 deletions app/scripts/modules/google/cache/cacheRefresh.component.js

This file was deleted.

54 changes: 54 additions & 0 deletions app/scripts/modules/google/cache/cacheRefresh.component.ts
@@ -0,0 +1,54 @@
import {module, IComponentOptions, IComponentController} from 'angular';
import {INFRASTRUCTURE_CACHE_SERVICE, InfrastructureCacheService} from 'core/cache/infrastructureCaches.service';
import {CACHE_INITIALIZER_SERVICE, CacheInitializerService} from 'core/cache/cacheInitializer.service';

class GceCacheRefreshCtrl implements IComponentController {
public capitalizedKey: string;
public depluralizedKey: string;
public renderCompact: boolean;
public refreshing = false;
public tooltipTemplate = require('./cacheRefreshTooltip.html');
private onRefresh: Function;
private cacheKey: string;
private cacheKeyAlias: string;

static get $inject() { return ['cacheInitializer', 'infrastructureCaches']; }

constructor(private cacheInitializer: CacheInitializerService,
private infrastructureCaches: InfrastructureCacheService) {}

public $onInit(): void {
let cacheKeyAlias = this.cacheKeyAlias || this.cacheKey;
this.capitalizedKey = cacheKeyAlias[0].toUpperCase() + cacheKeyAlias.substring(1);
this.depluralizedKey = cacheKeyAlias.substring(0, cacheKeyAlias.length - 1);
}

public getRefreshTime(): number {
return this.infrastructureCaches.get(this.cacheKey).getStats().ageMax;
}

public refresh(): void {
this.refreshing = true;
this.cacheInitializer.refreshCache(this.cacheKey)
.then(() => this.onRefresh())
.then(() => { this.refreshing = false; });
};
}

class GceCacheRefresh implements IComponentOptions {
public bindings: any = {
onRefresh: '&',
cacheKey: '@',
cacheKeyAlias: '@',
renderCompact: '<'
};
public controller: any = GceCacheRefreshCtrl;
public templateUrl = require('./cacheRefresh.component.html');
}

export const GCE_CACHE_REFRESH = 'spinnaker.gce.cacheRefresh.component';
module(GCE_CACHE_REFRESH, [
CACHE_INITIALIZER_SERVICE,
INFRASTRUCTURE_CACHE_SERVICE
]).component('gceCacheRefresh', new GceCacheRefresh());

3 changes: 3 additions & 0 deletions app/scripts/modules/google/cache/cacheRefreshTooltip.html
@@ -0,0 +1,3 @@
<p ng-if="$ctrl.refreshing">{{$ctrl.capitalizedKey}} data is <strong>refreshing</strong></p>
<p ng-if="!$ctrl.refreshing">(click <span class="small glyphicon glyphicon-refresh"></span> to refresh)</p>
<p>Last refresh: {{$ctrl.getRefreshTime() | timestamp }}</p>
2 changes: 2 additions & 0 deletions app/scripts/modules/google/domain/loadBalancer.ts
Expand Up @@ -16,6 +16,7 @@ export interface IGceHttpLoadBalancer extends IGceLoadBalancer {
defaultService: IGceBackendService;
detail: string;
hostRules: IGceHostRule;
ipAddress: string;
listeners: IGceListener[];
loadBalancerType: 'HTTP';
provider: 'gce';
Expand All @@ -41,4 +42,5 @@ export interface IGceListener {
certificate: string;
name: string;
port: string;
ipAddress: string;
}
@@ -0,0 +1,47 @@
import {module, IComponentOptions, IComponentController} from 'angular';
import {IGceAddress} from 'google/address/address.reader';

class GceAddressSelectorCtrl implements IComponentController {
public selectedAddress: IGceAddress;
public addressList: IGceAddress[];
public account: string;
// The IP address string is the only piece that we can expect a parent resource to keep track of.
// We'll try to match this IP to a full address map.
private initialIpAddress: string;

public $onInit(): void {
this.selectedAddress = this.addressList.find(address => address.address === this.initialIpAddress);
if (!this.selectedAddress) {
this.selectedAddress = {address: this.initialIpAddress, account: this.account};
}
}
}

class GceAddressSelector implements IComponentOptions {
public bindings: any = {
initialIpAddress: '<',
addressList: '<',
readOnly: '<',
onAddressSelect: '&',
account: '<',
};
public template = `
<ui-select on-select="$ctrl.onAddressSelect({address: $ctrl.selectedAddress})"
ng-disabled="$ctrl.readOnly"
ng-model="$ctrl.selectedAddress"
class="form-control input-sm">
<ui-select-match allow-clear>
{{$ctrl.selectedAddress.address}} <span ng-if="$ctrl.selectedAddress.name">({{$ctrl.selectedAddress.name}})</span>
</ui-select-match>
<ui-select-choices repeat="address in $ctrl.addressList | filter: {name: $select.search, account: $ctrl.account}">
<span>
{{address.address}} <span ng-if="address.name">({{address.name}})</span> <br>
</span>
</ui-select-choices>
</ui-select>`;
public controller: any = GceAddressSelectorCtrl;
}

export const GCE_ADDRESS_SELECTOR = 'spinnaker.gce.addressSelector.component';
module(GCE_ADDRESS_SELECTOR, [])
.component('gceAddressSelector', new GceAddressSelector());
Expand Up @@ -8,6 +8,7 @@ import {LOAD_BALANCER_READ_SERVICE} from 'core/loadBalancer/loadBalancer.read.se
import {GCEProviderSettings} from '../../../gce.settings';
import {GCE_HTTP_LOAD_BALANCER_UTILS} from 'google/loadBalancer/httpLoadBalancerUtils.service';
import {GCE_CERTIFICATE_READER} from 'google/certificate/certificate.reader';
import {GCE_ADDRESS_READER} from 'google/address/address.reader';

let angular = require('angular');

Expand All @@ -17,6 +18,7 @@ module.exports = angular.module('spinnaker.deck.gce.httpLoadBalancer.backing.ser
ACCOUNT_SERVICE,
LOAD_BALANCER_READ_SERVICE,
GCE_HTTP_LOAD_BALANCER_UTILS,
GCE_ADDRESS_READER,
require('../../../httpHealthCheck/httpHealthCheck.reader.js'),
require('./transformer.service.js'),
])
Expand All @@ -26,7 +28,8 @@ module.exports = angular.module('spinnaker.deck.gce.httpLoadBalancer.backing.ser
gceCertificateReader,
gceHttpHealthCheckReader,
gceHttpLoadBalancerTransformer,
loadBalancerReader) {
loadBalancerReader,
gceAddressReader) {

function buildCommand ({ originalLoadBalancer, isNew }) {
originalLoadBalancer = _.cloneDeep(originalLoadBalancer);
Expand All @@ -48,6 +51,7 @@ module.exports = angular.module('spinnaker.deck.gce.httpLoadBalancer.backing.ser
removeUnusedBackendServices,
getUnusedHealthChecks,
removeUnusedHealthChecks,
onAddressRefresh,
};
});
}
Expand All @@ -59,6 +63,7 @@ module.exports = angular.module('spinnaker.deck.gce.httpLoadBalancer.backing.ser
certificates: getCertificates(),
loadBalancerMap: getLoadBalancerMap(),
accounts: getAccounts(),
addresses: gceAddressReader.listAddresses('global'),
}).then((backingData) => {
let loadBalancer = buildLoadBalancer(isNew, originalLoadBalancer, backingData);

Expand Down Expand Up @@ -322,5 +327,11 @@ module.exports = angular.module('spinnaker.deck.gce.httpLoadBalancer.backing.ser
command.loadBalancer.defaultService = null;
}

function onAddressRefresh(command) {
gceAddressReader.listAddresses('global').then(addresses => {
command.backingData.addresses = addresses;
});
}

return { buildCommand };
});
Expand Up @@ -5,6 +5,7 @@ let angular = require('angular');
import {HealthCheckTemplate, BackendServiceTemplate, HostRuleTemplate, ListenerTemplate} from './templates';
import {V2_MODAL_WIZARD_SERVICE} from 'core/modal/wizard/v2modalWizard.service';
import {TASK_MONITOR_BUILDER} from 'core/task/monitor/taskMonitor.builder';
import {GCE_CACHE_REFRESH} from 'google/cache/cacheRefresh.component';

require('./httpLoadBalancerWizard.component.less');

Expand All @@ -13,7 +14,7 @@ module.exports = angular.module('spinnaker.deck.gce.loadBalancer.createHttp.cont
require('angular-ui-router'),
require('./backendService/backendService.component.js'),
require('./basicSettings/basicSettings.component.js'),
require('google/cache/cacheRefresh.component.js'),
GCE_CACHE_REFRESH,
require('core/modal/wizard/wizardSubFormValidation.service.js'),
V2_MODAL_WIZARD_SERVICE,
TASK_MONITOR_BUILDER,
Expand Down
Expand Up @@ -4,7 +4,7 @@
position: absolute;
}

help-field[key="gce.httpLoadBalancer.certificate"] {
help-field.help-field-absolute {
span {
position: absolute;
top: 7px;
Expand Down
Expand Up @@ -70,7 +70,7 @@
</div>
<div ng-if="$ctrl.isHttps($ctrl.listener.port)">
<div class="col-md-2 sm-label-right">Certificate
<help-field key="gce.httpLoadBalancer.certificate"></help-field>
<help-field key="gce.httpLoadBalancer.certificate" class="help-field-absolute"></help-field>
</div>
<div class="col-md-3">
<ui-select ng-model="$ctrl.listener.certificate"
Expand All @@ -84,6 +84,30 @@
</ui-select-choices>
</ui-select>
</div>
<div class="col-md-1" style="padding-left: 0; margin-top: 4px;">
<gce-cache-refresh cache-key="certificates"
render-compact="true"
on-refresh="$ctrl.command.onCertificateRefresh($ctrl.command)"></gce-cache-refresh>
</div>
</div>
</div>

<div class="form-group">
<div class="col-md-2 sm-label-right">External IP
<help-field key="gce.httpLoadBalancer.externalIP" class="help-field-absolute"></help-field>
</div>
<div class="col-md-5">
<gce-address-selector address-list="$ctrl.command.backingData.addresses"
read-only="$ctrl.listener.created"
account="$ctrl.command.loadBalancer.credentials"
initial-ip-address="$ctrl.listener.ipAddress"
on-address-select="$ctrl.onAddressSelect(address)"></gce-address-selector>
</div>
<div class="col-md-1" style="padding-left: 0; margin-top: 4px;">
<gce-cache-refresh ng-if="!$ctrl.listener.created"
cache-key="addresses"
render-compact="true"
on-refresh="$ctrl.command.onAddressRefresh($ctrl.command)"></gce-cache-refresh>
</div>
</div>

Expand Down

0 comments on commit 0fa0338

Please sign in to comment.