diff --git a/app/components/container-row/template.hbs b/app/components/container-row/template.hbs index 6e6344de8..270cb8fa5 100644 --- a/app/components/container-row/template.hbs +++ b/app/components/container-row/template.hbs @@ -2,7 +2,7 @@ {{badge-state model=model}} - {{#link-to detailRoute model.id}}{{model.displayName}}{{/link-to}} + {{model.displayName}} {{format-ip ip=model.displayIp}} @@ -10,7 +10,7 @@ {{#if showHost}} {{#if model.primaryHost}} - {{#link-to "host" model.primaryHost.id}}{{model.primaryHost.displayName}}{{/link-to}} + {{model.primaryHost.displayName}} {{else}} {{t 'containersPage.table.primaryHostUnknown'}} {{/if}} diff --git a/app/components/container-subpod/component.js b/app/components/container-subpod/component.js index 15750ce4d..581194f41 100644 --- a/app/components/container-subpod/component.js +++ b/app/components/container-subpod/component.js @@ -11,7 +11,7 @@ export default Ember.Component.extend(StrippedName, { classNameBindings: ['model.isManaged:managed'], stateBackground: function() { - return this.get('model.stateColor').replace("text-","bg-"); + return 'bg-'+this.get('model.stateColor').substr(5); }.property('model.stateColor'), isKubernetes: function() { diff --git a/app/components/container-subpod/template.hbs b/app/components/container-subpod/template.hbs index a20dac64e..4d4585663 100644 --- a/app/components/container-subpod/template.hbs +++ b/app/components/container-subpod/template.hbs @@ -1,11 +1,11 @@
- {{#link-to (if model.isVm "virtualmachine" "container") model.id classNameBindings="showEllipsis:tiny-hellip"}} + {{#tooltip-element tagName="span" inlineBlock=false type="tooltip-basic" model=model tooltipTemplate='tooltip-container-subpod' }} {{displayName}} {{/tooltip-element}} - {{/link-to}} +
{{#if model.showTransitioningMessage}}
diff --git a/app/components/form-volumes/component.js b/app/components/form-volumes/component.js index a091b5428..6d1ac600f 100644 --- a/app/components/form-volumes/component.js +++ b/app/components/form-volumes/component.js @@ -184,7 +184,7 @@ export default Ember.Component.extend({ }); return list.sortBy('group','name','id'); - }.property('instance.requestedHostId','allHosts.@each.instancesUpdated'), + }.property('instance.requestedHostId','allHosts.@each.instances'), volumesFromArray: null, initVolumesFrom: function() { diff --git a/app/components/host-pod/template.hbs b/app/components/host-pod/template.hbs index e8eb36085..1befe506b 100644 --- a/app/components/host-pod/template.hbs +++ b/app/components/host-pod/template.hbs @@ -7,7 +7,7 @@ {{#if isMachine}} {{model.displayName}} {{else}} - {{#link-to "host" model.id}}{{model.displayName}}{{/link-to}} + {{model.displayName}} {{#if model.showTransitioningMessage}}
{{model.transitioningMessage}} diff --git a/app/components/language-dropdown/component.js b/app/components/language-dropdown/component.js index 22e965b55..694626848 100644 --- a/app/components/language-dropdown/component.js +++ b/app/components/language-dropdown/component.js @@ -12,6 +12,7 @@ export default Ember.Component.extend({ language : Ember.inject.service('user-language'), intl : Ember.inject.service(), session : Ember.inject.service(), + settings : Ember.inject.service(), locales : Ember.computed.alias('language.locales'), diff --git a/app/components/language-dropdown/template.hbs b/app/components/language-dropdown/template.hbs index 85b76c302..d1f61b94c 100644 --- a/app/components/language-dropdown/template.hbs +++ b/app/components/language-dropdown/template.hbs @@ -2,6 +2,10 @@ {{selectedLabel}} diff --git a/app/components/page-footer/template.hbs b/app/components/page-footer/template.hbs index 3e3066f29..bcd5f1e10 100644 --- a/app/components/page-footer/template.hbs +++ b/app/components/page-footer/template.hbs @@ -2,7 +2,7 @@ {{#if settings.isRancher}} {{#if projectId}} - {{#link-to "authenticated.project.help" projectId role="button" class="btn btn-sm btn-link"}}{{t 'pageFooter.help'}}{{/link-to}} + {{t 'pageFooter.help'}} {{/if}} {{t 'pageFooter.documentation'}} {{t 'pageFooter.faq'}} diff --git a/app/components/scheduling-rule-row/component.js b/app/components/scheduling-rule-row/component.js index d0f9da22e..c89770c9a 100644 --- a/app/components/scheduling-rule-row/component.js +++ b/app/components/scheduling-rule-row/component.js @@ -246,7 +246,7 @@ export default Ember.Component.extend({ }); return out.sortBy('name','id').uniq(); - }.property('allHosts.@each.instancesUpdated'), + }.property('allHosts.@each.instances'), normalizedContainerLabels: function() { return normalizedLabels(this.get('allContainers')); diff --git a/app/hosts/route.js b/app/hosts/route.js index 6b8de99d4..ac4aec341 100644 --- a/app/hosts/route.js +++ b/app/hosts/route.js @@ -6,6 +6,7 @@ export default Ember.Route.extend({ return Ember.RSVP.hash({ machines: store.findAll('machine'), hosts: store.findAll('host'), + instances: store.findAll('instance'), }).then((hash) => { return hash.hosts; }); diff --git a/app/mixins/container-choices.js b/app/mixins/container-choices.js index 558dd0377..a7e720681 100644 --- a/app/mixins/container-choices.js +++ b/app/mixins/container-choices.js @@ -70,7 +70,7 @@ export default Ember.Mixin.create({ } return list.sortBy('group','name','id'); - }.property('allHosts.@each.instancesUpdated','intl._locale').volatile(), + }.property('allHosts.@each.instances','intl._locale'), containersOnRequestedHost: function() { var requestedHostId = this.get('instance.requestedHostId'); diff --git a/app/mixins/subscribe.js b/app/mixins/subscribe.js index 39764f236..05c927fe9 100644 --- a/app/mixins/subscribe.js +++ b/app/mixins/subscribe.js @@ -3,6 +3,8 @@ import Socket from 'ui/utils/socket'; import Util from 'ui/utils/util'; import C from 'ui/utils/constants'; +let DEADTOME = ['removed','purging','purged']; + export default Ember.Mixin.create({ k8s : Ember.inject.service(), projects : Ember.inject.service(), @@ -18,49 +20,63 @@ export default Ember.Mixin.create({ this.set('k8sUidBlacklist', []); var store = this.get('store'); - var boundTypeify = store._typeify.bind(store); var socket = Socket.create(); socket.on('message', (event) => { - // Fail-safe: make sure the message is for this project - var currentProject = this.get(`tab-session.${C.TABSESSION.PROJECT}`); - var metadata = socket.getMetadata(); - var socketProject = metadata.projectId; - if ( currentProject !== socketProject ) { - console.error(`Subscribe ignoring message, current=${currentProject} socket=${socketProject} ` + this.forStr()); - this.connectSubscribe(); - return; - } - - var d = JSON.parse(event.data, boundTypeify); - //this._trySend('subscribeMessage',d); - - if ( d.name === 'resource.change' ) - { - this._trySend(d.resourceType+'Changed', d); - } - else if ( d.name === 'service.kubernetes.change' ) - { - var changeType = (Ember.get(d, 'data.type')||'').toLowerCase(); - var obj = Ember.get(d, 'data.object'); - if ( changeType && obj ) - { - this._trySend('k8sResourceChanged', changeType, obj); + Ember.run.schedule('actions', this, function() { + // Fail-safe: make sure the message is for this project + var currentProject = this.get(`tab-session.${C.TABSESSION.PROJECT}`); + var metadata = socket.getMetadata(); + var socketProject = metadata.projectId; + if ( currentProject !== socketProject ) { + console.error(`Subscribe ignoring message, current=${currentProject} socket=${socketProject} ` + this.forStr()); + this.connectSubscribe(); + return; } - } - else if ( d.name === 'ping' ) - { - this._trySend('subscribePing', d); - } + + var d = JSON.parse(event.data); + let resource; + if ( d.data && d.data.resource ) { + resource = store._typeify(d.data.resource); + d.data.resource = resource; + } + + //this._trySend('subscribeMessage',d); + + if ( d.name === 'resource.change' ) + { + let key = d.resourceType+'Changed'; + if ( this[key] ) { + this[key](d); + } + + if ( resource && DEADTOME.contains(resource.state) ) { + store._remove(resource.type, resource); + } + } + else if ( d.name === 'service.kubernetes.change' ) + { + var changeType = (Ember.get(d, 'data.type')||'').toLowerCase(); + var obj = Ember.get(d, 'data.object'); + if ( changeType && obj ) + { + this.k8sResourceChanged(changeType, obj); + } + } + else if ( d.name === 'ping' ) + { + this.subscribePing(d); + } + }); }); socket.on('connected', (tries, after) => { - this._trySend('subscribeConnected', tries, after); + this.subscribeConnected(tries, after); }); socket.on('disconnected', () => { - this._trySend('subscribeDisconnected', this.get('tries')); + this.subscribeDisconnected(this.get('tries')); }); this.set('subscribeSocket', socket); @@ -107,153 +123,106 @@ export default Ember.Mixin.create({ return out; }, - actions: { - // Raw message from the WebSocket - //subscribeMessage: function(/*data*/) { - //console.log('subscribeMessage',data); - //}, + // WebSocket connected + subscribeConnected: function(tries,msec) { + this.set('connected', true); - // WebSocket connected - subscribeConnected: function(tries,msec) { - this.set('connected', true); - - let msg = 'Subscribe connected ' + this.forStr(); - if (tries > 0) + let msg = 'Subscribe connected ' + this.forStr(); + if (tries > 0) + { + msg += ' (after '+ tries + ' ' + (tries === 1 ? 'try' : 'tries'); + if (msec) { - msg += ' (after '+ tries + ' ' + (tries === 1 ? 'try' : 'tries'); - if (msec) - { - msg += ', ' + (msec/1000) + ' sec'; - } - - msg += ')'; + msg += ', ' + (msec/1000) + ' sec'; } - console.log(msg); - }, + msg += ')'; + } - // WebSocket disconnected (unexpectedly) - subscribeDisconnected: function() { - this.set('connected', false); + console.log(msg); + }, - console.log('Subscribe disconnected ' + this.forStr()); - if ( this.get('reconnect') ) { - this.connectSubscribe(); - } - }, + // WebSocket disconnected (unexpectedly) + subscribeDisconnected: function() { + this.set('connected', false); - subscribePing: function() { - console.log('Subscribe ping ' + this.forStr()); - }, - - hostChanged: function(change) { - // If the host has a physicalHostId, ensure it is in the machine's hosts array. - var host = change.data.resource; - var machine = this.get('store').getById('machine', host.get('physicalHostId')); - if ( machine ) - { - machine.get('hosts').addObject(host); - } - }, - - containerChanged: function(change) { - this._includeChanged('host', 'instances', 'hosts', change.data.resource); - }, - - virtualMachineChanged: function(change) { - this._includeChanged('host', 'instances', 'hosts', change.data.resource); - }, - - instanceChanged: function(change) { - this._includeChanged('host', 'instances', 'hosts', change.data.resource); - }, - - ipAddressChanged: function(change) { - this._includeChanged('host', 'ipAddresses', 'hosts', change.data.resource); -// this._includeChanged('container', 'container', 'ipAddresses', 'containers', change.data.resource); - }, - - loadBalancerTargetChanged: function(change) { - this._includeChanged('loadBalancer', 'loadBalancerTargets', 'loadBalancerId', change.data.resource); - }, - - loadBalancerChanged: function(change) { - var balancer = change.data.resource; - var config = balancer.get('loadBalancerConfig'); - var balancers = config.get('loadBalancers'); - if ( !balancers ) - { - balancers = []; - config.set('loadBalancers',balancers); - } - - if ( config.get('state') === 'removed' ) - { - balancers.removeObject(balancer); - } - else - { - balancers.addObject(balancer); - } - }, - - registryCredentialChanged: function(change) { - this._includeChanged('registry', 'credentials', 'registryId', change.data.resource); - }, - - loadBalancerServiceChanged: function(change) { - this._includeChanged('stack', 'services', 'stackId', change.data.resource); - }, - - dnsServiceChanged: function(change) { - this._includeChanged('stack', 'services', 'stackId', change.data.resource); - }, - - externalServiceChanged: function(change) { - this._includeChanged('stack', 'services', 'stackId', change.data.resource); - }, - - serviceChanged: function(change) { - this._includeChanged('stack', 'services', 'stackId', change.data.resource); - }, - - kubernetesServiceChanged: function(change) { - this._includeChanged('stack', 'services', 'stackId', change.data.resource); - }, - - k8sResourceChanged: function(changeType, obj) { - //console.log('k8s change', changeType, (obj && obj.metadata && obj.metadata.uid ? obj.metadata.uid : 'none')); - if ( obj && obj.metadata && obj.metadata.uid && this.get('k8sUidBlacklist').indexOf(obj.metadata.uid) >= 0 ) - { - //console.log('^-- Ignoring', changeType, 'for removed resource'); - return; - } - - var resource = this.get('k8s')._typeify(obj); - - if ( changeType === 'deleted' ) - { - this.get('k8sUidBlacklist').addObject(obj.metadata.uid); - this.get('store')._remove(resource.get('type'), resource); - } + console.log('Subscribe disconnected ' + this.forStr()); + if ( this.get('reconnect') ) { + this.connectSubscribe(); } }, - _trySend: function(/*arguments*/) { - try + subscribePing: function() { + console.log('Subscribe ping ' + this.forStr()); + }, + + ipAddressChanged: function(change) { + this._includeChanged('host', 'ipAddresses', 'hosts', change.data.resource); +// this._includeChanged('container', 'container', 'ipAddresses', 'containers', change.data.resource); + }, + + loadBalancerTargetChanged: function(change) { + this._includeChanged('loadBalancer', 'loadBalancerTargets', 'loadBalancerId', change.data.resource); + }, + + loadBalancerChanged: function(change) { + var balancer = change.data.resource; + var config = balancer.get('loadBalancerConfig'); + var balancers = config.get('loadBalancers'); + if ( !balancers ) { - this.send.apply(this,arguments); + balancers = []; + config.set('loadBalancers',balancers); } - catch (err) + + if ( config.get('state') === 'removed' ) { - if ( err instanceof Ember.Error && err.message.indexOf('Nothing handled the action') === 0 ) - { - // Don't care - } - else - { - throw err; - } + balancers.removeObject(balancer); + } + else + { + balancers.addObject(balancer); + } + }, + + registryCredentialChanged: function(change) { + this._includeChanged('registry', 'credentials', 'registryId', change.data.resource); + }, + + loadBalancerServiceChanged: function(change) { + this._includeChanged('stack', 'services', 'stackId', change.data.resource); + }, + + dnsServiceChanged: function(change) { + this._includeChanged('stack', 'services', 'stackId', change.data.resource); + }, + + externalServiceChanged: function(change) { + this._includeChanged('stack', 'services', 'stackId', change.data.resource); + }, + + serviceChanged: function(change) { + this._includeChanged('stack', 'services', 'stackId', change.data.resource); + }, + + kubernetesServiceChanged: function(change) { + this._includeChanged('stack', 'services', 'stackId', change.data.resource); + }, + + k8sResourceChanged: function(changeType, obj) { + //console.log('k8s change', changeType, (obj && obj.metadata && obj.metadata.uid ? obj.metadata.uid : 'none')); + if ( obj && obj.metadata && obj.metadata.uid && this.get('k8sUidBlacklist').indexOf(obj.metadata.uid) >= 0 ) + { + //console.log('^-- Ignoring', changeType, 'for removed resource'); + return; + } + + var resource = this.get('k8s')._typeify(obj); + + if ( changeType === 'deleted' ) + { + this.get('k8sUidBlacklist').addObject(obj.metadata.uid); + this.get('store')._remove(resource.get('type'), resource); } }, @@ -268,6 +237,8 @@ export default Ember.Mixin.create({ return; } + let start = (new Date().getTime()); + var changedId = changed.get('id'); var store = this.get('store'); @@ -342,5 +313,8 @@ export default Ember.Mixin.create({ } }).catch(() => {}); }); + + let diff = ((new Date()).getTime())-start; + console.log('includechanged:', resourceName, destProperty, expectedProperty, diff); }, }); diff --git a/app/models/host.js b/app/models/host.js index bc2657f68..5fbae7a6e 100644 --- a/app/models/host.js +++ b/app/models/host.js @@ -5,6 +5,15 @@ import { byId as serviceById } from 'ui/models/service'; import { formatMib } from 'ui/utils/util'; import C from 'ui/utils/constants'; +function getByInstanceId(store,id) { + let obj = store.getById('container', id); + if ( !obj ) { + obj = store.getById('virtualmachine', id); + } + + return obj; +} + var Host = Resource.extend({ type: 'host', @@ -78,10 +87,19 @@ var Host = Resource.extend({ }.property('actionLinks.{activate,deactivate,remove,purge,update}','machine','machine.links.config'), - instancesUpdated: 0, - onInstanceChanged: function() { - this.incrementProperty('instancesUpdated'); - }.observes('instances.@each.{id,name,state}','instances.length'), + instances: function() { + let out = []; + let store = this.get('store'); + + (this.get('instanceIds')||[]).forEach((id) => { + let obj = getByInstanceId(store,id); + if ( obj ) { + out.push(obj); + } + }); + + return out; + }.property('instanceIds.[]'), state: function() { var host = this.get('hostState'); @@ -233,20 +251,14 @@ var Host = Resource.extend({ endpoint.service = serviceById(endpoint.serviceId); } - if ( !endpoint.instance ) { - endpoint.instance = store.getById('container', endpoint.instanceId); - if ( !endpoint.instanceId ) { - endpoint.instance = store.getById('virtualmachine', endpoint.instanceId); - } - } - + endpoint.instance = getByInstanceId(store, endpoint.instanceId); return endpoint; }); }.property('publicEndpoints.@each.{ipAddress,port,serviceId,instanceId}'), }); Host.reopenClass({ - alwaysInclude: ['instances','ipAddresses'], + alwaysInclude: ['ipAddresses'], // Remap the host state to hostState so the regular state can be a computed combination of host+agent state. mangleIn: function(data) { diff --git a/app/models/machine.js b/app/models/machine.js index a3d6b3c65..1a8da5b57 100644 --- a/app/models/machine.js +++ b/app/models/machine.js @@ -70,19 +70,6 @@ var Machine = Resource.extend(PolledResource, { }); Machine.reopenClass({ - alwaysInclude: ['hosts'], - pollTransitioningDelay: 60000, - pollTransitioningInterval: 60000, - - mangleIn: function(data) { - if ( !data.hosts ) - { - data.hosts = []; - } - - return data; - }, - stateMap: { 'bootstrapping': {icon: 'icon icon-tag', color: 'text-info'}, 'active': {icon: 'icon icon-tag', color: 'text-info'}, diff --git a/app/models/storagepool.js b/app/models/storagepool.js index 44ae893fe..96b71df56 100644 --- a/app/models/storagepool.js +++ b/app/models/storagepool.js @@ -6,7 +6,7 @@ var StoragePool = Resource.extend({ }); StoragePool.reopenClass({ - alwaysInclude: ['hosts','volumes'], + alwaysInclude: ['volumes'], }); export default StoragePool; diff --git a/config/environment.js b/config/environment.js index 6457167d4..e3da8c1c4 100644 --- a/config/environment.js +++ b/config/environment.js @@ -101,9 +101,7 @@ module.exports = function(environment) { '?eventNames=resource.change' + '&eventNames=service.kubernetes.change' + '&limit=-1' + - '&include=hosts' + '&include=services' + - '&include=instances' + '&include=instance' + '&include=instanceLinks' + '&include=ipAddresses', diff --git a/package.json b/package.json index eff19efaa..f65493cf5 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "ember-cli-uglify": "^1.2.0", "ember-cli-test-loader": "^1.1.0", "ember-export-application-global": "^1.0.5", + "ember-href-to": "1.6.0", "ember-intl": "2.13.0", "ember-load-initializers": "^0.5.1", "ember-power-select": "1.0.0-beta.19",