mirror of https://github.com/rancher/ui.git
commit
a9df09e6c3
|
|
@ -0,0 +1,206 @@
|
|||
import Ember from 'ember';
|
||||
import Util from 'ui/utils/util';
|
||||
import C from 'ui/utils/constants';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
settings: Ember.inject.service(),
|
||||
growl: Ember.inject.service(),
|
||||
cookies: Ember.inject.service(),
|
||||
projects: Ember.inject.service(),
|
||||
|
||||
csrf: Ember.computed.alias('cookies.CSRF'),
|
||||
|
||||
userUrl: '',
|
||||
selfSign: true,
|
||||
generating: false,
|
||||
justGenerated: false,
|
||||
errors: null,
|
||||
confirmPanic: false,
|
||||
haProject: null,
|
||||
|
||||
configExecute: function() {
|
||||
return 'sudo bash ./rancher-ha.sh rancher/server:' + (this.get('settings.rancherVersion') || 'latest');
|
||||
}.property('settings.rancherVersion'),
|
||||
|
||||
runCode: function() {
|
||||
let version = this.get('settings.rancherVersion') || 'latest';
|
||||
|
||||
return `sudo docker run -d --restart=always -p 8080:8080 \\
|
||||
-e CATTLE_DB_CATTLE_MYSQL_HOST=<hostname or IP of MySQL instance> \\
|
||||
-e CATTLE_DB_CATTLE_MYSQL_PORT=<port> \\
|
||||
-e CATTLE_DB_CATTLE_MYSQL_NAME=<Name of database> \\
|
||||
-e CATTLE_DB_CATTLE_USERNAME=<Username> \\
|
||||
-e CATTLE_DB_CATTLE_PASSWORD=<Password> \\
|
||||
rancher/server:${version}`;
|
||||
}.property('settings.rancherVersion'),
|
||||
|
||||
isLocalDb: function() {
|
||||
return (this.get('model.haConfig.dbHost')||'').toLowerCase() === 'localhost';
|
||||
}.property('model.haConfig.dbHost'),
|
||||
|
||||
actions: {
|
||||
exportDatabase() {
|
||||
Util.download(this.get('model.haConfig').linkFor('dbdump'));
|
||||
},
|
||||
|
||||
readFile(field, text) {
|
||||
this.set('model.createScript.'+field, text.trim());
|
||||
},
|
||||
|
||||
promptPanic() {
|
||||
this.set('confirmPanic', true);
|
||||
Ember.run.later(() => {
|
||||
if ( this._state !== 'destroying' )
|
||||
{
|
||||
this.set('confirmPanic', false);
|
||||
}
|
||||
}, 5000);
|
||||
},
|
||||
|
||||
panic() {
|
||||
var orig = this.get('model.haConfig');
|
||||
var clone = orig.clone();
|
||||
clone.set('enabled', false);
|
||||
clone.save({headers: {[C.HEADER.PROJECT]: undefined}}).then(() => {
|
||||
orig.set('enabled', false);
|
||||
}).catch((err) => {
|
||||
this.get('growl').fromError(err);
|
||||
});
|
||||
},
|
||||
|
||||
generateConfig() {
|
||||
if ( !this.validate() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set('generating',true);
|
||||
this.set('haProject', null);
|
||||
|
||||
Ember.run.later(() => {
|
||||
this.set('generating',false);
|
||||
this.set('justGenerated',true);
|
||||
}, 500);
|
||||
},
|
||||
|
||||
downloadConfig() {
|
||||
var form = $('#haConfigForm')[0];
|
||||
form.submit();
|
||||
this.set('downloaded',true);
|
||||
|
||||
var ha = this.get('model.haConfig');
|
||||
var clone = ha.clone();
|
||||
clone.set('enabled',true);
|
||||
clone.save({headers: {[C.HEADER.PROJECT]: undefined}}).then((neu) => {
|
||||
ha.merge(neu);
|
||||
this.findProject();
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
userUrlChanged: function() {
|
||||
let val = this.get('userUrl')||'';
|
||||
let match = val.match(/^https?:\/\//);
|
||||
if ( match )
|
||||
{
|
||||
val = val.substr(match[0].length);
|
||||
}
|
||||
|
||||
if ( match = val.match(/^(.*):(\d+)$/) )
|
||||
{
|
||||
let port = parseInt(match[2],10);
|
||||
if ( port > 0 )
|
||||
{
|
||||
this.set('model.httpsPort', port);
|
||||
}
|
||||
}
|
||||
|
||||
let pos = val.indexOf('/',1);
|
||||
if ( pos >= 1 && val.substr(pos-2,2) !== ':/' && val.substr(pos-2,2) !== 's:' )
|
||||
{
|
||||
val = val.substr(0,pos);
|
||||
}
|
||||
|
||||
this.set('userUrl', val);
|
||||
this.set('model.createScript.hostRegistrationUrl', 'https://'+val);
|
||||
}.observes('userUrl'),
|
||||
|
||||
selfSignChanged: function() {
|
||||
if ( this.get('selfSign') )
|
||||
{
|
||||
this.get('model.createScript').setProperties({
|
||||
key: null,
|
||||
cert: null,
|
||||
certChain: null,
|
||||
});
|
||||
}
|
||||
}.observes('selfSign'),
|
||||
|
||||
validate() {
|
||||
var errors = this.get('model.createScript').validationErrors();
|
||||
this.set('errors',errors);
|
||||
return errors.length === 0;
|
||||
},
|
||||
|
||||
findProject: function() {
|
||||
this.get('store').find('project', null, {authAsUser: true, filter: {all: true}, forceReload: true}).then((projects) => {
|
||||
var matches = projects.filter((project) => {
|
||||
return project.get('uuid').match(/^system-ha-(\d+)$/) || project.get('uuid').match(/^system-management-(\d+)$/);
|
||||
});
|
||||
|
||||
if ( matches.length )
|
||||
{
|
||||
this.set('haProject', matches.objectAt(0));
|
||||
if ( this.get('projects.current.id') === this.get('haProject.id') )
|
||||
{
|
||||
this.getHosts();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.send('switchProject', this.get('haProject.id'), false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Ember.run.later(this,'findProject', 5000);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
hosts: null,
|
||||
getHosts: function() {
|
||||
return this.get('store').findAll('host', null, {forceReload: true}).then((hosts) => {
|
||||
this.set('hosts', hosts);
|
||||
});
|
||||
}.observes('haProject'),
|
||||
|
||||
expectedHosts: Ember.computed.alias('model.haConfig.clusterSize'),
|
||||
activeHosts: function() {
|
||||
return (this.get('hosts')||[]).filterBy('state','active').get('length');
|
||||
}.property('hosts.@each.state'),
|
||||
|
||||
hostBlurb: function() {
|
||||
clearInterval(this.get('hostTimer'));
|
||||
var total = this.get('expectedHosts');
|
||||
var active = this.get('activeHosts');
|
||||
|
||||
if ( active < total )
|
||||
{
|
||||
this.set('hostTimer', setInterval(() => {
|
||||
this.getHosts();
|
||||
}, 5000));
|
||||
return active + '/' + total;
|
||||
}
|
||||
else
|
||||
{
|
||||
return total;
|
||||
}
|
||||
}.property('hosts.@each.state','model.haConfig.clusterSize'),
|
||||
|
||||
cert: null,
|
||||
getCertificate: function() {
|
||||
return this.get('store').find('certificate', null, {filter: {name: 'system-ssl'}}).then((certs) => {
|
||||
this.set('cert', certs.objectAt(0));
|
||||
this.getHosts();
|
||||
});
|
||||
}.observes('haProject'),
|
||||
});
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
settings: Ember.inject.service(),
|
||||
|
||||
beforeModel() {
|
||||
return Ember.RSVP.all([
|
||||
this.get('store').find('schema','haconfig', {authAsUser: true}),
|
||||
this.get('store').find('schema','haconfiginput', {authAsUser: true}),
|
||||
]);
|
||||
},
|
||||
|
||||
model() {
|
||||
var store = this.get('store');
|
||||
return store.find('haConfig', null, {authAsUser: true, forceReload: true}).then((res) => {
|
||||
return Ember.Object.create({
|
||||
haConfig: res.objectAt(0),
|
||||
createScript: store.createRecord({type: 'haConfigInput'})
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
setupController(controller/*, model*/) {
|
||||
this._super(...arguments);
|
||||
controller.findProject();
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
<section class="well">
|
||||
<h2>High Availability is {{#if model.haConfig.enabled}}<b class="text-success">enabled</b>{{else}}<b class="text-warning">not configured</b>{{/if}}</h2>
|
||||
</section>
|
||||
|
||||
{{#if model.haConfig.enabled}}
|
||||
{{#if (lt activeHosts expectedHosts)}}
|
||||
<section class="well">
|
||||
<h4>5. Add hosts</h4>
|
||||
<hr/>
|
||||
<p>
|
||||
Copy the downloaded script and run it on to each HA host to register them:
|
||||
{{code-block code=configExecute language="bash" constrained=false}}
|
||||
</p>
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="well">
|
||||
<h4 class="r-mb10">Hosts:</h4>
|
||||
{{#if hosts}}
|
||||
<h1 class="text-center">{{hostBlurb}}</h1>
|
||||
{{else}}
|
||||
<i class="icon icon-spinner icon-spin"></i> Waiting for a host...
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<div class="well">
|
||||
<h4 class="r-mb10">Management Server Certificate: {{#if cert.cert}}{{copy-to-clipboard size="small" clipboardText=cert.cert}}{{/if}}</h4>
|
||||
{{#if cert.cert}}
|
||||
<pre><code>{{cert.cert}}</code></pre>
|
||||
{{else}}
|
||||
<i class="icon icon-spinner icon-spin"></i> Waiting for a host...
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="well">
|
||||
<h4>Danger Zone™</h4>
|
||||
<hr/>
|
||||
|
||||
<p>
|
||||
{{#if confirmPanic}}
|
||||
<button class="btn btn-danger" {{action "panic"}}>
|
||||
<i class="icon icon-alert"></i> Are you sure? Click again to really disable access HA
|
||||
</button>
|
||||
{{else}}
|
||||
<button class="btn btn-danger" {{action "promptPanic"}}>
|
||||
<i class="icon icon-umbrella"></i> Disable HA
|
||||
</button>
|
||||
{{/if}}
|
||||
</p>
|
||||
</section>
|
||||
{{else}}
|
||||
|
||||
<section class="well">
|
||||
{{#if isLocalDb}}
|
||||
<h4>1. Setup an external database</h4>
|
||||
<hr/>
|
||||
<p>
|
||||
This {{settings.appName}} installation is currently configured to use the built-in database server, but HA requires a standalone installation of MySQL.
|
||||
</p>
|
||||
<p>
|
||||
<ul>
|
||||
<li>
|
||||
Setup an external database instance.
|
||||
<ul>
|
||||
<li>This can be a hosted solution like Amazon RDS or Google Cloud SQL,</li>
|
||||
<li>Or a self-hosted instance or multi-master cluster.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Click the export button below to export the entire contents of the current database.</li>
|
||||
<li>Import the data into the new external database.</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p class="r-mb0 r-mt20">
|
||||
<button class="btn btn-primary" {{action "exportDatabase"}}>Export Database</button>
|
||||
<p class="help-block r-mb0">Uncompressed Size: {{format-mib model.haConfig.dbSize}}</p>
|
||||
</p>
|
||||
{{else}}
|
||||
<h4 class="text-success">1. Setup an external database <i class="icon icon-check"/></h4>
|
||||
<p class="text-muted r-mb0">
|
||||
Complete, running off of an external database.
|
||||
</p>
|
||||
{{/if}}
|
||||
</section>
|
||||
|
||||
<section class="well">
|
||||
{{#if isLocalDb}}
|
||||
<h4>2. Use the new external database</h4>
|
||||
<hr/>
|
||||
<ul>
|
||||
<li>Re-launch the server container pointed at the external database:
|
||||
{{code-block code=runCode language="bash" constrained=false}}
|
||||
</li>
|
||||
{{#unless settings.isPrivateLabel}}
|
||||
<li>
|
||||
<a href="http://docs.rancher.com/rancher/installing-rancher/installing-server/#using-an-external-database" target="_blank">See docs</a> for more detail.
|
||||
</li>
|
||||
{{/unless}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<h4 class="text-success">2. Use the new external database <i class="icon icon-check"/></h4>
|
||||
<p class="text-muted r-mb0">
|
||||
Complete, <code>{{model.haConfig.dbHost}}</code> will be used as the external database for HA.
|
||||
</p>
|
||||
{{/if}}
|
||||
</section>
|
||||
|
||||
<section class="well">
|
||||
{{#if justGenerated}}
|
||||
<h4 class="text-success">3. Generate HA config script <i class="icon icon-check"/></h4>
|
||||
<p class="text-muted r-mb0">
|
||||
Complete.
|
||||
</p>
|
||||
{{else}}
|
||||
<h4>3. Generate HA config script</h4>
|
||||
<hr/>
|
||||
{{#if isLocalDb}}
|
||||
<p class="text-muted">Come back here once you are running off the external database...</p>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<iframe name="haConfigFrame" id="haConfigFrame" style="display: none;"></iframe>
|
||||
<form action="{{model.haConfig.actionLinks.createscript}}" method="POST" id="haConfigForm" target="haConfigFrame" class="{{if (or isLocalDb justGenerated) 'hide'}}">
|
||||
<input type="hidden" name="hostRegistrationUrl" value="{{model.createScript.hostRegistrationUrl}}"/>
|
||||
<input type="hidden" name="CSRF" value="{{csrf}}"/>
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-6 col-md-2 form-control-static">
|
||||
<label>Cluster Size</label>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-10">
|
||||
<div class="radio">
|
||||
<label>
|
||||
{{radio-button name="clusterSize" selection=model.createScript.clusterSize value=1}}
|
||||
<span class="text-bold" style="display: inline-block: width: 120px;">1 Host:</span> Not really very HA at all
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
{{radio-button name="clusterSize" selection=model.createScript.clusterSize value=3}}
|
||||
<span class="text-bold" style="display: inline-block: width: 120px;">3 Hosts:</span> Any <b>one</b> host can fail
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
{{radio-button name="clusterSize" selection=model.createScript.clusterSize value=5}}
|
||||
<span class="text-bold" style="display: inline-block: width: 120px;">5 Hosts:</span> Any <b>two</b> hosts can fail
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-6 col-md-2 form-control-static">
|
||||
<label>Host Registration URL</label>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-10">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">
|
||||
https://
|
||||
</span>
|
||||
{{input type="text" value=userUrl type="text" classNames="form-control"}}
|
||||
</div>
|
||||
<p class="help-block">This should be a FQDN that resolves to the addresses of or is a load balancer for {{#if (eq model.createScript.clusterSize 1)}}the HA host{{else}}all {{model.createScript.clusterSize}} HA hosts{{/if}}. Do not include <code>/v1</code> or any other path.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-6 col-md-2 form-control-static">
|
||||
<label>Certificate</label>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-10">
|
||||
<div class="radio">
|
||||
<label>
|
||||
{{radio-button selection=selfSign value=true}} Generate a self-signed certificate
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
{{radio-button selection=selfSign value=false}} Upload a valid certificate{{#if model.createScript.hostRegistrationUrl}} for <code>{{model.createScript.hostRegistrationUrl}}</code>{{/if}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#liquid-if (not selfSign)}}
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-4">
|
||||
<div class="clearfix r-mb10 r-mt15">
|
||||
<label class="r-pt5">Private Key</label>
|
||||
<span class="pull-right">{{read-text-file accept="text/*, .pem, .pkey, .key" action=(action "readFile" "key")}}</span>
|
||||
</div>
|
||||
{{textarea name="key" value=model.createScript.key classNames="form-control no-resize" rows="5" placeholder="Paste in the private key, starting with -----BEGIN RSA PRIVATE KEY-----"}}
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-4">
|
||||
<div class="clearfix r-mb10 r-mt15">
|
||||
<label class="r-pt5">Certificate</label>
|
||||
<span class="pull-right">{{read-text-file accept="text/*, .pem, .crt" action=(action "readFile" "cert")}}</span>
|
||||
</div>
|
||||
{{textarea name="cert" value=model.createScript.cert classNames="form-control no-resize" rows="5" placeholder="Paste in the primary certificate, starting with -----BEGIN CERTIFICATE-----"}}
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-4">
|
||||
<div class="clearfix r-mb10 r-mt15">
|
||||
<label class="r-pt5">Chain Certs</label>
|
||||
<span class="pull-right">{{read-text-file accept="text/*, .pem, .crt" action=(action "readFile" "certChain")}}</span>
|
||||
</div>
|
||||
{{textarea name="certChain" value=model.createScript.certChain classNames="form-control no-resize" rows="5" placeholder="Optional; Paste in the additional chained certificates, starting with -----BEGIN CERTIFICATE-----"}}
|
||||
</div>
|
||||
</div>
|
||||
{{/liquid-if}}
|
||||
|
||||
{{#advanced-section}}
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-md-2 form-control-static">
|
||||
<label>Listening Ports</label>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-5 r-pt5">
|
||||
<table class="fixed">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="200">HTTPS</td>
|
||||
<td width="100" class="text-muted">Required</td>
|
||||
<td width="100">{{input name="httpsPort" class="form-control input-sm r-mb5" type="number" min=1 max=65535 value=model.createScript.httpsPort}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>HTTP</td>
|
||||
<!-- <td><label>{{input name="httpEnabled" type="checkbox" checked=model.createScript.httpEnabled}} Enable</label></td> -->
|
||||
<td width="100" class="text-muted">Required</td>
|
||||
<td>{{input name="httpPort" class="form-control input-sm r-mb5" type="number" min=1 max=65535 value=model.createScript.httpPort disabled=(not model.createScript.httpEnabled)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Swarm</td>
|
||||
<!-- <td><label>{{input name="swarmEnabled" type="checkbox" checked=model.createScript.swarmEnabled}} Enable</label></td> -->
|
||||
<td width="100" class="text-muted">Required</td>
|
||||
<td>{{input name="swarmPort" class="form-control input-sm r-mb5" type="number" min=1 max=65535 value=model.createScript.swarmPort disabled=(not model.createScript.swarmEnabled)}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-5 r-pt5">
|
||||
<table class="fixed">
|
||||
<tbody>
|
||||
<tr class="r-mb5">
|
||||
<td width="200">Redis</td>
|
||||
<td width="100" class="text-muted">Required</td>
|
||||
<td width="100">{{input name="redisPort" class="form-control input-sm r-mb5" type="number" min=1 max=65535 value=model.createScript.redisPort}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZooKeeper Client</td>
|
||||
<td class="text-muted">Required</td>
|
||||
<td>{{input name="zookeeperClientPort" class="form-control input-sm r-mb5" type="number" min=1 max=65535 value=model.createScript.zookeeperClientPort}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZooKeeper Quorum</td>
|
||||
<td class="text-muted">Required</td>
|
||||
<td>{{input name="zookeeperQuorumPort" class="form-control input-sm r-mb5" type="number" min=1 max=65535 value=model.createScript.zookeeperQuorumPort}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZooKeeper Leader</td>
|
||||
<td class="text-muted">Required</td>
|
||||
<td>{{input name="zookeeperLeaderPort" class="form-control input-sm r-mb5" type="number" min=1 max=65535 value=model.createScript.zookeeperLeaderPort}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{/advanced-section}}
|
||||
|
||||
<p class="r-mb0 r-mt20">
|
||||
{{top-errors errors=errors}}
|
||||
|
||||
{{#if generating}}
|
||||
<button class="btn btn-primary btn-disabled" type="button" disabled><i class="icon icon-spinner icon-spin"/> Generating...</button>
|
||||
{{else}}
|
||||
<button class="btn btn-primary" type="button" {{action "generateConfig"}}>Generate Config Script</button>
|
||||
{{/if}}
|
||||
</p>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="well">
|
||||
{{#if downloaded}}
|
||||
<h4 class="text-success">4. Download script <i class="icon icon-check"/></h4>
|
||||
<p class="text-muted r-mb0">
|
||||
Complete, check your Downloads folder.
|
||||
</p>
|
||||
{{else}}
|
||||
<h4>4. Download script</h4>
|
||||
<hr/>
|
||||
{{#if justGenerated}}
|
||||
<p>
|
||||
Click the button below to download a shell script.
|
||||
<div class="alert alert-info">
|
||||
The script generates new encryption keys that will be used for the HA hosts to communicate with each other, so keep it safe.
|
||||
New keys are generated every time you download the config script, and all hosts must have the same keys for HA to work.
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<button class="btn btn-primary" type="button" {{action "downloadConfig"}}>Download Config Script</button>
|
||||
{{else}}
|
||||
<p class="text-muted r-mb0">
|
||||
Generate the script in step 3.
|
||||
</p>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</section>
|
||||
{{/if}}
|
||||
|
|
@ -205,9 +205,11 @@ export default Ember.Route.extend(Subscribe, {
|
|||
this.controllerFor('application').set('showAbout', true);
|
||||
},
|
||||
|
||||
switchProject(projectId) {
|
||||
switchProject(projectId, transition=true) {
|
||||
this.reset();
|
||||
this.intermediateTransitionTo('authenticated');
|
||||
if ( transition ) {
|
||||
this.intermediateTransitionTo('authenticated');
|
||||
}
|
||||
this.set(`tab-session.${C.TABSESSION.PROJECT}`, projectId);
|
||||
this.refresh();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ export default Ember.Component.extend({
|
|||
language: 'javascript',
|
||||
code: '',
|
||||
hide: false,
|
||||
constrained: true,
|
||||
|
||||
tagName: 'PRE',
|
||||
classNames: ['line-numbers','constrained'],
|
||||
classNameBindings: ['languageClass','hide:hide'],
|
||||
classNames: ['line-numbers'],
|
||||
classNameBindings: ['languageClass','hide:hide','constrained:constrained'],
|
||||
|
||||
languageClass: function() {
|
||||
var lang = this.get('language');
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ Router.map(function() {
|
|||
});
|
||||
|
||||
this.route('audit-logs');
|
||||
this.route('ha');
|
||||
});
|
||||
|
||||
this.route('project', {path: '/env/:project_id'}, function() {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export function normalizeName(str) {
|
|||
}
|
||||
|
||||
export function denormalizeName(str) {
|
||||
return str.replace(C.SETTING.DOT_CHAR,'.').toLowerCase();
|
||||
return str.replace(new RegExp('['+C.SETTING.DOT_CHAR+']','g'),'.').toLowerCase();
|
||||
}
|
||||
|
||||
export default Ember.Service.extend(Ember.Evented, {
|
||||
|
|
@ -85,6 +85,12 @@ export default Ember.Service.extend(Ember.Evented, {
|
|||
return this.get('asMap')[normalizeName(name)];
|
||||
},
|
||||
|
||||
findAsUser(key) {
|
||||
return this.get('store').find('setting', denormalizeName(key), {authAsUser: true, forceReload: true}).then(() => {
|
||||
return Ember.RSVP.resolve(this.unknownProperty(key));
|
||||
});
|
||||
},
|
||||
|
||||
asMap: function() {
|
||||
var out = {};
|
||||
(this.get('all')||[]).forEach((setting) => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<div>
|
||||
<label class="text-muted r-mt10">Image: </label>
|
||||
<span class="force-wrap">
|
||||
{{service.launchConfig.imageUuid}}
|
||||
{{service.launchConfig.displayImage}}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@
|
|||
{{#link-to "admin-tab.accounts"}}<i class="icon icon-users"></i>Accounts{{/link-to}}
|
||||
{{#link-to "admin-tab.auth"}}<i class="icon icon-key"></i>Access Control{{/link-to}}
|
||||
{{#link-to "admin-tab.settings"}}<i class="icon icon-network"></i>Settings{{/link-to}}
|
||||
{{#link-to "admin-tab.ha"}}<i class="icon icon-umbrella"></i>HA{{/link-to}}
|
||||
|
|
|
|||
|
|
@ -166,23 +166,23 @@ var C = {
|
|||
|
||||
SETTING: {
|
||||
// Dots in key names do not mix well with Ember, so use $ in their place.
|
||||
DOT_CHAR: '$',
|
||||
VERSION_RANCHER: 'rancher$server$image',
|
||||
VERSION_COMPOSE: 'rancher$compose$version',
|
||||
VERSION_CATTLE: 'cattle$version',
|
||||
VERSION_MACHINE: 'docker$machine$version',
|
||||
VERSION_GMS: 'go$machine$service$version',
|
||||
DOT_CHAR: '$',
|
||||
VERSION_RANCHER: 'rancher$server$image',
|
||||
VERSION_COMPOSE: 'rancher$compose$version',
|
||||
VERSION_CATTLE: 'cattle$version',
|
||||
VERSION_MACHINE: 'docker$machine$version',
|
||||
VERSION_GMS: 'go$machine$service$version',
|
||||
COMPOSE_URL: {
|
||||
DARWIN: 'rancher$compose$darwin$url',
|
||||
WINDOWS: 'rancher$compose$windows$url',
|
||||
LINUX: 'rancher$compose$linux$url',
|
||||
DARWIN: 'rancher$compose$darwin$url',
|
||||
WINDOWS: 'rancher$compose$windows$url',
|
||||
LINUX: 'rancher$compose$linux$url',
|
||||
},
|
||||
API_HOST: 'api$host',
|
||||
CATALOG_URL: 'catalog$url',
|
||||
VM_ENABLED: 'vm$enabled',
|
||||
HELP_ENABLED: 'help$enabled',
|
||||
SWARM_PORT: 'swarm$tls$port',
|
||||
ENGINE_URL: 'engine$install$url'
|
||||
API_HOST: 'api$host',
|
||||
CATALOG_URL: 'catalog$url',
|
||||
VM_ENABLED: 'vm$enabled',
|
||||
HELP_ENABLED: 'help$enabled',
|
||||
SWARM_PORT: 'swarm$tls$port',
|
||||
ENGINE_URL: 'engine$install$url',
|
||||
},
|
||||
|
||||
USER: {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ui",
|
||||
"version": "0.100.4",
|
||||
"version": "1.0.1",
|
||||
"private": true,
|
||||
"directories": {
|
||||
"doc": "doc",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ module.exports = function(app, options) {
|
|||
ws: true,
|
||||
xfwd: false,
|
||||
target: config.apiServer,
|
||||
secure: false,
|
||||
});
|
||||
|
||||
proxy.on('error', onProxyError);
|
||||
|
|
|
|||
Loading…
Reference in New Issue