Skip to content
This repository has been archived by the owner on Oct 20, 2021. It is now read-only.

Commit

Permalink
feat(gateway): Manage group of endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
brasseld committed Jun 11, 2018
1 parent 8538572 commit 6807762
Show file tree
Hide file tree
Showing 13 changed files with 296 additions and 110 deletions.
3 changes: 3 additions & 0 deletions docs/management-api-proxy-group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Endpoints group

Group allows to manage a pool of endpoints. The group reference may be used while applying routing policy.
44 changes: 40 additions & 4 deletions src/management/api/proxy/apiProxy.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import UserService from '../../../services/user.service';

class ApiProxyController {
private initialApi: any;
private initialDiscovery: any;

private api: any;
private groups: any;
private views: any;
Expand Down Expand Up @@ -62,6 +64,7 @@ class ApiProxyController {
this.api = _.cloneDeep(this.$scope.$parent.apiCtrl.api);
this.discovery = this.api.services && this.api.services['discovery'];
this.discovery = this.discovery || {enabled: false, configuration: {}};
this.initialDiscovery = _.cloneDeep(this.discovery);
this.tenants = resolvedTenants.data;
this.$scope.selected = [];

Expand Down Expand Up @@ -198,10 +201,12 @@ class ApiProxyController {
}).then(function (response) {
if (response) {
_(_that.$scope.selected).forEach(function (endpoint) {
_(_that.api.proxy.endpoints).forEach(function (endpoint2, index, object) {
if (endpoint2 !== undefined && endpoint2.name === endpoint.name) {
object.splice(index, 1);
}
_(_that.api.proxy.groups).forEach(function (group) {
_(group.endpoints).forEach(function (endpoint2, index, object) {
if (endpoint2 !== undefined && endpoint2.name === endpoint.name) {
object.splice(index, 1);
}
});
});
});

Expand All @@ -212,6 +217,8 @@ class ApiProxyController {

reset() {
this.api = _.cloneDeep(this.initialApi);
this.discovery = _.cloneDeep(this.initialDiscovery);

if (this.formApi) {
this.formApi.$setPristine();
this.formApi.$setUntouched();
Expand Down Expand Up @@ -301,6 +308,35 @@ class ApiProxyController {
return angular.lowercase(header).indexOf(lowercaseQuery) === 0;
};
}

createGroup() {
this.$state.go('management.apis.detail.proxy.group', {groupName: ''});
}

deleteGroup(groupname) {
var _that = this;
let that = this;
this.$mdDialog.show({
controller: 'DialogConfirmController',
controllerAs: 'ctrl',
template: require('../../../components/dialog/confirmWarning.dialog.html'),
clickOutsideToClose: true,
locals: {
title: 'Are you sure you want to delete group ' + groupname + '?',
msg: '',
confirmButton: 'Delete group'
}
}).then(function (response) {
if (response) {
_(_that.api.proxy.groups).forEach(function (group, index, object) {
if (group.name !== undefined && group.name === groupname) {
object.splice(index, 1);
that.update(that.api);
}
});
}
});
}
}

export default ApiProxyController;
4 changes: 2 additions & 2 deletions src/management/api/proxy/apis.proxy.route.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<li class="iterable-item"
ng-class='{"aui-nav-selected": apiCtrl.$state.includes("management.apis.detail.proxy.endpoints") || apiCtrl.$state.includes("management.apis.detail.proxy.endpoint") || apiCtrl.$state.includes("management.apis.detail.proxy.endpointhc") }'
ui-sref='management.apis.detail.proxy.endpoints'><a class="execute">Endpoints</a></li>
<li class="iterable-item" ui-sref-active="aui-nav-selected" ui-sref='management.apis.detail.proxy.loadbalancing'><a class="execute">Load balancing</a></li>
<li class="iterable-item" ui-sref-active="aui-nav-selected" ui-sref='management.apis.detail.proxy.failover'><a class="execute">Failover</a></li>
<li class="iterable-item"
ng-class='{"aui-nav-selected": apiCtrl.$state.includes("management.apis.detail.proxy.healthcheck") || apiCtrl.$state.includes("management.apis.detail.proxy.healthcheck.configure") || apiCtrl.$state.includes("management.apis.detail.proxy.healthcheck.log") }'
ui-sref='management.apis.detail.proxy.healthcheck.visualize'><a class="execute">Health-check</a></li>
Expand All @@ -44,4 +44,4 @@
<div flex class="gv-sub-content" ui-view></div>

</div>
</div>
</div>
22 changes: 18 additions & 4 deletions src/management/api/proxy/apis.proxy.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ function apisProxyRouterConfig($stateProvider: ng.ui.IStateProvider) {
}
}
})
.state('management.apis.detail.proxy.loadbalancing', {
url: '/loadbalancing',
template: require('./backend/loadbalancing/apiProxyLoadBalancing.html'),
.state('management.apis.detail.proxy.failover', {
url: '/failover',
template: require('./backend/failover/apiProxyFailover.html'),
controller: 'ApiProxyController',
controllerAs: 'apiProxyCtrl',
data: {
Expand Down Expand Up @@ -105,7 +105,7 @@ function apisProxyRouterConfig($stateProvider: ng.ui.IStateProvider) {
}
})
.state('management.apis.detail.proxy.endpoint', {
url: '/endpoints/:endpointName',
url: '/groups/:groupName/endpoints/:endpointName',
template: require('./backend/endpoint/endpointConfiguration.html'),
controller: 'ApiEndpointController',
controllerAs: 'endpointCtrl',
Expand All @@ -121,6 +121,20 @@ function apisProxyRouterConfig($stateProvider: ng.ui.IStateProvider) {
}
}
})
.state('management.apis.detail.proxy.group', {
url: '/groups/:groupName',
template: require('./backend/endpoint/group.html'),
controller: 'ApiEndpointGroupController',
controllerAs: 'groupCtrl',
data: {
perms: {
only: ['api-definition-r']
},
docs: {
page: 'management-api-proxy-group'
}
}
})
.state('management.apis.detail.proxy.endpointhc', {
url: '/endpoints/:endpointName/healthcheck',
template: require('./backend/healthcheck/healthcheck-configure.html'),
Expand Down
152 changes: 86 additions & 66 deletions src/management/api/proxy/backend/endpoint/apiEndpoints.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,73 +17,95 @@
-->
<h4>Endpoints</h4>
<form name="apiProxyCtrl.formApi" ng-submit="apiProxyCtrl.update(apiProxyCtrl.api)" novalidate>
<md-subheader class="md-primary" style="background-color: #fafafa">Endpoints</md-subheader>
<md-table-container>
<table md-table md-row-select="true" ng-model="selected" ng-init="order = 'name'" multiple="true">
<thead md-head md-order="order">
<tr md-row>
<th md-column md-order-by="name"><span>Name</span></th>
<th md-column md-order-by="target"><span>Target</span></th>
<th md-column md-order-by="tenant" hide-gt-xs show-gt-sm>Tenants</th>
<th md-column md-order-by="weight" md-numeric hide-gt-xs show-gt-sm><span>Weight</span></th>
<th md-column md-order-by="backup" hide-gt-xs show-gt-sm>Backup</th>
<th md-column md-order-by="healthcheck" hide-gt-xs show-gt-sm>Health-check</th>
<th md-column permission permission-only="'api-definition-u'">
<md-button class="md-icon-button" aria-label="Add endpoint" ui-sref="management.apis.detail.proxy.endpoint({endpointName: ''})">
<ng-md-icon icon="add" style="fill: rgba(0, 0, 0, 0.54);"></ng-md-icon>
<md-tooltip md-direction="left">Add new endpoint</md-tooltip>
</md-button>

<md-button class="md-icon-button" aria-label="Remove endpoint" ng-click="apiProxyCtrl.removeEndpoints($event)" ng-disabled="selected.length == 0">
<ng-md-icon icon="delete" style="fill: rgba(0, 0, 0, 0.54);" ng-show="selected.length > 0"></ng-md-icon>
<ng-md-icon icon="delete" style="fill: rgba(142, 158, 170, 0.54);" ng-show="selected.length == 0"></ng-md-icon>
<md-tooltip md-direction="left">Delete endpoint</md-tooltip>
</md-button>
</th>
</tr>
</thead>
<tbody md-body>
<tr md-row md-select="endpoint" md-auto-select="false" ng-repeat="endpoint in apiProxyCtrl.api.proxy.endpoints | orderBy:order">
<td md-cell>{{endpoint.name}}</td>
<td md-cell>{{endpoint.target}}</td>
<td md-cell hide-gt-xs show-gt-sm>{{apiProxyCtrl.getTenants(endpoint.tenants)}}</td>
<td md-cell hide-gt-xs show-gt-sm ng-click="apiProxyCtrl.editWeight($event, endpoint)" ng-class="{'md-placeholder': !endpoint.weight}">{{endpoint.weight}}</td>
<td md-cell hide-gt-xs show-gt-sm>
<ng-md-icon ng-show="endpoint.backup" icon="done" style="fill: #107F20"></ng-md-icon>
<ng-md-icon ng-show="!endpoint.backup" icon="clear" style="fill: #BE2628"></ng-md-icon>
</td>
<td md-cell hide-gt-xs show-gt-sm>
<ng-md-icon ng-show="endpoint.healthcheck === undefined || endpoint.healthcheck.enabled === true" icon="done" style="fill: #107F20"></ng-md-icon>
<ng-md-icon ng-show="endpoint.healthcheck.enabled === false" icon="clear" style="fill: #BE2628"></ng-md-icon>
</td>
<td md-cell permission permission-only="'api-definition-u'">
<md-button class="md-icon-button" aria-label="Edit endpoint" ui-sref="management.apis.detail.proxy.endpoint({endpointName: endpoint.name})">
<div class="md-padding" ng-repeat="group in apiProxyCtrl.api.proxy.groups">
<md-subheader class="md-primary" style="background-color: #fafafa">
<div layout="row">
<div flex="90">
Group: {{group.name}}
</div>
<div flex layout-align="end center">
<md-button class="md-icon-button" aria-label="Edit group" ui-sref="management.apis.detail.proxy.group({groupName: group.name})">
<ng-md-icon icon="settings" style="fill: rgba(0, 0, 0, 0.54);"></ng-md-icon>
<md-tooltip md-direction="left">Edit endpoint</md-tooltip>
<md-tooltip md-direction="left">Edit group</md-tooltip>
</md-button>
</td>
</tr>
</tbody>
</table>
</md-table-container>
<md-button class="md-icon-button" aria-label="Delete group" ng-click="apiProxyCtrl.deleteGroup(group.name)">
<ng-md-icon icon="delete" style="fill: rgba(0, 0, 0, 0.54);"></ng-md-icon>
<md-tooltip md-direction="left">Delete group</md-tooltip>
</md-button>
</div>
</div>

</md-subheader>
<md-table-container>
<table md-table md-row-select="true" ng-model="selected" ng-init="order = 'name'" multiple="true">
<thead md-head md-order="order">
<tr md-row>
<th md-column md-order-by="name"><span>Name</span></th>
<th md-column md-order-by="target"><span>Target</span></th>
<th md-column md-order-by="tenant" hide-gt-xs show-gt-sm>Tenants</th>
<th md-column md-order-by="weight" md-numeric hide-gt-xs show-gt-sm><span>Weight</span></th>
<th md-column md-order-by="backup" hide-gt-xs show-gt-sm>Backup</th>
<th md-column md-order-by="healthcheck" hide-gt-xs show-gt-sm>Health-check</th>
<th md-column permission permission-only="'api-definition-u'">
<md-button class="md-icon-button" aria-label="Add endpoint" ui-sref="management.apis.detail.proxy.endpoint({groupName: group.name, endpointName: ''})">
<ng-md-icon icon="add" style="fill: rgba(0, 0, 0, 0.54);"></ng-md-icon>
<md-tooltip md-direction="left">Add new endpoint</md-tooltip>
</md-button>

<md-content flex>
<md-content>
<md-input-container class="md-block">
<md-checkbox
ng-model="apiProxyCtrl.discovery.enabled"
aria-label="Enable endpoint discovery"
class="md-warn md-align-top-left"
flex>
Enable endpoint discovery<br/>
<span class="ipsum">
By enabling endpoint discovery, endpoints will be dynamically added or removed (without downtime).
</span>
</md-checkbox>
</md-input-container>
</md-content>
<md-button class="md-icon-button" aria-label="Delete endpoint" ng-click="apiProxyCtrl.removeEndpoints($event)" ng-disabled="selected.length == 0">
<ng-md-icon icon="delete" style="fill: rgba(0, 0, 0, 0.54);" ng-show="selected.length > 0"></ng-md-icon>
<ng-md-icon icon="delete" style="fill: rgba(142, 158, 170, 0.54);" ng-show="selected.length == 0"></ng-md-icon>
<md-tooltip md-direction="left">Delete endpoint</md-tooltip>
</md-button>
</th>
</tr>
</thead>
<tbody md-body>
<tr md-row md-select="endpoint" md-auto-select="false" ng-repeat="endpoint in group.endpoints | orderBy:order">
<td md-cell>{{endpoint.name}}</td>
<td md-cell>{{endpoint.target}}</td>
<td md-cell hide-gt-xs show-gt-sm>{{apiProxyCtrl.getTenants(endpoint.tenants)}}</td>
<td md-cell hide-gt-xs show-gt-sm ng-click="apiProxyCtrl.editWeight($event, endpoint)" ng-class="{'md-placeholder': !endpoint.weight}">{{endpoint.weight}}</td>
<td md-cell hide-gt-xs show-gt-sm>
<ng-md-icon ng-show="endpoint.backup" icon="done" style="fill: #107F20"></ng-md-icon>
<ng-md-icon ng-show="!endpoint.backup" icon="clear" style="fill: #BE2628"></ng-md-icon>
</td>
<td md-cell hide-gt-xs show-gt-sm>
<ng-md-icon ng-show="endpoint.healthcheck === undefined || endpoint.healthcheck.enabled === true" icon="done" style="fill: #107F20"></ng-md-icon>
<ng-md-icon ng-show="endpoint.healthcheck.enabled === false" icon="clear" style="fill: #BE2628"></ng-md-icon>
</td>
<td md-cell permission permission-only="'api-definition-u'">
<md-button class="md-icon-button" aria-label="Edit endpoint" ui-sref="management.apis.detail.proxy.endpoint({groupName: group.name, endpointName: endpoint.name})">
<ng-md-icon icon="settings" style="fill: rgba(0, 0, 0, 0.54);"></ng-md-icon>
<md-tooltip md-direction="left">Edit endpoint</md-tooltip>
</md-button>
</td>
</tr>
</tbody>
</table>
</md-table-container>
</div>

<md-content layout="row" layout-align="end center">
<md-button class="md-primary" permission permission-only="'api-definition-u'" ng-click="apiProxyCtrl.createGroup()">
<ng-md-icon icon="my_library_add" style="fill: rgba(0, 0, 0, 0.54);"></ng-md-icon>New group
</md-button>
</md-content>

<br>
<div class="md-padding">
<md-subheader class="md-primary" style="background-color: #fafafa">
<md-checkbox
ng-model="apiProxyCtrl.discovery.enabled"
aria-label="Enable endpoint discovery" flex>
<div ng-switch on="apiProxyCtrl.discovery.enabled">
Enable endpoint discovery
<span class="proxy-activated" ng-switch-when="true">(active)</span>
<span class="proxy-deactivated" ng-switch-when="false">(not active)</span>
<span class="proxy-deactivated" ng-switch-default>(not active)</span>
</div>
<div class="hints">By enabling endpoint discovery, endpoints will be dynamically added or removed (without downtime).</div>
</md-checkbox>
</md-subheader>

<div ng-show="apiProxyCtrl.discovery.enabled">
<md-subheader class="md-primary" style="background-color: #fafafa">Consul.io configuration</md-subheader>
Expand Down Expand Up @@ -114,6 +136,7 @@ <h4>Endpoints</h4>
</md-input-container>
</md-content>
</div>
</div>

<div class="md-actions gravitee-api-save-button" layout="row">
<md-button permission permission-only="'api-definition-u'" class="md-raised" type="submit" ng-disabled="apiProxyCtrl.formApi.$invalid || apiProxyCtrl.formApi.$pristine">
Expand All @@ -122,8 +145,5 @@ <h4>Endpoints</h4>
<md-button permission permission-only="'api-definition-u'" class="md-raised md-primary" type="button" ng-click="apiProxyCtrl.reset()" ng-disabled="apiProxyCtrl.formApi.$pristine">
Reset
</md-button>
<md-button permission permission-only="'api-definition-d'" class="md-raised md-warn pull-right" type="button" ng-click="apiProxyCtrl.delete(apiProxyCtrl.api.id)" ng-disabled="apiProxyCtrl.api.state === 'started'">
Delete
</md-button>
</div>
</form>
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import _ = require('lodash');

class ApiEndpointController {

private group: any;
private api: any;
private endpoint: any;
private initialEndpoints: any;
Expand All @@ -37,8 +38,9 @@ class ApiEndpointController {
this.api = this.$scope.$parent.apiCtrl.api;
this.tenants = resolvedTenants.data;

this.endpoint = _.find(this.api.proxy.endpoints, { 'name': $stateParams.endpointName});
this.initialEndpoints = _.cloneDeep(this.api.proxy.endpoints);
this.group = _.find(this.api.proxy.groups, { 'name': $stateParams.groupName});
this.endpoint = _.find(this.group.endpoints, { 'name': $stateParams.endpointName});
this.initialEndpoints = _.cloneDeep(this.group.endpoints);

// Creation mode
if (!this.endpoint) {
Expand Down Expand Up @@ -76,15 +78,18 @@ class ApiEndpointController {
}

update(api) {
if (!_.includes(api.proxy.endpoints, this.endpoint)) {
api.proxy.endpoints.push(this.endpoint);
let group: any = _.find(this.api.proxy.groups, { 'name': this.$stateParams.groupName});

if (!_.includes(group.endpoints, this.endpoint)) {
group.endpoints = group.endpoints || [];
group.endpoints.push(this.endpoint);
}

this.ApiService.update(api).then((updatedApi) => {
this.api = updatedApi.data;
this.api.etag = updatedApi.headers('etag');
this.onApiUpdate();
this.initialEndpoints = _.cloneDeep(api.proxy.endpoints);
this.initialEndpoints = _.cloneDeep(group.endpoints);
});
}

Expand All @@ -100,7 +105,8 @@ class ApiEndpointController {
}

backToEndpointsConfiguration() {
this.api.proxy.endpoints = _.cloneDeep(this.initialEndpoints);
let group: any = _.find(this.api.proxy.groups, { 'name': this.$stateParams.groupName});
group.endpoints = _.cloneDeep(this.initialEndpoints);
this.$state.go('management.apis.detail.proxy.endpoints');
}

Expand Down
Loading

0 comments on commit 6807762

Please sign in to comment.