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.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",