mirror of https://github.com/rancher/ui.git
LoadBalancer WIP
This commit is contained in:
parent
6c7134627a
commit
818991523a
|
|
@ -27,18 +27,8 @@
|
|||
</div>
|
||||
|
||||
<div class="clearfix no-resource-action-hover">
|
||||
{{#each item in model.arrangedTargets}}
|
||||
{{#if item.ipAddress}}
|
||||
<p>IP: {{item.ipAddress}}</p>
|
||||
{{else}}
|
||||
{{#if item.instance}}
|
||||
{{#with item.instance as c controller="container"}}
|
||||
<p>Container: {{c.displayName}}</p>
|
||||
{{/with}}
|
||||
{{else}}
|
||||
<p>Instance?: {{item.instanceId}}</p>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#each item in model.arrangedTargets itemController="loadbalancertarget"}}
|
||||
{{loadbalancertarget-subpod model=item}}
|
||||
{{/each}}
|
||||
{{#if showAdd}}
|
||||
{{add-subpod action="newTarget" label="Add Target"}}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import Ember from 'ember';
|
||||
import HoverActions from 'ui/mixins/hover-actions';
|
||||
|
||||
|
||||
export default Ember.Component.extend(HoverActions, {
|
||||
model: null,
|
||||
classNames: ['subpod','resource-action-hover'],
|
||||
|
||||
click: function() {
|
||||
// For touch devices, show actions on a click anywhere in the component
|
||||
if ( $('BODY').hasClass('touch') )
|
||||
{
|
||||
this.send('showActions');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
{{resource-actions-menu model=model choices=model.availableActions}}
|
||||
|
||||
<div class="subpod-name">
|
||||
{{#if model.isIp}}
|
||||
<i class="ss-record text-success"></i>
|
||||
{{model.ipAddress}}
|
||||
{{else}}
|
||||
{{#if model.instance}}
|
||||
{{#with model.instance as container controller="container"}}
|
||||
<i {{bind-attr class="container.stateIcon container.stateColor" tooltip=container.displayState}}></i>
|
||||
{{#link-to "container" model.instanceId}}
|
||||
{{container.displayName}}
|
||||
{{/link-to}}
|
||||
{{/with}}
|
||||
{{else}}
|
||||
<i class="ss-record-text-success" style="visibility: hidden"></i>
|
||||
<span class="text-muted">Loading...</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if model.showTransitioningMessage}}
|
||||
<div {{bind-attr class=":subpod-detail :clip model.isError:text-danger"}}>
|
||||
{{model.transitioningMessage}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="subpod-detail">
|
||||
{{#if model.isIp}}
|
||||
IP Address
|
||||
{{else}}
|
||||
Container
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if model.isTransitioning}}
|
||||
<div class="progress progress-striped active">
|
||||
<div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" {{bind-attr aria-valuenow=model.displayProgress style=model.progressStyle}}>
|
||||
<span class="sr-only">{{model.displayProgress}}% Complete</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
@ -1,137 +1,5 @@
|
|||
<section class="text-right">
|
||||
<button {{action "editConfig"}} class="btn btn-sm btn-primary">Edit Configuration</button>
|
||||
</section>
|
||||
<div class="well section">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<h4>Listeners ({{listeners.length}})</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="grid fixed" style="margin-bottom: 0;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="120">State</th>
|
||||
<th>Source</th>
|
||||
<th width="30"></th>
|
||||
<th>Target</th>
|
||||
<th class="text-right">Algorithm</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each listener in listeners itemController="loadbalancerlistener"}}
|
||||
<tr>
|
||||
<td>
|
||||
<span {{bind-attr class=":badge :state listener.stateBackground"}}>
|
||||
{{listener.displayState}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{{listener.sourcePort}}/{{listener.sourceProtocol}}
|
||||
</td>
|
||||
<td>
|
||||
<i class="ss-arrow-right"></i>
|
||||
</td>
|
||||
<td>
|
||||
{{listener.targetPort}}/{{listener.targetProtocol}}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{listener.algorithm}}
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr><td colspan="4" class="text-center text-muted">This host does not have any containers yet.</td></tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="well section">
|
||||
<h4 style="margin-bottom: 20px;">Health Check</h4>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>URL</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">
|
||||
{{#if config.healthCheck.uri}}
|
||||
{{config.healthCheck.uri}}
|
||||
{{else}}
|
||||
<i>None</i>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Check Interval</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<span class="form-control-static">{{config.healthCheck.interval}}ms</span>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Timeout</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<span class="form-control-static">{{config.healthCheck.responseTimeout}}ms</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Healthy Threshold</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<span class="form-control-static">{{config.healthCheck.healthyThreshold}}ms</span>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Unealthy Threshold</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<span class="form-control-static">{{config.healthCheck.unhealthyThreshold}}ms</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="well section">
|
||||
<h4>Stickiness</h4>
|
||||
{{#if config.appCookieStickinessPolicy}}
|
||||
{{else}}
|
||||
{{#if config.lbCookieStickinessPolicy}}
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Cookie Name</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">{{config.lbCookieStickinessPolicy.cookie}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Cookie Domain</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">{{config.lbCookieStickinessPolicy.domain}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Mode</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">
|
||||
{{config.lbCookieStickinessPolicy.mode}}
|
||||
{{#if config.lbCookieStickinessPolicy.indirect}}, indirect{{/if}}
|
||||
{{#if config.lbCookieStickinessPolicy.nocache}}, no-cache{{/if}}
|
||||
{{#if config.lbCookieStickinessPolicy.postonly}}, POST only{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<span class="text-muted">Stickiness is not configured.</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{partial "loadbalancer/config-detail"}}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ import Ember from 'ember';
|
|||
|
||||
export default Ember.Route.extend({
|
||||
model: function(/*params*/) {
|
||||
return this.modelFor('loadbalancer');
|
||||
var balancer = this.modelFor('loadbalancer');
|
||||
return balancer.importLink('hosts',{sort: 'name', include: 'ipAddresses'}).then(() => {
|
||||
return balancer;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,15 @@ export default Ember.ObjectController.extend({
|
|||
return !this.get('actions.settargets');
|
||||
}.property('actions.settargets'),
|
||||
|
||||
arrangedTargets: function() {
|
||||
var targets = this.get('loadBalancerTargets');
|
||||
|
||||
return Ember.ArrayController.create({
|
||||
content: targets,
|
||||
sortProperties: ['ipAddress', 'instance.name', 'instance.id', 'instanceId']
|
||||
});
|
||||
}.property('instances.[]','loadBalancerTargets.@each.{instanceId,ipAddress}'),
|
||||
|
||||
actions: {
|
||||
newTarget: function() {
|
||||
this.transitionToRoute('loadbalancer.targets.new');
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<section class="grid-header">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<h3>Targets ({{loadBalancerTargets.length}})</h3>
|
||||
<h3>Targets ({{arrangedTargets.length}})</h3>
|
||||
</div>
|
||||
<div class="col-sm-6 text-right">
|
||||
<button {{action "newTarget"}} class="btn btn-sm btn-primary" {{bind-attr disabled="addDisabled:disabled"}}>Add Targets</button>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each target in loadBalancerTargets itemController="loadbalancertarget"}}
|
||||
{{#each target in arrangedTargets itemController="loadbalancertarget"}}
|
||||
<tr>
|
||||
<td>
|
||||
<span {{bind-attr class=":badge :state target.stateBackground"}}>
|
||||
|
|
@ -34,9 +34,13 @@
|
|||
Container
|
||||
</td>
|
||||
<td>
|
||||
{{#with target.instance as c controller="container"}}
|
||||
{{#link-to "container" c.id}}{{c.displayName}}{{/link-to}}
|
||||
{{/with}}
|
||||
{{#if target.instance}}
|
||||
{{#with target.instance as c controller="container"}}
|
||||
{{#link-to "container" c.id}}{{c.displayName}}{{/link-to}}
|
||||
{{/with}}
|
||||
{{else}}
|
||||
<span class="text-muted">Loading...</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
{{/if}}
|
||||
<td class="actions">
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
{{partial "loadbalancer/config-detail"}}
|
||||
|
|
@ -2,9 +2,14 @@ import Cattle from 'ui/utils/cattle';
|
|||
|
||||
var LoadBalancerConfig = Cattle.TransitioningResource.extend({
|
||||
type: 'loadBalancerConfig',
|
||||
listeners: Ember.computed.alias('loadBalancerListeners'),
|
||||
config: function() {
|
||||
return this;
|
||||
}.property()
|
||||
});
|
||||
|
||||
LoadBalancerConfig.reopenClass({
|
||||
alwaysInclude: ['loadBalancerListeners','loadBalancers'],
|
||||
});
|
||||
|
||||
export default LoadBalancerConfig;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
model: function(params) {
|
||||
return this.get('store').find('loadbalancerconfig', params.loadbalancerconfig_id);
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.send('setPageLayout', {label: 'All Balancer Configs', backRoute: 'loadbalancerconfigs', hasAside: 'nav-balancing active'});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<aside>
|
||||
<label>Balancer Config</label>
|
||||
{{resource-actions-menu model=this choices=availableActions classNames="pull-right"}}
|
||||
<h3>{{displayName}}</h3>
|
||||
|
||||
<hr/>
|
||||
|
||||
{{#if description}}
|
||||
<label style="margin-top: 10px;">Description</label>
|
||||
<p>{{description}}</p>
|
||||
<hr/>
|
||||
{{/if}}
|
||||
|
||||
<div class="clearfix">
|
||||
<label>Info</label>
|
||||
</div>
|
||||
|
||||
<ul class="list-circles">
|
||||
<li>
|
||||
<i {{bind-attr class=":fa-fw stateIcon"}}></i>
|
||||
{{displayState}}
|
||||
{{#if isTransitioning}}
|
||||
<div class="progress progress-striped active" style="height: 10px; border: 0;">
|
||||
<div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" {{bind-attr aria-valuenow=displayProgress style=progressStyle}}>
|
||||
<span class="sr-only">{{displayProgress}}% Complete</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if showTransitioningMessage}}
|
||||
<div class="force-wrap">
|
||||
{{transitioningMessage}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
{{outlet}}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import Cattle from 'ui/utils/cattle';
|
||||
|
||||
export default Cattle.CollectionController.extend({
|
||||
itemController: 'loadbalancerconfig'
|
||||
});
|
||||
|
|
@ -1,3 +1,56 @@
|
|||
{{partial "balancing-aside"}}
|
||||
|
||||
Configs grid...
|
||||
<section>
|
||||
<table class="grid fixed" style="margin-bottom: 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="120">State</th>
|
||||
<th>Name</th>
|
||||
<th width="100">Listeners</th>
|
||||
<th width="100">Stickiness</th>
|
||||
<th width="150">Used by</th>
|
||||
<th width="50"> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each config in this}}
|
||||
<tr>
|
||||
<td>
|
||||
<span {{bind-attr class=":badge :state config.stateBackground"}}>
|
||||
{{config.displayState}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{{#link-to "loadbalancerconfig" config.id}}{{config.displayName}}{{/link-to}}
|
||||
</td>
|
||||
<td>
|
||||
{{#if config.loadBalancerListeners}}{{config.loadBalancerListeners.length}}{{else}}<i class="text-muted">None</i>{{/if}}
|
||||
</td>
|
||||
<td>
|
||||
{{#if config.appCookieStickinessPolicy}}
|
||||
Create Cookie
|
||||
{{else}}
|
||||
{{#if config.lbCookieStickinessPolicy}}
|
||||
Use existing cookie
|
||||
{{else}}
|
||||
None
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</td>
|
||||
<td>
|
||||
{{#each balancer in config.loadBalancers itemController="loadbalancer"}}
|
||||
<p>{{#link-to "loadbalancer" balancer.id}}{{balancer.displayName}}{{/link-to}}</p>
|
||||
{{else}}
|
||||
<span class="text-muted">None</span>
|
||||
{{/each}}
|
||||
</td>
|
||||
<td align="right">
|
||||
{{resource-actions-menu model=config choices=config.availableActions}}
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr><td colspan="4" class="text-center text-muted">You don't have any registries yet.</td></tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.View.extend({
|
||||
didInsertElement: function() {
|
||||
$('BODY').addClass('white');
|
||||
},
|
||||
|
||||
willDestroyElement: function() {
|
||||
$('BODY').removeClass('white');
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import Ember from 'ember';
|
||||
import Cattle from 'ui/utils/cattle';
|
||||
import EditLoadBalancerConfig from 'ui/mixins/edit-loadbalancerconfig';
|
||||
|
||||
export default Ember.ObjectController.extend(Cattle.NewOrEditMixin, EditLoadBalancerConfig, {
|
||||
queryParams: ['tab'],
|
||||
tab: 'listeners',
|
||||
error: null,
|
||||
editing: false,
|
||||
primaryResource: Ember.computed.alias('model.config'),
|
||||
|
||||
initFields: function() {
|
||||
this.set('listenersArray', [
|
||||
this.get('store').createRecord({
|
||||
type: 'loadBalancerListener',
|
||||
name: 'uilistener',
|
||||
sourcePort: '',
|
||||
sourceProtocol: 'tcp',
|
||||
targetPort: '',
|
||||
targetProtocol: 'tcp',
|
||||
algorithm: 'roundrobin',
|
||||
})
|
||||
]);
|
||||
},
|
||||
|
||||
didSave: function() {
|
||||
var listeners = this.get('listenersArray');
|
||||
var promises = [];
|
||||
listeners.forEach((listener) => {
|
||||
promises.push(listener.save());
|
||||
});
|
||||
|
||||
return Ember.RSVP.all(promises).then((listeners) => {
|
||||
var ids = listeners.map((listener) => {
|
||||
return listener.get('id');
|
||||
});
|
||||
|
||||
return this.get('config').doAction('setlisteners',{loadBalancerListenerIds: ids});
|
||||
});
|
||||
},
|
||||
|
||||
doneSaving: function() {
|
||||
this.transitionToRoute('loadbalancerconfigs');
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import AuthenticatedRouteMixin from 'ui/mixins/authenticated-route';
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
||||
model: function(/*params, transition*/) {
|
||||
var store = this.get('store');
|
||||
|
||||
var dependencies = [
|
||||
store.findAll('host'),
|
||||
];
|
||||
|
||||
return Ember.RSVP.all(dependencies, 'Load dependencies').then(function(results) {
|
||||
return {
|
||||
config: store.createRecord({
|
||||
type: 'loadBalancerConfig',
|
||||
healthCheck: store.createRecord({
|
||||
type: 'loadBalancerHealthCheck',
|
||||
interval: 2000,
|
||||
responseTimeout: 2000,
|
||||
healthyThreshold: 2,
|
||||
unhealthyThreshold: 3,
|
||||
}),
|
||||
appCookieStickinessPolicy: null,
|
||||
lbCookieStickinessPolicy: null,
|
||||
}),
|
||||
appCookie: store.createRecord({
|
||||
type: 'loadBalancerAppCookieStickinessPolicy',
|
||||
mode: 'path_parameters',
|
||||
requestLearn: true,
|
||||
timeout: 3600000,
|
||||
}),
|
||||
lbCookie: store.createRecord({
|
||||
type: 'loadBalancerCookieStickinessPolicy'
|
||||
}),
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
controller.set('model',model);
|
||||
controller.initFields();
|
||||
},
|
||||
|
||||
resetController: function (controller, isExisting/*, transition*/) {
|
||||
if (isExisting)
|
||||
{
|
||||
controller.set('tab', 'listeners');
|
||||
controller.set('stickiness', 'none');
|
||||
}
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.send('setPageLayout', {label: 'Back', backRoute: 'loadbalancers'});
|
||||
},
|
||||
|
||||
actions: {
|
||||
cancel: function() {
|
||||
this.transitionTo('loadbalancers');
|
||||
},
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<section class="horizontal-form container-fluid">
|
||||
<h2>Add Balancer Config</h2>
|
||||
{{partial "top-error"}}
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-2 form-label">
|
||||
<label for="name">Name</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-8">
|
||||
{{input id="name" type="text" value=config.name classNames="form-control" placeholder="e.g. Web balancer config"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-2 form-label">
|
||||
<label for="description">Description</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-8">
|
||||
{{textarea id="description" value=config.description classNames="form-control no-resize" rows="5" placeholder="e.g. HTTP balancing for www.example.com"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-10 col-xs-offset-1">
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{partial "loadbalancer/edit-config"}}
|
||||
|
||||
{{partial "save-cancel"}}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
function addAction(action, selector) {
|
||||
return function() {
|
||||
this.get('controller').send(action);
|
||||
Ember.run.next(this, function() {
|
||||
this.$(selector).last().focus();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default Ember.View.extend({
|
||||
actions: {
|
||||
addHost: addAction('addHost', '.lb-host'),
|
||||
addTargetContainer: addAction('addTargetContainer', '.lb-target'),
|
||||
addTargetIp: addAction('addTargetIp', '.lb-target'),
|
||||
addListener: addAction('addListener', '.lb-listener-source-port'),
|
||||
|
||||
selectTab: function(name) {
|
||||
this.set('context.tab',name);
|
||||
this.$('.tab').removeClass('active');
|
||||
this.$('.tab[data-section="'+name+'"]').addClass('active');
|
||||
this.$('.section').addClass('hide');
|
||||
this.$('.section[data-section="'+name+'"]').removeClass('hide');
|
||||
}
|
||||
},
|
||||
|
||||
didInsertElement: function() {
|
||||
$('BODY').addClass('white');
|
||||
this._super();
|
||||
this.send('selectTab',this.get('context.tab'));
|
||||
|
||||
this.$('INPUT')[0].focus();
|
||||
},
|
||||
|
||||
willDestroyElement: function() {
|
||||
$('BODY').removeClass('white');
|
||||
},
|
||||
});
|
||||
|
|
@ -17,7 +17,7 @@ export default HostController.extend({
|
|||
|
||||
availableActions: function() {
|
||||
var choices = [
|
||||
{ label: 'Delete', icon: 'ss-trash', action: 'promptDelete', enabled: true, altAction: 'delete' },
|
||||
{ label: 'Remove Host', icon: 'ss-trash', action: 'promptDelete', enabled: true, altAction: 'delete' },
|
||||
];
|
||||
|
||||
return choices;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import Ember from 'ember';
|
||||
import Cattle from 'ui/utils/cattle';
|
||||
import EditLoadBalancerConfig from 'ui/mixins/edit-loadbalancerconfig';
|
||||
|
||||
export default Ember.ObjectController.extend(Cattle.NewOrEditMixin, {
|
||||
export default Ember.ObjectController.extend(Cattle.NewOrEditMixin, EditLoadBalancerConfig, {
|
||||
queryParams: ['tab'],
|
||||
tab: 'listeners',
|
||||
error: null,
|
||||
|
|
@ -25,26 +26,6 @@ export default Ember.ObjectController.extend(Cattle.NewOrEditMixin, {
|
|||
removeTarget: function(obj) {
|
||||
this.get('targetsArray').removeObject(obj);
|
||||
},
|
||||
|
||||
addListener: function() {
|
||||
this.get('listenersArray').pushObject(this.get('store').createRecord({
|
||||
type: 'loadBalancerListener',
|
||||
name: 'uilistener',
|
||||
sourcePort: '',
|
||||
sourceProtocol: 'tcp',
|
||||
targetPort: '',
|
||||
targetProtocol: 'tcp',
|
||||
algorithm: 'roundrobin',
|
||||
}));
|
||||
},
|
||||
|
||||
removeListener: function(obj) {
|
||||
this.get('listenersArray').removeObject(obj);
|
||||
},
|
||||
|
||||
chooseProtocol: function(listener, key, val) {
|
||||
listener.set(key,val);
|
||||
},
|
||||
},
|
||||
|
||||
initFields: function() {
|
||||
|
|
@ -113,52 +94,6 @@ export default Ember.ObjectController.extend(Cattle.NewOrEditMixin, {
|
|||
});
|
||||
}.property('targetsArray.@each.{isIp,isContainer,value}'),
|
||||
|
||||
sourceProtocolOptions: function() {
|
||||
return this.get('store').getById('schema','loadbalancerlistener').get('resourceFields.sourceProtocol.options');
|
||||
}.property(),
|
||||
|
||||
targetProtocolOptions: function() {
|
||||
return this.get('store').getById('schema','loadbalancerlistener').get('resourceFields.targetProtocol.options');
|
||||
}.property(),
|
||||
|
||||
algorithmOptions: function() {
|
||||
return this.get('store').getById('schema','loadbalancerlistener').get('resourceFields.algorithm.options');
|
||||
}.property(),
|
||||
|
||||
listenersArray: null,
|
||||
|
||||
stickiness: 'none',
|
||||
isStickyNone: Ember.computed.equal('stickiness','none'),
|
||||
isStickyLbCookie: Ember.computed.equal('stickiness','lbCookie'),
|
||||
isStickyAppCookie: Ember.computed.equal('stickiness','appCookie'),
|
||||
lbCookieModeChoices: [
|
||||
{value: 'rewrite', label: 'Rewrite'},
|
||||
{value: 'insert', label: 'Insert'},
|
||||
{value: 'prefix', label: 'Prefix'},
|
||||
],
|
||||
appCookieModeChoices: [
|
||||
{value: 'path_parameters', label: 'Path Parameter'},
|
||||
{value: 'query_string', label: 'Query String'},
|
||||
],
|
||||
stickinessDidChange: function() {
|
||||
var stickiness = this.get('stickiness');
|
||||
if ( stickiness === 'none' )
|
||||
{
|
||||
this.set('config.lbCookieStickinessPolicy', null);
|
||||
this.set('config.appCookieStickinessPolicy', null);
|
||||
}
|
||||
else if ( stickiness === 'lbCookie' )
|
||||
{
|
||||
this.set('config.lbCookieStickinessPolicy', this.get('lbCookie'));
|
||||
this.set('config.appCookieStickinessPolicy', null);
|
||||
}
|
||||
else if ( stickiness === 'appCookie' )
|
||||
{
|
||||
this.set('config.lbCookieStickinessPolicy', null);
|
||||
this.set('config.appCookieStickinessPolicy', this.get('appCookie'));
|
||||
}
|
||||
}.observes('stickiness'),
|
||||
|
||||
validate: function() {
|
||||
var config = this.get('model.config');
|
||||
var balancer = this.get('model.balancer');
|
||||
|
|
|
|||
|
|
@ -70,37 +70,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<section class="text-center" style="padding: 0;">
|
||||
<ul class="nav nav-pills" style="display: inline-block">
|
||||
<li role="presentation" class="tab" data-section="listeners" {{action "selectTab" "listeners" target=view}}><a>Listeners</a></li>
|
||||
<li role="presentation" class="tab" data-section="healthcheck" {{action "selectTab" "healthcheck" target=view}}><a>Health Check</a></li>
|
||||
<li role="presentation" class="tab" data-section="stickiness" {{action "selectTab" "stickiness" target=view}}><a>Stickiness</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="horizontal-form tab-section" style="background-color: #f8f9fa; margin: -7px 10px 0 10px;">
|
||||
<div class="section container-fluid" data-section="listeners">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<label>Listening Ports</label>
|
||||
|
||||
<button class="btn-circle-plus" {{action "addListener" target="view"}}></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-8 col-md-offset-2">
|
||||
{{partial "loadbalancer/new-listeners"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section container-fluid tab-section" data-section="healthcheck">
|
||||
{{partial "loadbalancer/edit-healthcheck"}}
|
||||
</div>
|
||||
|
||||
<div class="section container-fluid tab-section" data-section="stickiness">
|
||||
{{partial "loadbalancer/edit-stickiness"}}
|
||||
</div>
|
||||
</section>
|
||||
{{partial "loadbalancer/edit-config"}}
|
||||
|
||||
{{partial "save-cancel"}}
|
||||
|
|
|
|||
|
|
@ -13,14 +13,19 @@ var LoadBalancerTargetController = Cattle.TransitioningResourceController.extend
|
|||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
delete: function() {
|
||||
this.delete();
|
||||
}
|
||||
},
|
||||
|
||||
availableActions: function() {
|
||||
|
||||
var a = this.get('actions');
|
||||
|
||||
var choices = [
|
||||
{ label: 'Delete', icon: 'ss-trash', action: 'promptDelete', enabled: !!a.remove, altAction: 'delete' },
|
||||
{ label: 'Remove Target', icon: 'ss-trash', action: 'promptDelete', enabled: true, altAction: 'delete' },
|
||||
{ label: 'Purge', icon: 'ss-tornado', action: 'purge', enabled: !!a.purge },
|
||||
{ divider: true },
|
||||
{ label: 'View in API', icon: 'fa fa-external-link', action: 'goToApi', enabled: true, detail: true },
|
||||
];
|
||||
|
||||
return choices;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Mixin.create({
|
||||
actions: {
|
||||
addListener: function() {
|
||||
this.get('listenersArray').pushObject(this.get('store').createRecord({
|
||||
type: 'loadBalancerListener',
|
||||
name: 'uilistener',
|
||||
sourcePort: '',
|
||||
sourceProtocol: 'tcp',
|
||||
targetPort: '',
|
||||
targetProtocol: 'tcp',
|
||||
algorithm: 'roundrobin',
|
||||
}));
|
||||
},
|
||||
|
||||
removeListener: function(obj) {
|
||||
this.get('listenersArray').removeObject(obj);
|
||||
},
|
||||
|
||||
chooseProtocol: function(listener, key, val) {
|
||||
listener.set(key,val);
|
||||
},
|
||||
},
|
||||
|
||||
listenersArray: null,
|
||||
|
||||
sourceProtocolOptions: function() {
|
||||
return this.get('store').getById('schema','loadbalancerlistener').get('resourceFields.sourceProtocol.options');
|
||||
}.property(),
|
||||
|
||||
targetProtocolOptions: function() {
|
||||
return this.get('store').getById('schema','loadbalancerlistener').get('resourceFields.targetProtocol.options');
|
||||
}.property(),
|
||||
|
||||
algorithmOptions: function() {
|
||||
return this.get('store').getById('schema','loadbalancerlistener').get('resourceFields.algorithm.options');
|
||||
}.property(),
|
||||
|
||||
stickiness: 'none',
|
||||
isStickyNone: Ember.computed.equal('stickiness','none'),
|
||||
isStickyLbCookie: Ember.computed.equal('stickiness','lbCookie'),
|
||||
isStickyAppCookie: Ember.computed.equal('stickiness','appCookie'),
|
||||
|
||||
lbCookieModeChoices: [
|
||||
{value: 'rewrite', label: 'Rewrite'},
|
||||
{value: 'insert', label: 'Insert'},
|
||||
{value: 'prefix', label: 'Prefix'},
|
||||
],
|
||||
|
||||
appCookieModeChoices: [
|
||||
{value: 'path_parameters', label: 'Path Parameter'},
|
||||
{value: 'query_string', label: 'Query String'},
|
||||
],
|
||||
|
||||
stickinessDidChange: function() {
|
||||
var stickiness = this.get('stickiness');
|
||||
if ( stickiness === 'none' )
|
||||
{
|
||||
this.set('config.lbCookieStickinessPolicy', null);
|
||||
this.set('config.appCookieStickinessPolicy', null);
|
||||
}
|
||||
else if ( stickiness === 'lbCookie' )
|
||||
{
|
||||
this.set('config.lbCookieStickinessPolicy', this.get('lbCookie'));
|
||||
this.set('config.appCookieStickinessPolicy', null);
|
||||
}
|
||||
else if ( stickiness === 'appCookie' )
|
||||
{
|
||||
this.set('config.lbCookieStickinessPolicy', null);
|
||||
this.set('config.appCookieStickinessPolicy', this.get('appCookie'));
|
||||
}
|
||||
}.observes('stickiness'),
|
||||
});
|
||||
|
|
@ -99,6 +99,11 @@ Router.map(function() {
|
|||
this.resource('loadbalancerconfigs', {path: '/configs'}, function() {
|
||||
this.route('new', {path: '/add'});
|
||||
this.route('index', {path: '/'});
|
||||
|
||||
this.resource('loadbalancerconfig', {path: '/:loadbalancerconfig_id'}, function() {
|
||||
this.route('index', {path: '/'});
|
||||
this.route('edit');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,178 @@
|
|||
<div class="well section">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<h4>Listeners ({{listeners.length}})</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="grid fixed" style="margin-bottom: 0;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="120">State</th>
|
||||
<th>Source</th>
|
||||
<th width="30"></th>
|
||||
<th>Target</th>
|
||||
<th class="text-right">Algorithm</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each listener in listeners itemController="loadbalancerlistener"}}
|
||||
<tr>
|
||||
<td>
|
||||
<span {{bind-attr class=":badge :state listener.stateBackground"}}>
|
||||
{{listener.displayState}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{{listener.sourcePort}}/{{listener.sourceProtocol}}
|
||||
</td>
|
||||
<td>
|
||||
<i class="ss-arrow-right"></i>
|
||||
</td>
|
||||
<td>
|
||||
{{listener.targetPort}}/{{listener.targetProtocol}}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{listener.algorithm}}
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr><td colspan="4" class="text-center text-muted">This host does not have any containers yet.</td></tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="well section">
|
||||
<h4 style="margin-bottom: 20px;">Health Check</h4>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>URL</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">
|
||||
{{#if config.healthCheck.uri}}
|
||||
{{config.healthCheck.uri}}
|
||||
{{else}}
|
||||
<i>None</i>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Check Interval</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<span class="form-control-static">{{config.healthCheck.interval}}ms</span>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Timeout</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<span class="form-control-static">{{config.healthCheck.responseTimeout}}ms</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Healthy Threshold</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<span class="form-control-static">{{config.healthCheck.healthyThreshold}}ms</span>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Unealthy Threshold</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<span class="form-control-static">{{config.healthCheck.unhealthyThreshold}}ms</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="well section">
|
||||
<h4 style="margin-bottom: 20px;">Stickiness</h4>
|
||||
|
||||
{{#if config.appCookieStickinessPolicy}}
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Cookie Name</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">{{config.appCookieStickinessPolicy.cookie}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Prefix</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">{{config.appCookieStickinessPolicy.prefix}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Maximum Length</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">{{config.appCookieStickinessPolicy.length}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Timeout</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">{{config.appCookieStickinessPolicy.timeout}}ms</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Mode</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">
|
||||
{{config.appCookieStickinessPolicy.mode}}
|
||||
{{#if config.appCookieStickinessPolicy.requestLearn}}, lean from request{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if config.lbCookieStickinessPolicy}}
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Cookie Name</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">{{config.lbCookieStickinessPolicy.cookie}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Cookie Domain</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">{{config.lbCookieStickinessPolicy.domain}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-3">
|
||||
<label>Mode</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9">
|
||||
<span class="form-control-static">
|
||||
{{config.lbCookieStickinessPolicy.mode}}
|
||||
{{#if config.lbCookieStickinessPolicy.indirect}}, indirect{{/if}}
|
||||
{{#if config.lbCookieStickinessPolicy.nocache}}, no-cache{{/if}}
|
||||
{{#if config.lbCookieStickinessPolicy.postonly}}, POST only{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<span class="text-muted">Stickiness is not configured.</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<section class="text-center" style="padding: 0;">
|
||||
<ul class="nav nav-pills" style="display: inline-block">
|
||||
<li role="presentation" class="tab" data-section="listeners" {{action "selectTab" "listeners" target=view}}><a>Listeners</a></li>
|
||||
<li role="presentation" class="tab" data-section="healthcheck" {{action "selectTab" "healthcheck" target=view}}><a>Health Check</a></li>
|
||||
<li role="presentation" class="tab" data-section="stickiness" {{action "selectTab" "stickiness" target=view}}><a>Stickiness</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="horizontal-form tab-section" style="background-color: #f8f9fa; margin: -7px 10px 0 10px;">
|
||||
<div class="section container-fluid" data-section="listeners">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<label>Listening Ports</label>
|
||||
|
||||
<button class="btn-circle-plus" {{action "addListener" target="view"}}></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-8 col-md-offset-2">
|
||||
{{partial "loadbalancer/new-listeners"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section container-fluid tab-section" data-section="healthcheck">
|
||||
{{partial "loadbalancer/edit-healthcheck"}}
|
||||
</div>
|
||||
|
||||
<div class="section container-fluid tab-section" data-section="stickiness">
|
||||
{{partial "loadbalancer/edit-stickiness"}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Loading…
Reference in New Issue