Merge pull request #294 from vincent99/k8s

k8s
This commit is contained in:
Vincent Fiduccia 2015-10-29 09:52:09 -07:00
commit 369c653084
17 changed files with 276 additions and 92 deletions

View File

@ -304,6 +304,15 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
serviceChanged: function(change) {
this._includeChanged('environment', 'services', 'environmentId', change.data.resource);
},
kubernetesServiceChanged: function(change) {
this._includeChanged('environment', 'services', 'environmentId', change.data.resource);
},
kubernetesReplicationControllerChanged: function(change) {
this._includeChanged('environment', 'services', 'environmentId', change.data.resource);
},
},
_trySend: function(/*arguments*/) {

View File

@ -23,44 +23,57 @@ export default Ember.Component.extend(ReadLabels, FasterLinksAndMenus, {
groupedInstances: function() {
var groups = [];
// Everything must be sorted first to guarantee that parents appear before sidekicks
(this.get('model.instances')||[]).sortBy('name','id').forEach((instance) => {
var labels = instance.get('labels')||{};
var isSidekick = !!labels[C.LABEL.LAUNCH_CONFIG] && labels[C.LABEL.LAUNCH_CONFIG] !== C.LABEL.LAUNCH_CONFIG_PRIMARY;
var parentUnit = labels[C.LABEL.DEPLOYMENT_UNIT];
var groupName = (instance.get('labels')||{})[C.LABEL.PROJECT_NAME] || '';
var entry, group;
if ( isSidekick && parentUnit )
function getOrCreateGroup(groupName)
{
var group = groups.filterBy('name', groupName)[0];
if ( !group )
{
group = groups.filterBy('name', groupName)[0];
if ( group )
{
entry = group.instances.filterBy('unit', parentUnit)[0];
if ( entry )
{
entry.children.push(instance);
group.hasChildren = true;
}
}
group = { name: groupName, instances: [], hasChildren: false };
groups.push(group);
}
return group;
}
function getOrCreateUnit(groupName, deploymentUnit)
{
var group = getOrCreateGroup(groupName);
var entry = group.instances.filterBy('unit', deploymentUnit)[0];
if ( !entry )
{
entry = {unit: deploymentUnit, main: null, children: []};
group.instances.push(entry);
}
return [group, entry];
}
(this.get('model.instances')||[]).forEach((instance) => {
var labels = instance.get('labels')||{};
var deploymentUnit = labels[C.LABEL.DEPLOYMENT_UNIT];
var isSidekick = deploymentUnit && labels[C.LABEL.LAUNCH_CONFIG] !== C.LABEL.LAUNCH_CONFIG_PRIMARY;
var groupName = (instance.get('labels')||{})[C.LABEL.PROJECT_NAME] || '';
//console.log(deploymentUnit, groupName, isSidekick, instance.get('id'), instance.get('name'));
let [group, unit] = getOrCreateUnit(groupName, deploymentUnit);
if ( isSidekick )
{
unit.children.push(instance);
group.hasChildren = true;
}
else
{
group = groups.filterBy('name', groupName)[0];
if ( !group )
{
group = { name: groupName, instances: [], hasChildren: false };
groups.push(group);
}
group.instances.push({unit: parentUnit, main: instance, children: []});
unit.main = instance;
}
});
groups = groups.sortBy('name');
if ( groups[0] && groups[0].name === '' )
{
// Move no name to the end of the list instead of the beginning
// Move no name/standalone containers to the end of the list instead of the beginning
groups.push(groups.shift());
}

View File

@ -165,15 +165,15 @@ export default Ember.Component.extend(NewOrEdit, {
return false;
}
var environments = {};
this.get('selectedTemplateModel.questions').forEach((item) => {
environments[item.variable] = item.answer;
var answers = {};
(this.get('selectedTemplateModel.questions')||[]).forEach((item) => {
answers[item.variable] = item.answer;
});
this.get('environmentResource').setProperties({
dockerCompose: this.get('selectedTemplateModel.dockerCompose'),
rancherCompose: this.get('selectedTemplateModel.rancherCompose'),
environment: environments,
environment: answers,
externalId: this.get('selectedTemplateModel.uuid')
});

View File

@ -101,7 +101,7 @@
</div>
</div>
{{else}}
<span class="text-muted">There are no configuration options for this application.</span>
<div class="text-muted text-center">There are no configuration options for this application.</div>
{{/each}}
<div class="over-hr r-mt20 r-mb20">

View File

@ -23,52 +23,67 @@ export default Ember.Component.extend(ReadLabels, FasterLinksAndMenus, {
isInactive: Ember.computed.equal('model.state','inactive'),
hasContainers: function() {
return ['service','loadbalancerservice'].indexOf(this.get('model.type').toLowerCase()) !== -1;
}.property('model.type'),
arrangedInstances: function() {
return (this.get('model.instances')||[]).sortBy('name','id');
}.property('model.instances.@each.{name,id}'),
groupedInstances: function() {
var instances = [];
var groups = [];
// Everything must be sorted first to guarantee that parents appear before sidekicks
this.get('arrangedInstances').forEach((instance) => {
var labels = instance.get('labels')||{};
var isSidekick = !!labels[C.LABEL.LAUNCH_CONFIG] && labels[C.LABEL.LAUNCH_CONFIG] !== C.LABEL.LAUNCH_CONFIG_PRIMARY;
var parentUnit = labels[C.LABEL.DEPLOYMENT_UNIT];
var groupName = parentUnit;
var entry, group;
if ( isSidekick && parentUnit )
function getOrCreateGroup(groupName)
{
var group = groups.filterBy('name', groupName)[0];
if ( !group )
{
group = instances.filterBy('name', groupName)[0];
if ( group )
{
entry = group.instances.filterBy('unit', parentUnit)[0];
if ( entry )
{
entry.children.push(instance);
group.hasChildren = true;
}
}
group = { name: groupName, instances: [], hasChildren: false };
groups.push(group);
}
return group;
}
function getOrCreateUnit(groupName, deploymentUnit)
{
var group = getOrCreateGroup(groupName);
var entry = group.instances.filterBy('unit', deploymentUnit)[0];
if ( !entry )
{
entry = {unit: deploymentUnit, main: null, children: []};
group.instances.push(entry);
}
return [group, entry];
}
(this.get('model.instances')||[]).forEach((instance) => {
var labels = instance.get('labels')||{};
var deploymentUnit = labels[C.LABEL.DEPLOYMENT_UNIT];
var isSidekick = deploymentUnit && labels[C.LABEL.LAUNCH_CONFIG] !== C.LABEL.LAUNCH_CONFIG_PRIMARY;
var groupName = deploymentUnit;
//console.log(deploymentUnit, groupName, isSidekick, instance.get('id'), instance.get('name'));
let [group, unit] = getOrCreateUnit(groupName, deploymentUnit);
if ( isSidekick )
{
unit.children.push(instance);
group.hasChildren = true;
}
else
{
group = instances.filterBy('name', groupName)[0];
if ( !group )
{
group = { name: groupName, instances: [], hasChildren: false };
instances.push(group);
}
group.instances.push({unit: parentUnit, main: instance, children: []});
unit.main = instance;
}
});
return instances;
groups = groups.sortBy('name');
if ( groups[0] && groups[0].name === '' )
{
// Move no name/standalone containers to the end of the list instead of the beginning
groups.push(groups.shift());
}
return groups;
}.property('model.instances.@each.{name,id}'),
hasChildren: function() {
@ -76,7 +91,7 @@ export default Ember.Component.extend(ReadLabels, FasterLinksAndMenus, {
}.property('groupedInstances.@each.hasChildren'),
showScaleUp: function() {
if ( this.get('isActive') && this.get('hasContainers') )
if ( this.get('isActive') && this.get('model.hasContainers') && this.get('model.canScale') )
{
return this.getLabel(C.LABEL.SCHED_GLOBAL) === null;
}
@ -101,4 +116,13 @@ export default Ember.Component.extend(ReadLabels, FasterLinksAndMenus, {
return color;
}
}.property('model.stateColor'),
iconLabel: function() {
switch ( this.get('model.type').toLowerCase() ) {
case 'kubernetesreplicationcontroller': return 'Controller';
case 'kubernetesservice': return 'Service';
default: return '';
}
}.property('model.type'),
});

View File

@ -4,7 +4,7 @@
</div>
<div class="pod-state {{stateBackground}}"><span>{{model.displayState}}</span></div>
<div class="pod-icon"><i class="{{model.stateIcon}} icon-lg fa-lg {{iconColor}}"></i></div>
<div class="pod-icon"><i class="{{model.stateIcon}} icon-lg fa-lg {{iconColor}}"></i> {{iconLabel}}</div>
<div class="pod-name">
{{#link-to "service" model.environmentId model.id}}{{model.displayName}}{{/link-to}}
{{#if model.showTransitioningMessage}}
@ -49,7 +49,7 @@
</div>
{{/if}}
{{#if hasContainers}}
{{#if model.hasContainers}}
<div class="clearfix {{if (eq mode "dot") 'r-p5'}}">
{{#if (eq mode "dot")}}
{{#each arrangedInstances as |item|}}

View File

@ -1,12 +1,19 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
import { parseExternalId } from 'ui/utils/parse-externalid';
export default Ember.Component.extend({
model: null,
collapseId: null,
classNames: ['pod','project'],
classNameBindings: ['stateBorder'],
classNameBindings: ['stateBorder','isKubernetes:kubernetes'],
isKubernetes: function() {
var parts = parseExternalId(this.get('model.externalId'));
return parts && parts.kind === C.EXTERNALID.KIND_KUBERNETES;
}.property('model.externalId'),
stateBorder: function() {
return this.get('model.stateColor').replace("text-","border-top-");

View File

@ -1,5 +1,7 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
import { ajaxPromise } from 'ember-api-store/utils/ajax-promise';
import { parseExternalId } from 'ui/utils/parse-externalid';
const NONE = 'none',
LOADING = 'loading',
@ -86,13 +88,14 @@ export default Ember.Component.extend({
}.property('upgradeStatus'),
updateStatus() {
var uuid = this.get('environmentResource.externalId');
if ( uuid )
var info = parseExternalId(this.get('environmentResource.externalId'));
if ( info && info.kind === C.EXTERNALID.KIND_CATALOG )
{
this.set('upgradeStatus', LOADING);
queue.push({
url: this.get('app.catalogEndpoint')+'/upgradeinfo/'+ uuid,
uuid: uuid, obj: this
url: this.get('app.catalogEndpoint')+'/upgradeinfo/'+ info.id,
obj: this
});
}
else

View File

@ -0,0 +1,7 @@
import Service from 'ui/models/service';
var KubernetesReplicationController = Service.extend({
type: 'kubernetesReplicationController',
});
export default KubernetesReplicationController;

View File

@ -0,0 +1,7 @@
import Service from 'ui/models/service';
var KubernetesService = Service.extend({
type: 'kubernetesService',
});
export default KubernetesService;

View File

@ -8,6 +8,8 @@ var _allRegularServices;
var _allLbServices;
var _allExternalServices;
var _allDnsServices;
var _allKubernetesServices;
var _allKubernetesReplicationControllers;
var Service = Resource.extend(ReadLabels, {
type: 'service',
@ -128,12 +130,13 @@ var Service = Resource.extend(ReadLabels, {
var a = this.get('actionLinks');
var canUpgrade = !!a.upgrade && this.get('type') === 'service';
var isK8s = this.get('isK8s');
var choices = [
{ label: 'Start', icon: 'icon icon-play', action: 'activate', enabled: !!a.activate, color: 'text-success'},
{ label: 'Stop', icon: 'icon icon-pause', action: 'deactivate', enabled: !!a.deactivate, color: 'text-danger'},
{ label: 'Delete', icon: 'icon icon-trash', action: 'promptDelete', enabled: !!a.remove, altAction: 'delete', color: 'text-warning' },
{ label: 'Purge', icon: '', action: 'purge', enabled: !!a.purge },
{ label: 'Start', icon: 'icon icon-play', action: 'activate', enabled: !!a.activate && !isK8s, color: 'text-success'},
{ label: 'Stop', icon: 'icon icon-pause', action: 'deactivate', enabled: !!a.deactivate && !isK8s, color: 'text-danger'},
{ label: 'Delete', icon: 'icon icon-trash', action: 'promptDelete', enabled: !!a.remove && !isK8s, altAction: 'delete', color: 'text-warning' },
{ label: 'Purge', icon: '', action: 'purge', enabled: !!a.purge && !isK8s },
{ divider: true },
{ label: 'Upgrade', icon: 'fa fa-arrow-circle-o-up',action: 'upgrade', enabled: canUpgrade },
{ label: 'Finish Upgrade', icon: 'fa fa-thumbs-o-up', action: 'finishUpgrade', enabled: !!a.finishupgrade },
@ -142,12 +145,12 @@ var Service = Resource.extend(ReadLabels, {
{ label: 'Cancel Rollback', icon: 'fa fa-life-ring', action: 'cancelRollback', enabled: !!a.cancelrollback },
{ divider: true },
{ label: 'View in API', icon: 'icon icon-externallink', action: 'goToApi', enabled: true },
{ label: 'Clone', icon: 'icon icon-copy', action: 'clone', enabled: true },
{ label: 'Edit', icon: 'icon icon-edit', action: 'edit', enabled: !!a.update },
{ label: 'Clone', icon: 'icon icon-copy', action: 'clone', enabled: !isK8s },
{ label: 'Edit', icon: 'icon icon-edit', action: 'edit', enabled: !!a.update && !isK8s },
];
return choices;
}.property('actionLinks.{activate,deactivate,update,remove,purge,finishupgrade,cancelupgrade,rollback,cancelrollback}','type'),
}.property('actionLinks.{activate,deactivate,update,remove,purge,finishupgrade,cancelupgrade,rollback,cancelrollback}','type','isK8s'),
_allMaps: null,
@ -155,11 +158,27 @@ var Service = Resource.extend(ReadLabels, {
_allLbServices: null,
_allExternalServices: null,
_allDnsServices: null,
_allKubernetesServices: null,
_allKubernetesReplicationControllers: null,
consumedServicesUpdated: 0,
consumedByServicesUpdated: 0,
serviceLinks: null, // Used for clone
reservedKeys: ['_allMaps','_allRegularServices','_allLbServices','_allExternalServices','_allDnsServices','consumedServices','consumedServicesUpdated','serviceLinks','_environment','_environmentState'],
reservedKeys: [
'_allMaps',
'_allRegularServices',
'_allLbServices',
'_allExternalServices',
'_allDnsServices',
'_allKubernetesServices',
'_allKubernetesReplicationControllers',
'consumedServices',
'consumedServicesUpdated',
'serviceLinks',
'_environment',
'_environmentState'
],
labelResource: Ember.computed.alias('launchConfig'),
init: function() {
@ -193,13 +212,25 @@ var Service = Resource.extend(ReadLabels, {
_allDnsServices = this.get('store').allUnremoved('dnsservice');
}
if ( !_allKubernetesServices )
{
_allKubernetesServices = this.get('store').allUnremoved('kubernetesservice');
}
if ( !_allKubernetesReplicationControllers )
{
_allKubernetesReplicationControllers = this.get('store').allUnremoved('kubernetesreplicationcontroller');
}
// And we need this here so that consumedServices can watch for changes
this.setProperties({
'_allMaps': _allMaps,
'_allRegularServices': _allRegularServices,
'_allLbServices': _allLbServices,
'_allExternalServices': _allExternalServices,
'_allDnsServices': _allDnsServices
'_allDnsServices': _allDnsServices,
'_allKubernetesServices': _allKubernetesServices,
'_allKubernetesReplicationControllers': _allKubernetesReplicationControllers,
});
},
@ -243,7 +274,6 @@ var Service = Resource.extend(ReadLabels, {
consumedServicesWithNames: function() {
var out = Service.consumedServicesFor(this.get('id'));
console.log('Consumed for', this.get('id'), out.get('length'));
return out;
}.property('id','_allMaps.@each.{name,serviceId,consumedServiceId}','state'),
@ -319,7 +349,12 @@ var Service = Resource.extend(ReadLabels, {
}.property('type'),
hasContainers: function() {
return ['service','loadbalancerservice'].indexOf(this.get('type').toLowerCase()) >= 0;
return [
'service',
'loadbalancerservice',
'kubernetesservice',
'kubernetesreplicationcontroller'
].indexOf(this.get('type').toLowerCase()) >= 0;
}.property('type'),
hasImage: function() {
@ -327,6 +362,10 @@ var Service = Resource.extend(ReadLabels, {
}.property('type'),
hasLabels: Ember.computed.alias('hasImage'),
isK8s: function() {
return ['kubernetesservice','kubernetesreplicationcontroller'].indexOf(this.get('type').toLowerCase()) >= 0;
}.property('type'),
displayType: function() {
var out;
switch ( this.get('type').toLowerCase() )
@ -334,6 +373,8 @@ var Service = Resource.extend(ReadLabels, {
case 'loadbalancerservice': out = 'Load Balancer'; break;
case 'dnsservice': out = 'DNS'; break;
case 'externalservice': out = 'External'; break;
case 'kubernetesservice': out = 'K8s Service'; break;
case 'kubernetesreplicationcontroller': out = 'K8s Replication Controller'; break;
default: out = 'Container'; break;
}
@ -354,13 +395,24 @@ export function activeIcon(service)
case 'loadbalancerservice': out = 'icon icon-fork'; break;
case 'dnsservice': out = 'icon icon-compass'; break;
case 'externalservice': out = 'icon icon-cloud'; break;
case 'kubernetesservice':
case 'kubernetesreplicationcontroller':
out = 'icon icon-kubernetes'; break;
}
return out;
}
export function byId(serviceId) {
var allTypes = [_allRegularServices, _allLbServices, _allExternalServices, _allDnsServices];
var allTypes = [
_allRegularServices,
_allLbServices,
_allExternalServices,
_allDnsServices,
_allKubernetesServices,
_allKubernetesReplicationControllers
];
var i = 0;
var service = null;
while ( i < allTypes.length && !service )

View File

@ -11,26 +11,26 @@ export default Resource.extend({
var consumer = byId(this.get('serviceId'));
if ( consumer )
{
console.log('Update consumer', this.get('serviceId'), '->', this.get('consumedServiceId'));
//console.log('Update consumer', this.get('serviceId'), '->', this.get('consumedServiceId'));
consumer.propertyDidChange('consumedServicesWithNames');
}
else
{
console.log('The consumer service', this.get('serviceId'), 'does not exist yet');
//console.log('The consumer service', this.get('serviceId'), 'does not exist yet');
}
var consumed = byId(this.get('consumedServiceId'));
if ( consumed )
{
console.log('Update consumed', this.get('serviceId'), '->', this.get('consumedServiceId'));
//console.log('Update consumed', this.get('serviceId'), '->', this.get('consumedServiceId'));
consumed.propertyDidChange('consumedServicesWithNames');
}
else
{
console.log('The *consumed* service', this.get('consumedServiceId'), 'does not exist yet');
//console.log('The *consumed* service', this.get('consumedServiceId'), 'does not exist yet');
}
} catch(e) {
console.log('Err:', e);
//console.log('Err:', e);
}
});
}.on('init')

View File

@ -5,6 +5,10 @@
background-size: 50px;
height: 95px;
&.kubernetes {
background-image: url('images/hexagon-kubernetes.svg');
}
H4, H6 {
padding-left: 90px;
}

View File

@ -89,6 +89,14 @@ var C = {
LAUNCH_CONFIG: 'io.rancher.service.launch.config',
LAUNCH_CONFIG_PRIMARY: 'io.rancher.service.primary.launch.config',
},
EXTERNALID: {
KIND_SEPARATOR: '://',
GROUP_SEPARATOR: '/',
KIND_CATALOG: 'catalog',
KIND_KUBERNETES: 'kubernetes',
CATALOG_DEFAULT_GROUP: 'library',
},
};
C.TOKEN_TO_SESSION_KEYS = [

View File

@ -0,0 +1,44 @@
import C from 'ui/utils/constants';
// Parses externalIds on services into
// {
// kind: what kind of id this is supposed to be
// group: for catalog, what group it's in
// id: the actual external id
export function parseExternalId(externalId) {
if ( !externalId )
{
return null;
}
var idx = externalId.indexOf(C.EXTERNALID.KIND_SEPARATOR);
var out = {
kind: C.EXTERNALID.KIND_CATALOG,
group: null,
id: null,
};
if ( idx >= 0 )
{
out.kind = externalId.substr(0,idx);
var rest = externalId.substr(idx + C.EXTERNALID.KIND_SEPARATOR.length);
idx = rest.indexOf(C.EXTERNALID.GROUP_SEPARATOR);
if ( idx >= 0 )
{
out.group = rest.substr(0,idx);
out.id = rest.substr(idx + C.EXTERNALID.GROUP_SEPARATOR.length );
}
else
{
if ( out.kind === C.EXTERNALID.KIND_CATALOG )
{
out.group = C.EXTERNALID.CATALOG_DEFAULT_GROUP;
}
out.id = rest;
}
return out;
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

2
vendor/icons vendored

@ -1 +1 @@
Subproject commit 511cb9092af8d996bdef70baa00b5d08204ffd3b
Subproject commit 7dcf9b5f94a98563b070a72f65a4b132722a9fad