Load against new APIs

This commit is contained in:
Vincent Fiduccia 2017-11-17 02:24:08 -07:00
parent 65c36eab5c
commit 544c921a48
No known key found for this signature in database
GPG Key ID: 2B29AD6BB2BB2582
20 changed files with 112 additions and 240 deletions

View File

@ -26,7 +26,7 @@ const App = Application.extend({
dependencies: {
services: [
'access',
'auth-store',
'authn-store',
'catalog',
'endpoint',
'github',

View File

@ -1,6 +1,7 @@
import { oneWay } from '@ember/object/computed';
import { inject as service } from '@ember/service';
import Controller from '@ember/controller';
import { run } from '@ember/runloop';
export default Controller.extend({
settings: service(),
@ -28,6 +29,14 @@ export default Controller.extend({
},
},
init() {
this._super(...arguments);
if ( this.get('app.environment') === 'development' ) {
run.backburner.DEBUG = true;
}
},
// currentRouteName is set by Ember.Router
// but getting the application controller to get it is inconvenient sometimes
currentRouteNameChanged: function() {

View File

@ -77,6 +77,7 @@ export default Route.extend({
this.transitionTo('failWhale');
console.log('Application Error', (err ? err.stack : undefined));
debugger;
},
goToPrevious(def) {

View File

@ -7,13 +7,13 @@ import Route from '@ember/routing/route';
import Subscribe from 'ui/mixins/subscribe';
import { inject as service } from '@ember/service';
import { later, scheduleOnce, cancel } from '@ember/runloop';
import { reject, Promise as EmberPromise, resolve } from 'rsvp';
import { xhrConcur } from 'ui/utils/platform';
import { reject, resolve, all as PromiseAll } from 'rsvp';
const CHECK_AUTH_TIMER = 60*10*1000;
export default Route.extend(Subscribe, PromiseToCb, {
access: service(),
authnStore: service('authn-store'),
clusterStore: service('cluster-store'),
cookies: service(),
language: service('user-language'),
@ -58,45 +58,25 @@ export default Route.extend(Subscribe, PromiseToCb, {
this.get('session').set(C.SESSION.BACK_TO, undefined);
let promise = new EmberPromise((resolve, reject) => {
let tasks = {
userSchemas: this.toCb('loadUserSchemas'),
clusters: this.toCb('loadClusters'),
projects: this.toCb('loadProjects'),
preferences: this.toCb('loadPreferences'),
settings: this.toCb('loadPublicSettings'),
project: ['clusters','projects', 'preferences',
this.toCb('selectProject',transition)],
projectSchemas: ['project', this.toCb('loadProjectSchemas')],
instances: ['projectSchemas', this.cbFind('instance')],
services: ['projectSchemas', this.cbFind('service')],
hosts: ['projectSchemas', this.cbFind('host')],
stacks: ['projectSchemas', this.cbFind('stack')],
mounts: ['projectSchemas', this.cbFind('mount', 'store', {filter: {state_ne: 'inactive'}})],
storagePools: ['projectSchemas', this.cbFind('storagepool')],
volumes: ['projectSchemas', this.cbFind('volume')],
volumeTemplates: ['projectSchemas', this.cbFind('volumetemplate')],
certificate: ['projectSchemas', this.cbFind('certificate')],
secret: ['projectSchemas', this.toCb('loadSecrets')],
identities: ['userSchemas', this.cbFind('identity', 'userStore')],
};
async.auto(tasks, xhrConcur, function(err, res) {
if ( err ) {
reject(err);
} else {
resolve(res);
}
});
}, 'Load all the things');
return promise.then((hash) => {
return EmberObject.create(hash);
return PromiseAll([
this.loadSchemas('clusterStore'),
// this.loadSchemas('authnStore'),
this.loadClusters(),
this.loadProjects()
//this.loadPreferences(),
//this.loadPublicSettings()
]).then(() => {
return this.selectProject(transition);
}).then(() => {
return this.loadSchemas('store');
}).then(() => {
return PromiseAll([
this.preload('workload'),
this.preload('nodes'),
this.preload('pods'),
]);
}).catch((err) => {
return this.loadingError(err, transition, EmberObject.create({
projects: [],
project: null,
}));
return this.loadingError(err, transition);
});
},
@ -139,35 +119,23 @@ export default Route.extend(Subscribe, PromiseToCb, {
this.get('storeReset').reset();
},
loadingError(err, transition, ret) {
loadingError(err, transition) {
let isAuthEnabled = this.get('access.enabled');
let isAuthFail = [401,403].indexOf(err.status) >= 0;
let isAuthFail = err && err.status && [401,403].indexOf(err.status) >= 0;
var msg = Errors.stringify(err);
console.log('Loading Error:', msg, err);
if ( err && (isAuthEnabled || isAuthFail) ) {
this.set('access.enabled', true);
this.send('logout', transition, isAuthFail, (isAuthFail ? undefined : msg));
return;
} else {
this.replaceWith('authenticated.clusters');
}
this.replaceWith('authenticated.clusters');
return ret;
},
cbFind(type, store='store', opt=null) {
return (results, cb) => {
if ( typeof results === 'function' ) {
cb = results;
results = null;
}
return this.get(store).find(type,null,opt).then(function(res) {
cb(null, res);
}).catch(function(err) {
cb(err, null);
});
};
preload(type, store='store', opt=null) {
return this.get(store).find(type,null,opt);
},
loadPreferences() {
@ -189,22 +157,14 @@ export default Route.extend(Subscribe, PromiseToCb, {
});
},
loadProjectSchemas() {
var store = this.get('store');
loadSchemas(storeName) {
var store = this.get(storeName);
store.resetType('schema');
return store.rawRequest({url:'schema', dataType: 'json'}).then((xhr) => {
store._bulkAdd('schema', xhr.body.data);
});
},
loadUserSchemas() {
// @TODO Inline me into releases
let userStore = this.get('userStore');
return userStore.rawRequest({url:'schema', dataType: 'json'}).then((xhr) => {
userStore._bulkAdd('schema', xhr.body.data);
});
},
loadClusters() {
let svc = this.get('scope');
return svc.getAllClusters().then((all) => {
@ -281,7 +241,7 @@ export default Route.extend(Subscribe, PromiseToCb, {
error(err,transition) {
// Unauthorized error, send back to login screen
if ( err.status === 401 )
if ( err && err.status === 401 )
{
this.send('logout',transition,true);
return false;

View File

@ -1,6 +1,6 @@
import initializer from 'ember-api-store/initializers/store';
export default {
name: 'auth-store',
initialize: initializer('auth-store','authStore')
name: 'authn-store',
initialize: initializer('authn-store','authnStore')
};

View File

@ -2,17 +2,13 @@ import StoreTweaks from 'ui/mixins/store-tweaks';
export function initialize(instance) {
var application = instance.lookup('application:main');
var store = instance.lookup('service:auth-store');
var store = instance.lookup('service:authn-store');
store.reopen(StoreTweaks);
store.reopen({
removeAfterDelete: false,
baseUrl: application.authEndpoint,
skipTypeifyKeys: ['labels'],
});
store.baseUrl = application.authenticationEndpoint;
}
export default {
name: 'auth-store',
name: 'authn-store',
initialize: initialize
};

View File

@ -6,7 +6,7 @@ export function initialize(instance) {
var cookies = instance.lookup('service:cookies');
store.reopen(StoreTweaks);
store.baseUrl = application.apiEndpoint;
store.baseUrl = application.clusterEndpoint;
let timeout = cookies.get('timeout');
if ( timeout ) {

View File

@ -99,7 +99,10 @@ module.exports = function(environment) {
environment: environment,
apiServer: 'http://localhost:8080',
legacyApiEndpoint: '/v2',
apiEndpoint: '/v3',
apiEndpoint: '/v1-workload',
clusterEndpoint: '/v1-cluster',
authenticationEndpoint: '/v1-authn',
authorizationEndpoint: '/v1-authz',
// betaApiEndpoint: '/v3',
catalogServer: '',
catalogEndpoint: '/v1-catalog',

View File

@ -11,7 +11,7 @@ const Eng = Engine.extend({
dependencies: {
services: [
'access',
'auth-store',
'authn-store',
'catalog',
'endpoint',
'github',

View File

@ -4,6 +4,6 @@ import { inject as service } from '@ember/service'
export default Route.extend({
userStore: service('user-store'),
model: function() {
return this.get('userStore').find('account', null, {filter: {'kind_ne': ['service','agent']}, forceReload: true});
// @TODO need schemas... return this.get('userStore').find('account', null, {filter: {'kind_ne': ['service','agent']}, forceReload: true});
},
});

View File

@ -14,8 +14,9 @@ export default Route.extend({
this.get('scope').setPageScope('cluster');
}
},
redirect() {
this.transitionTo('settings.auth');
this.transitionTo('accounts');
},
beforeModel() {
@ -29,6 +30,12 @@ export default Route.extend({
model() {
let settings = this.get('settings');
return EmberObject.create({
host: '',
catalog: '',
telemetry: 'out',
});
return this.get('userStore').find('setting').then(() => {
return EmberObject.create({
host: settings.get(C.SETTING.API_HOST),

View File

@ -2,9 +2,9 @@ import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default Route.extend({
authStore: service('auth-store'),
authnStore: service('authn-store'),
model: function() {
return this.get('authStore').find('config', null, {forceReload: true}).then(function(collection) {
return this.get('authnStore').find('config', null, {forceReload: true}).then(function(collection) {
return collection;
});
},

View File

@ -3,12 +3,6 @@ import { inject as service } from '@ember/service';
export default Route.extend({
access: service(),
authStore: service('auth-store'),
beforeModel: function() {
return this.get('authStore').rawRequest({url: '/v1-auth/schemas', dataType: 'json'}).then((resp) => {
return this.get('authStore')._bulkAdd('schema', resp.body.data);
});
},
model: function() {
var route = (this.get('access.provider')||'').toLowerCase().replace(/config$/i,'');

View File

@ -2,9 +2,9 @@ import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default Route.extend({
authStore: service('auth-store'),
authnStore: service('authn-store'),
model: function() {
return this.get('authStore').find('config', null, {forceReload: true}).then(function(collection) {
return this.get('authnStore').find('config', null, {forceReload: true}).then(function(collection) {
return collection;
});
},

View File

@ -8,37 +8,6 @@ module.exports = function(environment) {
modulePrefix: 'global-admin',
environment: environment,
APP: {
// Here you can pass flags/options to your application instance
// when it is created
appName: 'Rancher',
mode: mode,
environment: environment,
apiServer: 'http://localhost:8080',
legacyApiEndpoint: '/v2',
apiEndpoint: '/v3',
catalogServer: '',
catalogEndpoint: '/v1-catalog',
authServer: '',
authEndpoint: '/v1-auth',
telemetryEndpoint: '/v1-telemetry',
webhookEndpoint: '/v1-webhooks',
clusterToken: '%CLUSTERID%',
projectToken: '%PROJECTID%',
magicEndpoint: '/r',
kubernetesBase: '/k8s',
kubectlEndpoint: '/r/projects/%PROJECTID%/kubectld:8091/v1-kubectl',
kubernetesDashboard: '/k8s/clusters/%CLUSTERID%/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy/',
projectEndpoint: '/v3/projects/%PROJECTID%',
proxyEndpoint: '/v3/proxy',
wsEndpoint: '/v3/projects/%PROJECTID%/subscribe' +
'?eventNames=resource.change' +
'&resourceType_ne=auditLog' +
'&resourceType_ne=serviceLog' +
'&resourceType_ne=deploymentUnit',
baseAssets: '/',
stripe: {
publishableKey: 'pk_test_g925RcuVORh2KgHWfFbE80by'
},
},
};

View File

@ -17,7 +17,7 @@ export default Service.extend({
// These are set by authenticated/route
// Is access control enabled
enabled: null,
enabled: false, // @TODO have auth again someday... null,
// What kind of access control
provider: null,

View File

@ -1,5 +1,4 @@
import { equal } from '@ember/object/computed';
import { computed } from '@ember/object';
import { inject as service } from '@ember/service';
import Component from '@ember/component';
import ContainerChoices from 'ui/mixins/container-choices';

View File

@ -3,7 +3,6 @@ import {
resolve,
Promise as EmberPromise
} from 'rsvp';
import { alias } from '@ember/object/computed';
import Service, { inject as service } from '@ember/service';
import C from 'shared/utils/constants';
import { computed } from '@ember/object';
@ -26,6 +25,12 @@ export default Service.extend({
// currentCluster: alias('current.cluster'),
init() {
this._super(...arguments);
this.set('all', []);
this.set('allClusters', []);
},
setPageScope: function(scope) {
return this.set('currentPageScope', scope);
},
@ -48,10 +53,11 @@ export default Service.extend({
}
// TODO - this will change to use the clusters store when api is ready
return this.get('userStore').find('project', null, opt).then(() => {
return this.get('userStore').all('project');
return this.get('store').find('project', null, opt).then(() => {
return this.get('store').all('project');
});
},
getAllClusters: function() {
var opt = {
url: 'clusters', // This is called in authenticated/route before schemas are loaded
@ -82,10 +88,10 @@ export default Service.extend({
});
},
selectDefaultCluster: function(desired) {
selectDefaultCluster: function() {
var self = this;
var cookies = this.get('cookies');
this.controller
return this._activeClusterFromId(cookies.get(C.COOKIE.CLUSTER)).then(selectCluster)
.catch(() => {
@ -102,24 +108,19 @@ export default Service.extend({
else if ( this.get('access.admin') )
{
// Then if you're an admin the first active of any kind
return this.getAllClusters().then((all) => {
var firstActive = all.find((cluster) => {
return ACTIVEISH.includes(cluster.get('state'));
});
var firstActive = this.get('allClusters').find((cluster) => {
return ACTIVEISH.includes(cluster.get('state'));
});
if ( firstActive )
{
return selectCluster(firstActive, true);
}
else
{
// go to cluster managment page
return clusterFail();
}
}).catch(() => {
if ( firstActive )
{
return selectCluster(firstActive, true);
}
else
{
// go to cluster managment page
return clusterFail();
});
}
}
else
{
@ -145,7 +146,7 @@ export default Service.extend({
}
else
{
this.get('cookies').remove(C.COOKIE.CLUSTER);
cookies.remove(C.COOKIE.CLUSTER);
return self.setCurrentCluster(null);
}
}
@ -183,22 +184,18 @@ export default Service.extend({
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.find((project) => {
return ACTIVEISH.includes(project.get('state'));
});
if ( firstActive )
{
return select(firstActive, true);
}
else
{
return this.selectDefaultCluster(null);
}
}).catch(() => {
return this.selectDefaultCluster(null);
var firstActive = this.get('all').find((project) => {
return ACTIVEISH.includes(project.get('state'));
});
if ( firstActive )
{
return select(firstActive, true);
}
else
{
return this.selectDefaultCluster();
}
}
else
{

View File

@ -1,5 +1,5 @@
import { alias } from '@ember/object/computed';
import { Promise as EmberPromise } from 'rsvp';
import { resolve, Promise as EmberPromise } from 'rsvp';
import { isArray } from '@ember/array';
import Evented from '@ember/object/evented';
import Service, { inject as service } from '@ember/service';
@ -100,6 +100,8 @@ export default Service.extend(Evented, {
},
load(names) {
return resolve();
if ( !isArray(names) ) {
names = [names];
}

View File

@ -26,16 +26,24 @@ module.exports = function(app, options) {
let map = {
'API': config.apiEndpoint,
'Cluster': config.clusterEndpoint,
'AuthN': config.authenticationEndpoint,
'AuthZ': config.authorizationEndpoint,
'Catalog': config.catalogEndpoint,
// 'Beta API': config.betaApiEndpoint,
'Legacy API': config.legacyApiEndpoint,
// 'Legacy API': config.legacyApiEndpoint,
'K8s': config.kubernetesBase,
'Magic': config.magicEndpoint,
'Telemetry': config.telemetryEndpoint,
'WebHook': config.webhookEndpoint,
'Meta': '/meta',
'Swagger': '/swaggerapi',
'Version': '/version',
}
// Rancher API
console.log('Proxying API to', config.apiServer);
console.log('Proxying APIs to', config.apiServer);
Object.keys(map).forEach(function(label) {
let base = map[label];
app.use(base, function(req, res, next) {
@ -47,79 +55,6 @@ module.exports = function(app, options) {
proxy.web(req, res);
});
});
// New hotness
app.use('/meta', function(req, res, next) {
// include root path in proxied request
req.url = path.join('/meta', req.url);
req.headers['X-Forwarded-Proto'] = req.protocol;
proxyLog('Meta', req);
proxy.web(req, res);
});
// Kubernetes needs this API
app.use('/swaggerapi', function(req, res, next) {
// include root path in proxied request
req.url = path.join('/swaggerapi', req.url);
req.headers['X-Forwarded-Proto'] = req.protocol;
proxyLog('K8sSwag', req);
proxy.web(req, res);
});
app.use('/version', function(req, res, next) {
// include root path in proxied request
req.url = '/version';
req.headers['X-Forwarded-Proto'] = req.protocol;
proxyLog('K8sVers', req);
proxy.web(req, res);
});
// Catalog API
var catalogPath = config.catalogEndpoint;
// Default catalog to the regular API
var catalogServer = config.catalogServer || config.apiServer;
if ( catalogServer !== config.apiServer ) {
console.log('Proxying Catalog to', catalogServer);
}
app.use(catalogPath, function(req, res, next) {
req.headers['X-Forwarded-Proto'] = req.protocol;
var catalogProxy = HttpProxy.createProxyServer({
xfwd: false,
target: catalogServer
});
catalogProxy.on('error', onProxyError);
// include root path in proxied request
req.url = path.join(catalogPath, req.url);
proxyLog('Catalog', req);
catalogProxy.web(req, res);
});
// Auth API
var authPath = config.authEndpoint;
var authServer = config.authServer || config.apiServer;
if ( authServer !== config.apiServer ) {
console.log('Proxying Auth to', authServer);
}
app.use(authPath, function(req, res, next) {
req.headers['X-Forwarded-Proto'] = req.protocol;
var catalogProxy = HttpProxy.createProxyServer({
xfwd: false,
target: authServer
});
catalogProxy.on('error', onProxyError);
req.url = path.join(authPath, req.url);
proxyLog('Auth', req);
catalogProxy.web(req, res);
});
}
function onProxyError(err, req, res) {