This commit is contained in:
Vincent Fiduccia 2016-09-24 23:53:07 -07:00
parent 2939d59049
commit c35d2e7b52
17 changed files with 182 additions and 208 deletions

View File

@ -2,7 +2,7 @@
{{badge-state model=model}}
</td>
<td data-title="{{t 'generic.name'}}:" class="force-wrap">
{{#link-to detailRoute model.id}}{{model.displayName}}{{/link-to}}
<a href="{{href-to detailRoute model.id}}">{{model.displayName}}</a>
</td>
<td data-title="{{t 'containersPage.table.ipAddress'}}:">
{{format-ip ip=model.displayIp}}
@ -10,7 +10,7 @@
{{#if showHost}}
<td data-title="{{t 'containersPage.table.primaryHost'}}:">
{{#if model.primaryHost}}
{{#link-to "host" model.primaryHost.id}}{{model.primaryHost.displayName}}{{/link-to}}
<a href="{{href-to "host" model.primaryHost.id}}">{{model.primaryHost.displayName}}</a>
{{else}}
<span class="text-muted">{{t 'containersPage.table.primaryHostUnknown'}}</span>
{{/if}}

View File

@ -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() {

View File

@ -1,11 +1,11 @@
<div class="container-subpod">
<div class="subpod-name clip">
<i class="{{model.stateIcon}} {{model.stateColor}} dot "></i>
{{#link-to (if model.isVm "virtualmachine" "container") model.id classNameBindings="showEllipsis:tiny-hellip"}}
<a class="{{if showEllipsis 'tiny-hellip'}}" href="{{href-to (if model.isVm "virtualmachine" "container") model.id}}">
{{#tooltip-element tagName="span" inlineBlock=false type="tooltip-basic" model=model tooltipTemplate='tooltip-container-subpod' }}
{{displayName}}
{{/tooltip-element}}
{{/link-to}}
</a>
</div>
{{#if model.showTransitioningMessage}}
<div class="subpod-detail clip {{if model.isError 'text-danger'}}">

View File

@ -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() {

View File

@ -7,7 +7,7 @@
{{#if isMachine}}
{{model.displayName}}
{{else}}
{{#link-to "host" model.id}}{{model.displayName}}{{/link-to}}
<a href="{{href-to 'host' model.id}}">{{model.displayName}}</a>
{{#if model.showTransitioningMessage}}
<div class="pod-message {{if model.isError 'text-danger' 'text-muted'}}">
{{model.transitioningMessage}}

View File

@ -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'),

View File

@ -2,6 +2,10 @@
<i class="icon icon-globe"></i> {{selectedLabel}} <i class="icon icon-chevron-down"></i>
</a>
<ul class="dropdown-menu dropdown-menu-right text-right" role="menu">
{{#if settings.isRancher}}
<li><a href="http://translate.rancher.com" target="_blank" rel="noopener nofollow">{{t 'languageContribute'}}</a></li>
<li class="divider"></li>
{{/if}}
{{#each-in locales as |lang label|}}
<li class="{{if (eq selected lang) 'disabled selected'}}">
<a {{action 'selectLanguage' lang}}>
@ -9,8 +13,4 @@
</a>
</li>
{{/each-in}}
{{#if settings.isRancher}}
<li class="divider"></li>
<li><a href="http://translate.rancher.com" target="_blank" rel="noopener nofollow">{{t 'languageContribute'}}</a></li>
{{/if}}
</ul>

View File

@ -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}}
<a href="{{href-to 'authenticated.project.help' projectId}}" role="button" class="btn btn-sm btn-link">{{t 'pageFooter.help'}}</a>
{{/if}}
<a role="button" class="btn btn-sm btn-link" target="blank" href="{{settings.docsBase}}">{{t 'pageFooter.documentation'}}</a>
<a role="button" class="btn btn-sm btn-link" target="blank" href="{{settings.docsBase}}/faqs/">{{t 'pageFooter.faq'}}</a>

View File

@ -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'));

View File

@ -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;
});

View File

@ -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');

View File

@ -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);
},
});

View File

@ -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) {

View File

@ -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'},

View File

@ -6,7 +6,7 @@ var StoragePool = Resource.extend({
});
StoragePool.reopenClass({
alwaysInclude: ['hosts','volumes'],
alwaysInclude: ['volumes'],
});
export default StoragePool;

View File

@ -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',

View File

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