Merge pull request #205 from vincent99/service-consume-map

Refactor service consumer lookup, edit service link names
This commit is contained in:
Vincent Fiduccia 2015-06-11 15:03:18 -07:00
commit 64e09c190b
19 changed files with 183 additions and 106 deletions

View File

@ -347,26 +347,19 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
},
loadBalancerServiceChanged: function(change) {
var service = change.data.resource;
this._includeChanged('environment', 'services', 'environmentId', change.data.resource);
service.importLink('consumedservices');
},
dnsServiceChanged: function(change) {
this._includeChanged('environment', 'services', 'environmentId', change.data.resource);
},
externalServiceChanged: function(change) {
this._includeChanged('environment', 'services', 'environmentId', change.data.resource);
},
serviceChanged: function(change) {
var service = change.data.resource;
this._includeChanged('environment', 'services', 'environmentId', change.data.resource);
// Remove the service from depenedent services
if ( ['removed','purged','purging'].indexOf(service.get('state')) >= 0 )
{
['service','loadBalancerService','dnsService','externalService'].forEach((type) => {
this.get('store').all(type).forEach((otherService) => {
(otherService.get('consumedservices')||[]).removeObject(service);
});
});
}
service.importLink('consumedservices');
},
},

View File

@ -13,11 +13,22 @@
</div>
</div>
{{#if (or model.consumedservices.length model.externalIpAddresses.length)}}
{{#if (or model.consumedServicesWithNames.length model.externalIpAddresses.length)}}
<div class="pod-info clearfix">
<div class="pod-info-line">
{{#each item in model.consumedservices itemController="service"}}
<div class="pod-info-item">{{#link-to "service" item.environmentId item.id}}<i class="ss-layergroup"></i> {{item.displayName}}{{/link-to}}</div>
{{#each map in model.consumedServicesWithNames}}
{{#with map.service as service controller="service"}}
<div class="pod-info-item">
{{#link-to "service" service.environmentId service.id}}
<i {{bind-attr class="service.activeIcon"}}></i>
{{#if (eq map.name service.displayName)}}
{{map.name}}
{{else}}
{{service.displayName}}{{#if map.name}} <span class="text-muted">(as {{map.name}})</span>{{/if}}
{{/if}}
{{/link-to}}
</div>
{{/with}}
{{/each}}
</div>
{{#if model.externalIpAddresses.length}}

View File

@ -1,35 +1,11 @@
import Cattle from 'ui/utils/cattle';
import Service from 'ui/service/model';
var DnsService = Cattle.TransitioningResource.extend({
type: 'service',
consumedServicesUpdated: 0,
onConsumedServicesChanged: function() {
this.incrementProperty('consumedServicesUpdated');
}.observes('consumedservices.@each.{id,name,state}'),
var DnsService = Service.extend({
type: 'dnsService',
healthState: function() {
return 'healthy';
}.property(),
combinedState: function() {
var service = this.get('state');
var health = this.get('healthState');
if ( ['active','updating-active'].indexOf(service) === -1 )
{
// If the service isn't active, return its state
return service;
}
if ( health === 'healthy' )
{
return service;
}
else
{
return 'degraded';
}
}.property('state', 'healthState'),
});
DnsService.reopenClass({

View File

@ -1,6 +1,7 @@
import Ember from 'ember';
import Util from 'ui/utils/util';
import ThrottledResize from 'ui/mixins/throttled-resize';
import { activeIcon } from 'ui/service/controller';
export default Ember.View.extend(ThrottledResize,{
classNames: ['environment-graph'],
@ -72,7 +73,7 @@ export default Ember.View.extend(ThrottledResize,{
var color = (service.get('state') === 'active' ? 'green' : (service.get('state') === 'inactive' ? 'red' : 'yellow'));
var instances = service.get('instances.length')||'No';
var html = '<i class="icon ss-layergroup"></i>' +
var html = '<i class="icon '+ activeIcon(service) +'"></i>' +
'<h4 class="clip">'+ Util.escapeHtml(service.get('name')) + '</h4>' +
'<h6 class="count"><b>' + instances + '</b> container' + (instances === 1 ? '' : 's') + '</h6>' +
'<h6><span class="state '+ color +'">' + Util.escapeHtml(Util.ucFirst(service.get('state'))) + '</span></h6>';
@ -89,15 +90,24 @@ export default Ember.View.extend(ThrottledResize,{
unremovedServices.forEach(function(service) {
var serviceId = service.get('id');
(service.get('consumedservices')||[]).map(function(target) {
(service.get('consumedServicesWithNames')||[]).map(function(map) {
var target = map.get('service');
var targetId = target.get('id');
var color = (target.get('state') === 'active' ? 'green' : (target.get('state') === 'inactive' ? 'red' : 'yellow'));
g.setEdge(serviceId, targetId, {
var edgeOpts = {
arrowhead: 'vee',
lineInterpolate: 'bundle',
class: color,
});
};
var mapName = map.get('name');
if ( mapName && mapName !== target.get('name') )
{
edgeOpts.label = mapName;
}
g.setEdge(serviceId, targetId, edgeOpts);
var existing = unexpectedEdges.filter(function(edge) {
return edge.v === serviceId && edge.w === targetId;

View File

@ -8,9 +8,10 @@ export default Ember.Route.extend({
filter: {
environmentId: env.get('id'),
},
include: ['consumedservices','instances']
include: ['instances']
}).then((services) => {
env.set('services', services||[]);
env.set('services.sortProperties', ['name','id']);
return env;
});
});

View File

@ -3,14 +3,21 @@ import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
var store = this.get('store');
return store.findAllUnremoved('environment').then((environments) => {
var promises = [
store.findAllUnremoved('environment'),
];
return Ember.RSVP.all(promises).then((results) => {
var environments = results[0];
var promises = [];
environments.forEach((env) => {
var promise = store.find('service', null, {
filter: {
environmentId: env.get('id'),
},
include: ['consumedservices','instances']
include: ['instances']
}).then((services) => {
env.set('services', services||[]);
env.set('services.sortProperties', ['name','id']);

View File

@ -1,35 +1,11 @@
import Cattle from 'ui/utils/cattle';
import Service from 'ui/service/model';
var ExternalService = Cattle.TransitioningResource.extend({
type: 'service',
consumedServicesUpdated: 0,
onConsumedServicesChanged: function() {
this.incrementProperty('consumedServicesUpdated');
}.observes('consumedservices.@each.{id,name,state}'),
var ExternalService = Service.extend({
type: 'externalService',
healthState: function() {
return 'healthy';
}.property(),
combinedState: function() {
var service = this.get('state');
var health = this.get('healthState');
if ( ['active','updating-active'].indexOf(service) === -1 )
{
// If the service isn't active, return its state
return service;
}
if ( health === 'healthy' )
{
return service;
}
else
{
return 'degraded';
}
}.property('state', 'healthState'),
});
ExternalService.reopenClass({

View File

@ -50,26 +50,27 @@ export default Ember.Mixin.create(EditLabels, {
serviceLinksAsMap: null,
initServiceLinks: function() {
var out = [];
var links = this.get('service.consumedservices')||[];
var links;
if ( this.get('service.id') )
{
// Edit
links = this.get('service.consumedServicesWithNames')||[];
}
else
{
// New / Clone
links = this.get('service.serviceLinks')||[];
}
links.forEach(function(value) {
// Objects, from edit
var id;
if ( typeof value === 'object' )
{
id = Ember.get(value,'id');
if ( id )
{
out.push(Ember.Object.create({
obj: value,
serviceId: id,
}));
}
}
else
{
out.push(Ember.Object.create({serviceId: value}));
}
links.forEach(function(obj) {
var linkName = obj.get('name');
var service = obj.get('service');
out.push(Ember.Object.create({
linkName: (linkName === service.get('name') ? '' : linkName),
obj: service,
serviceId: service.get('id'),
}));
});
this.set('serviceLinksArray', out);

View File

@ -114,9 +114,13 @@ var ServiceController = Cattle.TransitioningResourceController.extend(ReadLabels
}.property('type'),
state: Ember.computed.alias('model.combinedState'),
activeIcon: function() {
return activeIcon(this.get('model'));
}.property('type'),
});
function activeIcon(service)
export function activeIcon(service)
{
var out = 'ss-layergroup';
switch ( service.get('type').toLowerCase() )

View File

@ -1,13 +1,85 @@
import Ember from 'ember';
import Cattle from 'ui/utils/cattle';
import C from 'ui/utils/constants';
var _allMaps;
var _allServices;
var _allLbServices;
var _allExternalServices;
var _allDnsServices;
var Service = Cattle.TransitioningResource.extend({
type: 'service',
_allMaps: null,
consumedServicesUpdated: 0,
serviceLinks: null, // Used for clone
reservedKeys: ['_allMaps','consumedServicesUpdated','serviceLinks'],
init: function() {
this._super();
// Hack: keep only one copy of all the services and serviceconsumemaps
// But you have to load service and serviceconsumemap beforehand somewhere...
// Bonus hack: all('services') doesn't include the other kinds of services, so load all those too.
if ( !_allMaps )
{
_allMaps = this.get('store').allUnremoved('serviceconsumemap');
}
this.set('_allMaps', _allMaps);
if ( !_allServices )
{
_allServices = this.get('store').allUnremoved('service');
}
if ( !_allLbServices )
{
_allLbServices = this.get('store').allUnremoved('loadbalancerservice');
}
if ( !_allExternalServices )
{
_allExternalServices = this.get('store').allUnremoved('externalservice');
}
if ( !_allDnsServices )
{
_allDnsServices = this.get('store').allUnremoved('dnsservice');
}
},
consumedServicesWithNames: function() {
var all = [_allServices, _allLbServices, _allExternalServices, _allDnsServices];
return this.get('_allMaps').filterProperty('serviceId', this.get('id')).map((map) => {
var i = 0;
var service = null;
while ( i < all.length && !service )
{
service = all[i].filterProperty('id', map.get('consumedServiceId'))[0];
i++;
}
return Ember.Object.create({
name: map.get('name'),
service: service
});
}).filter((obj) => {
return obj.get('service.id');
});
}.property('id','_allMaps.@each.{name,serviceId,consumedServiceId}'),
consumedServices: function() {
return this.get('consumedServicesWithNames').map((obj) => {
return obj.get('service');
});
}.property('consumedServicesWithNames.@each.service'),
onConsumedServicesChanged: function() {
this.incrementProperty('consumedServicesUpdated');
}.observes('consumedservices.@each.{id,name,state}'),
}.observes('consumedServicesWithNames.@each.{name,service}'),
healthState: function() {
var isGlobal = Object.keys(this.get('labels')||{}).indexOf(C.LABEL.SCHED_GLOBAL) >= 0;

View File

@ -34,7 +34,7 @@ export default Ember.ObjectController.extend(Cattle.NewOrEditMixin, {
targetsArray: null,
initTargets: function() {
var existing = this.get('dns.consumedservices');
var existing = this.get('dns.consumedServices');
var out = [];
if ( existing )
{

View File

@ -13,7 +13,7 @@ export default Ember.Route.extend({
if ( params.serviceId )
{
dependencies.pushObject(store.find('service', params.serviceId, {include: ['consumedservices']}));
dependencies.pushObject(store.find('service', params.serviceId));
}
return Ember.RSVP.all(dependencies, 'Load dependencies').then(function(results) {

View File

@ -45,7 +45,7 @@ export default Ember.ObjectController.extend(Cattle.NewOrEditMixin, EditLoadBala
targetsArray: null,
initTargets: function() {
var existing = this.get('balancer.consumedservices');
var existing = this.get('balancer.consumedServices');
var out = [];
if ( existing )
{

View File

@ -13,7 +13,7 @@ export default Ember.Route.extend({
if ( params.serviceId )
{
dependencies.pushObject(store.find('service', params.serviceId, {include: ['loadbalancerlisteners','consumedservices']}));
dependencies.pushObject(store.find('service', params.serviceId, {include: ['loadbalancerlisteners']}));
}
return Ember.RSVP.all(dependencies, 'Load dependencies').then(function(results) {

View File

@ -30,6 +30,7 @@ export default Ember.Route.extend({
var allHosts = results[0];
var environment = results[1];
var serviceOrContainer = results[2];
var serviceLinks = [];
var instanceData, serviceData, healthCheckData;
if ( serviceOrContainer )
@ -37,6 +38,7 @@ export default Ember.Route.extend({
if ( serviceOrContainer.get('type') === 'service' )
{
serviceData = serviceOrContainer.serializeForNew();
serviceLinks = serviceOrContainer.get('consumedServicesWithNames');
instanceData = serviceData.launchConfig;
delete serviceData.launchConfig;
delete serviceData.instances;
@ -80,7 +82,10 @@ export default Ember.Route.extend({
}
var instance = this.get('store').createRecord(instanceData);
var service = store.createRecord(serviceData);
service.set('serviceLinks', serviceLinks);
var healthCheck = store.createRecord(healthCheckData);
instance.set('healthCheck', healthCheck);
service.set('launchConfig', instance); // Creating a service needs the isntance definition here

View File

@ -0,0 +1,10 @@
import Cattle from 'ui/utils/cattle';
var ServiceConsumeMap = Cattle.TransitioningResource.extend({
type: 'serviceConsumeMap',
});
ServiceConsumeMap.reopenClass({
});
export default ServiceConsumeMap;

12
app/services/route.js Normal file
View File

@ -0,0 +1,12 @@
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
var store = this.get('store');
return Ember.RSVP.all([
store.findAllUnremoved('environment'),
store.findAllUnremoved('service'),
store.findAllUnremoved('serviceconsumemap'),
]);
}
});

View File

@ -49,7 +49,6 @@ module.exports = function(environment) {
'&include=loadBalancerTargets' +
'&include=loadBalancerListeners' +
'&include=instanceLinks' +
'&include=consumedservices' +
'&include=ipAddresses',
baseAssets: '',
},

View File

@ -1,6 +1,6 @@
{
"name": "ui",
"version": "0.25.0",
"version": "0.26.0",
"private": true,
"directories": {
"doc": "doc",