mirror of https://github.com/rancher/ui.git
Wait for K8S to be ready
This commit is contained in:
parent
185e46d773
commit
0f34c09181
|
|
@ -3,6 +3,7 @@ import C from 'ui/utils/constants';
|
|||
|
||||
export default Ember.Controller.extend({
|
||||
settings: Ember.inject.service(),
|
||||
projects: Ember.inject.service(),
|
||||
|
||||
queryParams: ['backToAdd'],
|
||||
backToAdd: false,
|
||||
|
|
@ -30,7 +31,6 @@ export default Ember.Controller.extend({
|
|||
}
|
||||
|
||||
if (this.get('backToAdd')) {
|
||||
|
||||
propsOut[C.SETTING.API_HOST] = model.host;
|
||||
} else {
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ export default Ember.Controller.extend({
|
|||
|
||||
if (this.get('backToAdd')) {
|
||||
|
||||
this.transitionToRoute('hosts.new');
|
||||
this.transitionToRoute('hosts.new', this.get('projects.current.id'));
|
||||
} else {
|
||||
|
||||
this.send('goToPrevious');
|
||||
|
|
|
|||
|
|
@ -11,4 +11,13 @@ export default Ember.Controller.extend({
|
|||
hasKubernetes: false,
|
||||
hasSystem: false,
|
||||
hasVm: Ember.computed.alias('settings.hasVm'),
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
this.k8sChanged();
|
||||
},
|
||||
|
||||
k8sChanged: function() {
|
||||
this.set('hasKubernetes', !!this.get('projects.current.kubernetes'));
|
||||
}.observes('projects.current.kubernetes'),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,14 +4,11 @@ export default Ember.Route.extend({
|
|||
projects: Ember.inject.service(),
|
||||
|
||||
redirect() {
|
||||
this.get('projects').selectDefault().then((project) => {
|
||||
if ( project ) {
|
||||
this.replaceWith('authenticated.project', project.get('id'));
|
||||
} else {
|
||||
this.replaceWith('settings.projects');
|
||||
}
|
||||
}).catch(() => {
|
||||
var project = this.get('projects.current');
|
||||
if ( project ) {
|
||||
this.replaceWith('authenticated.project', project.get('id'));
|
||||
} else {
|
||||
this.replaceWith('settings.projects');
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,50 +1,31 @@
|
|||
import Ember from 'ember';
|
||||
import Socket from 'ui/utils/socket';
|
||||
import Util from 'ui/utils/util';
|
||||
import C from 'ui/utils/constants';
|
||||
import { hasThings } from 'ui/authenticated/project/controller';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
k8s : Ember.inject.service(),
|
||||
prefs : Ember.inject.service(),
|
||||
projects : Ember.inject.service(),
|
||||
access : Ember.inject.service(),
|
||||
userTheme : Ember.inject.service('user-theme'),
|
||||
|
||||
socket : null,
|
||||
pingTimer : null,
|
||||
k8sUidBlacklist: null,
|
||||
|
||||
model(params, transition) {
|
||||
if ( !params.project_id )
|
||||
var project = this.modelFor('authenticated').project;
|
||||
if ( !project )
|
||||
{
|
||||
// If there isn't a project, pick one
|
||||
return this.get('projects').selectDefault().then((project) => {
|
||||
if ( project )
|
||||
{
|
||||
this.replaceWith('authenticated.project', project.get('id'));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.replaceWith('settings.projects');
|
||||
}
|
||||
}).catch(() => {
|
||||
this.replaceWith('settings.projects');
|
||||
});
|
||||
this.replaceWith('settings.projects');
|
||||
return;
|
||||
}
|
||||
|
||||
return this.loadProject(params.project_id).then((project) => {
|
||||
this.set(`tab-session.${C.TABSESSION.PROJECT}`, project.get('id'));
|
||||
this.get('projects').setCurrent(project);
|
||||
// If the project ID in the URL is out of sync somehow, bail
|
||||
if ( project.get('id') !== params.project_id )
|
||||
{
|
||||
this.replaceWith('authenticated');
|
||||
return;
|
||||
}
|
||||
|
||||
return this.loadSchemas().then(() => {
|
||||
return this.loadStacks().then((stacks) => {
|
||||
hasThings(stacks, project, window.lc('authenticated'));
|
||||
return this.loadSchemas().then(() => {
|
||||
return this.loadStacks().then((stacks) => {
|
||||
hasThings(stacks, project, window.lc('authenticated'));
|
||||
|
||||
return Ember.Object.create({
|
||||
project: project,
|
||||
stacks: stacks,
|
||||
});
|
||||
return Ember.Object.create({
|
||||
project: project,
|
||||
stacks: stacks,
|
||||
});
|
||||
});
|
||||
}).catch((err) => {
|
||||
|
|
@ -65,10 +46,6 @@ export default Ember.Route.extend({
|
|||
return ret;
|
||||
},
|
||||
|
||||
loadProject(id) {
|
||||
return this.get('store').find('project', id);
|
||||
},
|
||||
|
||||
loadSchemas() {
|
||||
var store = this.get('store');
|
||||
store.resetType('schema');
|
||||
|
|
@ -79,345 +56,4 @@ export default Ember.Route.extend({
|
|||
return this.get('store').findAllUnremoved('environment');
|
||||
},
|
||||
|
||||
activate() {
|
||||
this._super();
|
||||
|
||||
console.log('Activate socket for', this.get(`tab-session.${C.TABSESSION.PROJECT}`));
|
||||
var store = this.get('store');
|
||||
var boundTypeify = store._typeify.bind(store);
|
||||
|
||||
if ( !this.get('k8sUidBlacklist') )
|
||||
{
|
||||
this.set('k8sUidBlacklist', []);
|
||||
}
|
||||
|
||||
var url = "ws://"+window.location.host + this.get('app.wsEndpoint');
|
||||
|
||||
url = Util.addQueryParam(url, 'projectId', this.get(`tab-session.${C.TABSESSION.PROJECT}`));
|
||||
var socket = Socket.create({
|
||||
url: url
|
||||
});
|
||||
this.set('socket', socket);
|
||||
|
||||
socket.on('message', (event) => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
else if ( d.name === 'ping' )
|
||||
{
|
||||
this._trySend('subscribePing', d);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('connected', (tries, after) => {
|
||||
this._trySend('subscribeConnected', tries, after);
|
||||
});
|
||||
|
||||
socket.on('disconnected', () => {
|
||||
this._trySend('subscribeDisconnected', this.get('tries'));
|
||||
});
|
||||
|
||||
socket.connect();
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
this._super();
|
||||
this.closeSocket();
|
||||
},
|
||||
|
||||
resetController() {
|
||||
this._super();
|
||||
this.closeSocket();
|
||||
},
|
||||
|
||||
closeSocket() {
|
||||
var socket = this.get('socket');
|
||||
if ( socket )
|
||||
{
|
||||
socket.disconnect();
|
||||
this.set('socket', null);
|
||||
}
|
||||
|
||||
Ember.run.cancel(this.get('pingTimer'));
|
||||
},
|
||||
|
||||
actions: {
|
||||
// Raw message from the WebSocket
|
||||
//subscribeMessage: function(/*data*/) {
|
||||
//console.log('subscribeMessage',data);
|
||||
//},
|
||||
|
||||
// WebSocket connected
|
||||
subscribeConnected: function(tries,msec) {
|
||||
var msg = 'Subscribe connected';
|
||||
if (tries > 0)
|
||||
{
|
||||
msg += ' (after '+ tries + ' ' + (tries === 1 ? 'try' : 'tries');
|
||||
if (msec)
|
||||
{
|
||||
msg += ', ' + (msec/1000) + ' sec';
|
||||
}
|
||||
|
||||
msg += ')';
|
||||
}
|
||||
console.log(msg);
|
||||
},
|
||||
|
||||
// WebSocket disconnected
|
||||
subscribeDisconnected: function() {
|
||||
console.log('Subscribe disconnected');
|
||||
this.closeSocket();
|
||||
},
|
||||
|
||||
subscribePing: function() {
|
||||
console.log('Subscribe ping');
|
||||
if ( this.get('pingTimer') )
|
||||
{
|
||||
Ember.run.cancel(this.get('pingTimer'));
|
||||
}
|
||||
|
||||
this.set('pingTimer', Ember.run.later(this, function() {
|
||||
console.log('Subscribe missed 2 pings...');
|
||||
if ( this.get('socket') )
|
||||
{
|
||||
this.get('socket').connect();
|
||||
}
|
||||
}, 11000));
|
||||
},
|
||||
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
mountChanged: function(change) {
|
||||
var mount = change.data.resource;
|
||||
var volume = this.get('store').getById('volume', mount.get('volumeId'));
|
||||
if ( volume )
|
||||
{
|
||||
var mounts = volume.get('mounts');
|
||||
if ( !Ember.isArray(mounts) )
|
||||
{
|
||||
mounts = [];
|
||||
volume.set('mounts',mounts);
|
||||
}
|
||||
|
||||
var existingMount = mounts.filterBy('id', mount.get('id')).get('firstObject');
|
||||
if ( existingMount )
|
||||
{
|
||||
existingMount.setProperties(mount);
|
||||
}
|
||||
else
|
||||
{
|
||||
mounts.pushObject(mount);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
registryCredentialChanged: function(change) {
|
||||
this._includeChanged('registry', 'credentials', 'registryId', change.data.resource);
|
||||
},
|
||||
|
||||
loadBalancerServiceChanged: function(change) {
|
||||
this._includeChanged('environment', 'services', 'environmentId', change.data.resource);
|
||||
},
|
||||
|
||||
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) {
|
||||
this._includeChanged('environment', 'services', 'environmentId', change.data.resource);
|
||||
},
|
||||
|
||||
kubernetesServiceChanged: function(change) {
|
||||
this._includeChanged('environment', 'services', 'environmentId', 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').pushObject(obj.metadata.uid);
|
||||
this.get('store')._remove(resource.get('type'), resource);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_trySend: function(/*arguments*/) {
|
||||
try
|
||||
{
|
||||
this.send.apply(this,arguments);
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
if ( err instanceof Ember.Error && err.message.indexOf('Nothing handled the action') === 0 )
|
||||
{
|
||||
// Don't care
|
||||
}
|
||||
else
|
||||
{
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Update the `?include=`-ed arrays of a host,
|
||||
// e.g. when an instance changes:
|
||||
// Update the destProperty='instances' array on all models of type resourceName='hosts'.
|
||||
// to match the list in the the 'changed' resource's expectedProperty='hosts'
|
||||
// _includeChanged( 'host', 'hosts', 'instances', 'hosts', instance)
|
||||
_includeChanged: function(resourceName, destProperty, expectedProperty, changed) {
|
||||
if (!changed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var changedId = changed.get('id');
|
||||
var store = this.get('store');
|
||||
|
||||
//console.log('Include changed',resourceName,destProperty,expectedProperty,changedId);
|
||||
|
||||
// All the resources
|
||||
var all = store.all(resourceName);
|
||||
|
||||
// IDs the resource should be on
|
||||
var expectedIds = [];
|
||||
var expected = changed.get(expectedProperty)||[];
|
||||
if ( !Ember.isArray(expected) )
|
||||
{
|
||||
expected = [expected];
|
||||
}
|
||||
|
||||
if ( changed.get('state') !== 'purged' )
|
||||
{
|
||||
expectedIds = expected.map(function(item) {
|
||||
if ( typeof item === 'object' )
|
||||
{
|
||||
return item.get('id');
|
||||
}
|
||||
else
|
||||
{
|
||||
return item;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// IDs it is currently on
|
||||
var curIds = [];
|
||||
all.forEach(function(item) {
|
||||
var existing = (item.get(destProperty)||[]).filterBy('id', changedId);
|
||||
if ( existing.length )
|
||||
{
|
||||
curIds.push(item.get('id'));
|
||||
}
|
||||
});
|
||||
|
||||
// Remove from resources the changed shouldn't be on
|
||||
var remove = Util.arrayDiff(curIds, expectedIds);
|
||||
remove.forEach((id) => {
|
||||
//console.log('Remove',id);
|
||||
store.find(resourceName, id).then((item) => {
|
||||
var list = item.get(destProperty);
|
||||
if ( list )
|
||||
{
|
||||
//console.log('Removing',changedId,'from',item.get('id'));
|
||||
list.removeObjects(list.filterBy('id', changedId));
|
||||
}
|
||||
}).catch(() => {});
|
||||
});
|
||||
|
||||
// Add or update resources the changed should be on
|
||||
expectedIds.forEach((id) => {
|
||||
//console.log('Expect',id);
|
||||
store.find(resourceName, id).then((item) => {
|
||||
var list = item.get(destProperty);
|
||||
if ( !list )
|
||||
{
|
||||
list = [];
|
||||
//console.log('Adding empty to',item.get('id'), destProperty);
|
||||
item.set(destProperty, list);
|
||||
}
|
||||
|
||||
var existing = list.filterBy('id', changedId);
|
||||
if ( existing.length === 0)
|
||||
{
|
||||
//console.log('Adding',changedId,'to',item.get('id'), destProperty);
|
||||
list.pushObject(changed);
|
||||
}
|
||||
}).catch(() => {});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import Ember from 'ember';
|
||||
import C from 'ui/utils/constants';
|
||||
import Service from 'ui/models/service';
|
||||
import Subscribe from 'ui/mixins/subscribe';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
export default Ember.Route.extend(Subscribe, {
|
||||
prefs : Ember.inject.service(),
|
||||
projects : Ember.inject.service(),
|
||||
k8s : Ember.inject.service(),
|
||||
|
|
@ -29,26 +30,35 @@ export default Ember.Route.extend({
|
|||
preferences: this.loadPreferences(),
|
||||
settings: this.loadPublicSettings(),
|
||||
}).then((hash) => {
|
||||
var projectId = null;
|
||||
if ( transition.params && transition.params['authenticated.project'] && transition.params['authenticated.project'].project_id )
|
||||
{
|
||||
return hash;
|
||||
projectId = transition.params['authenticated.project'].project_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not going to a project-specific page, make sure a project is selected
|
||||
return this.get('projects').selectDefault().then(() => {
|
||||
return hash;
|
||||
|
||||
// Make sure a valid project is selected
|
||||
return this.get('projects').selectDefault(projectId).then((project) => {
|
||||
hash.project = project;
|
||||
return this.loadKubernetes(project, hash).then((out) => {
|
||||
return Ember.Object.create(out);
|
||||
});
|
||||
}
|
||||
});
|
||||
}).catch((err) => {
|
||||
return this.loadingError(err, transition, Ember.Object.create({
|
||||
projects: [],
|
||||
project: null,
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
activate() {
|
||||
this._super();
|
||||
this.connectSubscribe();
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
this._super();
|
||||
this.disconnectSubscribe();
|
||||
|
||||
// Forget all the things
|
||||
this.reset();
|
||||
|
|
@ -81,6 +91,36 @@ export default Ember.Route.extend({
|
|||
});
|
||||
},
|
||||
|
||||
loadKubernetes(project, hash) {
|
||||
hash = hash || {};
|
||||
|
||||
if ( !project.get('kubernetes') )
|
||||
{
|
||||
hash.kubernetesReady = false;
|
||||
return Ember.RSVP.resolve(hash);
|
||||
}
|
||||
|
||||
var svc = this.get('k8s');
|
||||
return svc.isReady().then((ready) => {
|
||||
if ( ready )
|
||||
{
|
||||
return this.get('k8s').allNamespaces().then((all) => {
|
||||
return this.get('k8s').selectNamespace().then((ns) => {
|
||||
hash.kubernetesReady = true;
|
||||
hash.namespaces = all;
|
||||
hash.namespace = ns;
|
||||
return hash;
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
hash.kubernetesReady = false;
|
||||
return Ember.RSVP.resolve(hash);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
loadProjects() {
|
||||
var svc = this.get('projects');
|
||||
return svc.getAll().then((all) => {
|
||||
|
|
@ -126,6 +166,13 @@ export default Ember.Route.extend({
|
|||
this.refresh();
|
||||
},
|
||||
|
||||
refreshKubernetes() {
|
||||
var model = this.get('controller.model');
|
||||
this.loadKubernetes(model.get('project')).then((hash) => {
|
||||
model.setProperties(hash);
|
||||
});
|
||||
},
|
||||
|
||||
switchNamespace(namespaceId) {
|
||||
var route = window.lc('application').get('currentRouteName');
|
||||
var okRoutes = [
|
||||
|
|
|
|||
|
|
@ -136,11 +136,13 @@ export default Ember.Component.extend({
|
|||
var requestLine='';
|
||||
if ( path )
|
||||
{
|
||||
requestLine = method + ' ' + path + ' ' + version;
|
||||
requestLine = method + ' ' + path + ' "' + version;
|
||||
if ( host )
|
||||
{
|
||||
requestLine += '\r\nHost:\\ ' + host;
|
||||
requestLine += '\r\nHost: ' + host;
|
||||
}
|
||||
|
||||
requestLine += '"';
|
||||
}
|
||||
this.set('healthCheck.requestLine', requestLine);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if isKubernetesTab}}
|
||||
{{#if (and isKubernetesTab k8s.namespace)}}
|
||||
<div class="dropdown btn-group project-btn pull-right">
|
||||
<button type="button" class="btn btn-link dropdown-toggle text-left clip" data-toggle="dropdown" aria-expanded="false">
|
||||
<i class="icon icon-thumbnails icon-fw"></i> {{k8s.namespace.displayName}}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ export default Ember.Component.extend(NewOrEdit, Sortable, {
|
|||
doneSaving: function() {
|
||||
var out = this._super();
|
||||
this.get('projects').refreshAll();
|
||||
this.get('router').transitionTo('settings.projects.detail', this.get('project.id'), {queryParams: {editing: false}});
|
||||
this.sendAction('done');
|
||||
return out;
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -56,17 +56,10 @@
|
|||
|
||||
<div class="{{if showEdit 'col-sm-12 col-md-8' 'col-xs-12'}}">
|
||||
<div class="well">
|
||||
{{#if showEdit}}
|
||||
{{#if (and accessEnabled showEdit)}}
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12">
|
||||
{{#if accessEnabled}}
|
||||
{{input-identity action="checkMember" onError="error"}}
|
||||
{{else}}
|
||||
<p class="help-block text-center r-mt0">
|
||||
Access Control is not enabled.
|
||||
Anybody with access to the API/UI acts as an admin and will be able to use any environment.
|
||||
</p>
|
||||
{{/if}}
|
||||
{{input-identity action="checkMember" onError="error"}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
@ -118,6 +111,11 @@
|
|||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<p class="help-block text-center">
|
||||
Access Control is not enabled.<br/>
|
||||
Anybody with access to the API/UI acts as an admin and will be able to use any environment.
|
||||
</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,19 +3,28 @@ import Ember from 'ember';
|
|||
export default Ember.Route.extend({
|
||||
k8s: Ember.inject.service(),
|
||||
|
||||
redirect() {
|
||||
if ( !this.modelFor('authenticated').kubernetesReady )
|
||||
{
|
||||
this.transitionTo('k8s-tab.waiting');
|
||||
}
|
||||
},
|
||||
|
||||
model() {
|
||||
var k8s = this.get('k8s');
|
||||
|
||||
return Ember.RSVP.hash({
|
||||
namespaces: k8s.allNamespaces(),
|
||||
services: k8s.allServices(),
|
||||
rcs: k8s.allRCs(),
|
||||
pods: k8s.allPods(),
|
||||
containers: this.get('store').findAll('container'),
|
||||
}).then((hash) => {
|
||||
return k8s.selectNamespace().then(() => {
|
||||
k8s.setProperties(hash);
|
||||
if ( this.modelFor('authenticated').kubernetesReady )
|
||||
{
|
||||
return Ember.RSVP.hash({
|
||||
namespaces: k8s.allNamespaces(),
|
||||
services: k8s.allServices(),
|
||||
rcs: k8s.allRCs(),
|
||||
pods: k8s.allPods(),
|
||||
containers: this.get('store').findAll('container'),
|
||||
}).then((hash) => {
|
||||
return k8s.selectNamespace().then(() => {
|
||||
k8s.setProperties(hash);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
import Ember from 'ember';
|
||||
import { debouncedObserver } from 'ui/utils/debounce';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
k8s: Ember.inject.service(),
|
||||
settings: Ember.inject.service(),
|
||||
|
||||
timer: null,
|
||||
currentStep: 0,
|
||||
|
||||
steps: [
|
||||
'Add at least one host',
|
||||
'Waiting for a host to be active',
|
||||
'Creating Kubernetes system stack',
|
||||
'Starting services',
|
||||
'Waiting for Kubernetes API',
|
||||
'Creating Namespace',
|
||||
],
|
||||
|
||||
updateStep: debouncedObserver('model.hosts.@each.state','model.stacks.@each.{state,externalId}', function() {
|
||||
if ( (this.get('model.hosts.length') + this.get('model.machines.length')) === 0 )
|
||||
{
|
||||
this.set('currentStep', 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.get('model.hosts').filterBy('state','active').get('length') === 0 )
|
||||
{
|
||||
this.set('currentStep', 1);
|
||||
return;
|
||||
}
|
||||
|
||||
var stack = this.get('model.stacks').filterBy('externalId','system://kubernetes')[0];
|
||||
if ( !stack )
|
||||
{
|
||||
this.set('currentStep', 2);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( stack.get('state') !== 'active' )
|
||||
{
|
||||
if ( stack.get('state') === 'inactive' )
|
||||
{
|
||||
stack.doAction('activate');
|
||||
}
|
||||
|
||||
this.set('currentStep', 3);
|
||||
return;
|
||||
}
|
||||
|
||||
var services = this.get('model.services').filterBy('environmentId', stack.get('id'));
|
||||
var num = services.get('length');
|
||||
var active = services.filterBy('state','active').get('length');
|
||||
if ( num === 0 || active < num )
|
||||
{
|
||||
this.set('currentStep', 3);
|
||||
return;
|
||||
}
|
||||
|
||||
this.set('currentStep', 4);
|
||||
this.get('k8s').isReady().then((ready) => {
|
||||
if ( ready )
|
||||
{
|
||||
this.get('k8s').getNamespace('default').then(() => {
|
||||
this.set('currentStep', 6);
|
||||
}).catch(() => {
|
||||
this.set('currentStep', 5);
|
||||
reschedule();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
reschedule();
|
||||
}
|
||||
}).catch(() => {
|
||||
reschedulerescheduleReady();
|
||||
});
|
||||
|
||||
var self = this;
|
||||
function reschedule() {
|
||||
self.set('timer', Ember.run.later(self, 'updateStep', 5000));
|
||||
}
|
||||
}),
|
||||
|
||||
onInit: function() {
|
||||
this.updateStep();
|
||||
}.on('init'),
|
||||
|
||||
stepChanged: function(){
|
||||
if ( this.get('currentStep') === 6 )
|
||||
{
|
||||
this.send('refreshKubernetes');
|
||||
this.transitionTo('k8s-tab.index');
|
||||
}
|
||||
}.observes('currentStep'),
|
||||
|
||||
deactivate() {
|
||||
Ember.run.cancel(this.get('timer'));
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
redirect() {
|
||||
if ( this.modelFor('authenticated').kubernetesReady )
|
||||
{
|
||||
this.transitionTo('k8s-tab.index');
|
||||
}
|
||||
},
|
||||
|
||||
model() {
|
||||
return Ember.RSVP.hash({
|
||||
hosts: this.get('store').findAllUnremoved('host'),
|
||||
machines: this.get('store').findAllUnremoved('machine'),
|
||||
stacks: this.get('store').findAllUnremoved('environment'),
|
||||
services: this.get('store').findAllUnremoved('service'),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
{{#if (gt currentStep 0)}}
|
||||
<div class="well r-mt40 text" style="width: 50%; margin-left: 25%">
|
||||
<h2 class="loading">Setting Up</h2>
|
||||
|
||||
<ul class="list-unstyled r-mt20">
|
||||
{{#each steps as |step index|}}
|
||||
<li class="{{if (lt currentStep index) 'text-muted'}}">
|
||||
{{#if (eq currentStep index)}}
|
||||
<i class="icon icon-spinner icon-spin" />
|
||||
{{else}}
|
||||
{{#if (gt currentStep index)}}
|
||||
<i class="icon icon-check text-success" />
|
||||
{{else}}
|
||||
<i class="icon icon-circle-o" />
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<span>{{step}}</span>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
{{else}}
|
||||
<section class="welcome well">
|
||||
<i class="icon icon-host"></i>
|
||||
<h2>Adding your first Host</h2>
|
||||
<p>
|
||||
Before launching Kubernetes, you must first add at least one Linux host that supports Docker 1.9.1+ and be able to reach the {{settings.appName}} server via HTTP.
|
||||
{{settings.appName}} supports adding Linux hosts in the form of a virtual or physical machine from any public cloud providers, privately hosted clouds, or even bare metal servers.
|
||||
{{#unless settings.isPrivateLabel}}<a href="{{docsBase}}/rancher-ui/infrastructure/hosts/" target="_blank">Learn More</a>{{/unless}}
|
||||
</p>
|
||||
{{#link-to "hosts.new" class="btn btn-primary"}}Add Host{{/link-to}}
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ var K8sResource = Resource.extend({
|
|||
goToApi: function() {
|
||||
var endpoint = this.get('endpoint.absolute'); // http://e.f.g.h/ , does not include version. e.f.g.h is where the API actually is.
|
||||
var projectId = this.get(`tab-session.${C.TABSESSION.PROJECT}`);
|
||||
var relative = this.linkFor('self');
|
||||
var relative = this.linkFor('self').replace(/^\/r\/kubernetes/,'');
|
||||
var url = `${endpoint}r/projects/${projectId}/kubernetes${relative}`;
|
||||
|
||||
// For local development where API doesn't match origin, add basic auth token
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ Router.map(function() {
|
|||
// Kubernetes
|
||||
this.route('k8s-tab', {path: '/kubernetes', resetNamespace: true}, function() {
|
||||
this.route('index', {path: '/'});
|
||||
this.route('waiting', {path: '/waiting'});
|
||||
|
||||
this.route('apply', {path: '/apply'});
|
||||
this.route('kubectl', {path: '/kubectl'});
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ export default Ember.Service.extend({
|
|||
}
|
||||
|
||||
// Un-namespaced things are cacheable
|
||||
var str = `${C.K8S.BASE}/namespaces/`;
|
||||
var str = `${C.K8S.BASE_VERSION}/namespaces/`;
|
||||
var pos = opt.url.indexOf(str);
|
||||
if ( pos >= 0 )
|
||||
{
|
||||
|
|
@ -317,7 +317,7 @@ export default Ember.Service.extend({
|
|||
{
|
||||
if ( opt.url.substr(0,1) !== '/' )
|
||||
{
|
||||
opt.url = `${self.get('app.kubernetesEndpoint')}/${C.K8S.BASE}/` + opt.url;
|
||||
opt.url = `${self.get('app.kubernetesEndpoint')}/${C.K8S.BASE_VERSION}/` + opt.url;
|
||||
}
|
||||
|
||||
return findWithUrl(opt.url);
|
||||
|
|
@ -424,6 +424,15 @@ export default Ember.Service.extend({
|
|||
}.property('containers.@each.externalId'),
|
||||
|
||||
|
||||
isReady() {
|
||||
return this.request({
|
||||
url: `${this.get('app.kubernetesEndpoint')}/${C.K8S.BASE}`
|
||||
}).then(() => {
|
||||
return true;
|
||||
}).catch(() => {
|
||||
return Ember.RSVP.resolve(false);
|
||||
});
|
||||
},
|
||||
|
||||
_getCollection(type, resourceName) {
|
||||
return this._find(`${C.K8S.TYPE_PREFIX}${type}`, null, {
|
||||
|
|
@ -495,7 +504,7 @@ export default Ember.Service.extend({
|
|||
selectNamespace(desiredName) {
|
||||
var self = this;
|
||||
return this.allNamespaces().then((all) => {
|
||||
// Asked fror a specific one
|
||||
// Asked for a specific one
|
||||
var obj = objForName(desiredName);
|
||||
if ( obj )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,45 +37,47 @@ export default Ember.Service.extend({
|
|||
});
|
||||
},
|
||||
|
||||
selectDefault: function() {
|
||||
selectDefault: function(desired) {
|
||||
var self = this;
|
||||
var tabSession = this.get('tab-session');
|
||||
|
||||
// Try the project ID in the session
|
||||
return this._activeProjectFromId(tabSession.get(C.TABSESSION.PROJECT)).then(select)
|
||||
// The one specifically asked for
|
||||
return this._activeProjectFromId(desired).then(select)
|
||||
.catch(() => {
|
||||
// Then the default project ID from the prefs
|
||||
return this._activeProjectFromId(this.get('prefs').get(C.PREFS.PROJECT_DEFAULT)).then(select)
|
||||
// Try the project ID in the session
|
||||
return this._activeProjectFromId(tabSession.get(C.TABSESSION.PROJECT)).then(select)
|
||||
.catch(() => {
|
||||
// Setting this now and then just below breaks API uniqueness checking
|
||||
// this.get('prefs').set(C.PREFS.PROJECT_DEFAULT, "");
|
||||
|
||||
// Then the first active project
|
||||
var project = this.get('active.firstObject');
|
||||
if ( project )
|
||||
{
|
||||
return select(project, true);
|
||||
}
|
||||
else if ( this.get('access.admin') )
|
||||
{
|
||||
return this.getAll().then((all) => {
|
||||
var firstActive = all.filterBy('state','active')[0];
|
||||
if ( firstActive )
|
||||
{
|
||||
return select(firstActive, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Then the default project ID from the prefs
|
||||
return this._activeProjectFromId(this.get('prefs').get(C.PREFS.PROJECT_DEFAULT)).then(select)
|
||||
.catch(() => {
|
||||
// Then the first active project you're a member of
|
||||
var project = this.get('active.firstObject');
|
||||
if ( project )
|
||||
{
|
||||
return select(project, true);
|
||||
}
|
||||
else if ( this.get('access.admin') )
|
||||
{
|
||||
// Then if you're an admin the first active of any kind
|
||||
return this.getAll().then((all) => {
|
||||
var firstActive = all.filterBy('state','active')[0];
|
||||
if ( firstActive )
|
||||
{
|
||||
return select(firstActive, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fail();
|
||||
}
|
||||
}).catch(() => {
|
||||
return fail();
|
||||
}
|
||||
}).catch(() => {
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return fail();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -109,19 +111,7 @@ export default Ember.Service.extend({
|
|||
|
||||
setCurrent: function(project) {
|
||||
this.set('current', project);
|
||||
|
||||
if ( project && project.get('kubernetes') )
|
||||
{
|
||||
return this.get('k8s').allNamespaces().then(() => {
|
||||
return this.get('k8s').selectNamespace().then(() => {
|
||||
return project;
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return project;
|
||||
}
|
||||
return Ember.RSVP.resolve(project);
|
||||
},
|
||||
|
||||
_activeProjectFromId: function(projectId) {
|
||||
|
|
@ -129,9 +119,10 @@ export default Ember.Service.extend({
|
|||
if ( !projectId )
|
||||
{
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
||||
this.get('store').find('project', projectId).then((project) => {
|
||||
this.get('store').find('project', projectId, {url: 'projects/'+encodeURIComponent(projectId)}).then((project) => {
|
||||
if ( project.get('state') === 'active' )
|
||||
{
|
||||
resolve(project);
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export default Ember.Service.extend(Ember.Evented, {
|
|||
obj.save().then(() => {
|
||||
this.notifyPropertyChange(normalizeName(key));
|
||||
}).catch((err) => {
|
||||
this.trigger('gotError', err);
|
||||
console.log('Error saving setting:', err);
|
||||
}).finally(() => {
|
||||
this.decrementProperty('promiseCount');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,8 +7,14 @@ export default Ember.Controller.extend({
|
|||
queryParams: ['editing'],
|
||||
|
||||
actions: {
|
||||
done() {
|
||||
this.transitionTo('settings.projects').then(() => {
|
||||
this.send('refreshKubernetes');
|
||||
});
|
||||
},
|
||||
|
||||
cancel() {
|
||||
this.transitionTo('settings.projects.detail', this.get('model.project.id'), {queryParams: {editing: false}});
|
||||
this.transitionTo('settings.projects');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,5 +2,6 @@
|
|||
model=model
|
||||
showEdit=editing
|
||||
editing=true
|
||||
done=(action "done")
|
||||
cancel=(action "cancel")
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@ import Ember from 'ember';
|
|||
|
||||
export default Ember.Controller.extend({
|
||||
actions: {
|
||||
done() {
|
||||
this.send('refreshKubernetes');
|
||||
this.send('goToPrevious');
|
||||
},
|
||||
|
||||
cancel() {
|
||||
this.send('goToPrevious');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,5 +2,6 @@
|
|||
model=model
|
||||
showEdit=true
|
||||
editing=false
|
||||
done=(action "done")
|
||||
cancel=(action "cancel")
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<p>
|
||||
Before adding your first service or launching a container, you must add at least a single Linux host that supports Docker 1.9.1+ and be able to reach the {{settings.appName}} server via HTTP.
|
||||
{{settings.appName}} supports adding Linux hosts in the form of a virtual or physical machine from any public cloud providers, privately hosted clouds, or even bare metal servers.
|
||||
{{#unless settings.isPrivateLabel}}<a href="{[docsBase}}/rancher-ui/infrastructure/hosts/" target="_blank">Learn More</a>{{/unless}}
|
||||
{{#unless settings.isPrivateLabel}}<a href="{{docsBase}}/rancher-ui/infrastructure/hosts/" target="_blank">Learn More</a>{{/unless}}
|
||||
</p>
|
||||
{{#link-to "hosts.new" class="btn btn-primary"}}Add Host{{/link-to}}
|
||||
</section>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
A service is simply a group of containers created from the same Docker image but extends Docker's "link" concept to leverage {{settings.appName}}'s lightweight distributed DNS service for service discovery.
|
||||
Services can be added individually or by deploying an item from the Catalog.</p>
|
||||
<p>A service is also capable of leveraging other {{settings.appName}} built-in services such as load balancers, health monitoring, upgrade support, and high-availability.
|
||||
{{#unless settings.isPrivateLabel}}<a href="{[docsBase}}/rancher-ui/applications/stacks/adding-services/" target="_blank">Learn More</a>{{/unless}}
|
||||
{{#unless settings.isPrivateLabel}}<a href="{{docsBase}}/rancher-ui/applications/stacks/adding-services/" target="_blank">Learn More</a>{{/unless}}
|
||||
</p>
|
||||
<a class="btn btn-primary" {{action "newService"}}>Add Service</a>
|
||||
{{#link-to "applications-tab.catalog" class="btn btn-primary"}}Add From Catalog{{/link-to}}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
{{#if hasKubernetes}}
|
||||
{{#link-to "environments" (query-params which="not-kubernetes")}}<i class="icon icon-layers"></i>Stacks{{/link-to}}
|
||||
{{#link-to "environments" project.id (query-params which="not-kubernetes")}}<i class="icon icon-layers"></i>Stacks{{/link-to}}
|
||||
{{else}}
|
||||
{{#link-to "environments" (query-params which="user")}}<i class="icon icon-layers"></i> Stacks{{/link-to}}
|
||||
{{#link-to "environments" project.id (query-params which="user")}}<i class="icon icon-layers"></i> Stacks{{/link-to}}
|
||||
{{#if hasSystem}}
|
||||
{{#link-to "environments" (query-params which="system")}}<i class="icon icon-network"></i>System{{/link-to}}
|
||||
{{#link-to "environments" project.id (query-params which="system")}}<i class="icon icon-network"></i>System{{/link-to}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#link-to "applications-tab.catalog"}}<i class="icon icon-catalog"></i> Catalog{{/link-to}}
|
||||
{{#link-to "applications-tab.catalog" project.id}}<i class="icon icon-catalog"></i> Catalog{{/link-to}}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
{{#link-to "hosts"}}<i class="icon icon-host"></i>Hosts{{/link-to}}
|
||||
{{#link-to "containers"}}<i class="icon icon-box"></i>Containers{{/link-to}}
|
||||
{{#link-to "hosts" project.id}}<i class="icon icon-host"></i>Hosts{{/link-to}}
|
||||
{{#link-to "containers" project.id}}<i class="icon icon-box"></i>Containers{{/link-to}}
|
||||
{{#if hasVm}}
|
||||
{{#link-to "virtualmachines"}}<i class="icon icon-vm"></i>Virtual Machines{{/link-to}}
|
||||
{{#link-to "virtualmachines" project.id}}<i class="icon icon-vm"></i>Virtual Machines{{/link-to}}
|
||||
{{/if}}
|
||||
{{#link-to "storagepools"}}<i class="icon icon-hdd"></i>Storage Pools{{/link-to}}
|
||||
{{#link-to "certificates"}}<i class="icon icon-certificate"></i>Certificates{{/link-to}}
|
||||
{{#link-to "registries" role="menuitem" tabindex="-1"}}<i class="icon icon-database"></i>Registries{{/link-to}}
|
||||
{{#link-to "storagepools" project.id}}<i class="icon icon-hdd"></i>Storage Pools{{/link-to}}
|
||||
{{#link-to "certificates" project.id}}<i class="icon icon-certificate"></i>Certificates{{/link-to}}
|
||||
{{#link-to "registries" project.id}}<i class="icon icon-database"></i>Registries{{/link-to}}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
{{#link-to "k8s-tab.namespace.services" namespace.id}}<i class="icon icon-compass"></i>Services{{/link-to}}
|
||||
{{#link-to "k8s-tab.namespace.rcs" namespace.id}}<i class="icon icon-tachometer"></i>RCs{{/link-to}}
|
||||
{{#link-to "k8s-tab.namespace.pods" namespace.id}}<i class="icon icon-containers"></i>Pods{{/link-to}}
|
||||
{{#link-to "k8s-tab.kubectl"}}<i class="icon icon-terminal"></i>kubectl{{/link-to}}
|
||||
{{#if namespace.id}}
|
||||
{{#link-to "k8s-tab.namespace.services" project.id namespace.id}}<i class="icon icon-compass"></i>Services{{/link-to}}
|
||||
{{#link-to "k8s-tab.namespace.rcs" project.id namespace.id}}<i class="icon icon-tachometer"></i>RCs{{/link-to}}
|
||||
{{#link-to "k8s-tab.namespace.pods" project.id namespace.id}}<i class="icon icon-containers"></i>Pods{{/link-to}}
|
||||
{{#link-to "k8s-tab.kubectl" project.id}}<i class="icon icon-terminal"></i>kubectl{{/link-to}}
|
||||
{{/if}}
|
||||
|
|
|
|||
|
|
@ -200,7 +200,8 @@ var C = {
|
|||
},
|
||||
|
||||
K8S: {
|
||||
BASE: 'api/v1',
|
||||
BASE: 'api',
|
||||
BASE_VERSION: 'api/v1',
|
||||
TYPE_PREFIX: 'k8s-',
|
||||
ID_SEPARATOR: '::'
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue