Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally enable endpoints-dashboard via env var for use in cf push #1221

Merged
merged 8 commits into from
Aug 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions components/app-core/backend/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Info struct {
User *interfaces.ConnectedUser `json:"user"`
Endpoints map[string]map[string]*Endpoint `json:"endpoints"`
CloudFoundry *interfaces.CFInfo `json:"cloud-foundry,omitempty"`
PluginConfig map[string]string `json:"plugin-config,omitempty"`
}

func (p *portalProxy) info(c echo.Context) error {
Expand Down Expand Up @@ -59,6 +60,7 @@ func (p *portalProxy) getInfo(c echo.Context) (*Info, error) {
User: uaaUser,
Endpoints: make(map[string]map[string]*Endpoint),
CloudFoundry: p.Config.CloudFoundryInfo,
PluginConfig: p.Config.PluginConfig,
}
// initialize the Endpoints maps
for _, plugin := range p.Plugins {
Expand Down
1 change: 1 addition & 0 deletions components/app-core/backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ func loadPortalConfig(pc interfaces.PortalConfig) (interfaces.PortalConfig, erro
// Add custom properties
pc.CFAdminIdentifier = CFAdminIdentifier
pc.HTTPS = true
pc.PluginConfig = make(map[string]string)

return pc, nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,5 @@ type PortalConfig struct {
LoginHook LoginHookFunc
SessionStore SessionStorer
ConsoleConfig *ConsoleConfig
PluginConfig map[string]string
}
17 changes: 15 additions & 2 deletions components/app-core/frontend/src/utils/logged-in.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

var loggedIn = false;
var lastUserInteraction = moment();
var sessionChecker, dialog;
var sessionChecker, dialog, dashboardRouteFunc;

// Check the session every 30 seconds (Note: this is vey cheap to do unless the session is about to expire)
var checkSessionInterval = 30 * 1000;
Expand Down Expand Up @@ -147,7 +147,9 @@

return {
isLoggedIn: isLoggedIn,
userInteracted: userInteracted
userInteracted: userInteracted,
setDashboardRouteFunc: setDashboardRouteFunc,
getDashboardRoute: getDashboardRoute
};

function isLoggedIn() {
Expand All @@ -158,6 +160,17 @@
lastUserInteraction = moment();
}

function setDashboardRouteFunc(func) {
dashboardRouteFunc = func;
}

function getDashboardRoute() {
// At this point console-info must have been called
if (angular.isFunction(dashboardRouteFunc)) {
return dashboardRouteFunc();
}
}

function _getAccountModel() {
return modelManager.retrieve('app.model.account');
}
Expand Down
79 changes: 34 additions & 45 deletions components/app-core/frontend/src/view/application.directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,19 @@
* @namespace app.view.application.ApplicationController
* @memberof app.view.application
* @name ApplicationController
* @param {object} $q - Angular $q service
* @param {app.utils.appEventService} appEventService - the event bus service
* @param {app.model.modelManager} modelManager - the application model manager
* @param {app.model.loginManager} loginManager - the login management service
* @param {app.view.appUpgradeCheck} appUpgradeCheck - the upgrade check service
* @param {object} appLocalStorage - the Local Storage In Service
* @param {object} appUtilsService - the App Utils service
* @param {app.view.consoleSetupCheck} consoleSetupCheck - the Console Setup checkservice
* @param {object} $timeout - Angular $timeout service
* @param {$stateParams} $stateParams - Angular ui-router $stateParams service
* @param {$window} $window - Angular $window service
* @param {$rootScope} $rootScope - Angular $rootScope service
* @param {$scope} $scope - Angular $scope service
* @param {appLoggedInService} appLoggedInService - Logged In Service
* @property {app.utils.appEventService} appEventService - the event bus service
* @property {app.model.modelManager} modelManager - the application model manager
* @property {app.view.appUpgradeCheck} appUpgradeCheck - the upgrade check service
Expand All @@ -47,8 +48,9 @@
* @property {boolean} serverErrorOnLogin - a flag indicating if user login failed because of a server error.
* @class
*/
function ApplicationController(appEventService, modelManager, loginManager, appUpgradeCheck, appLocalStorage,
appUtilsService, consoleSetupCheck, $timeout, $stateParams, $window, $rootScope, $scope) {
function ApplicationController($q, appEventService, modelManager, loginManager, appUpgradeCheck, appLocalStorage,
consoleSetupCheck, $timeout, $stateParams, $window, $rootScope, $scope,
appLoggedInService) {

var vm = this;

Expand All @@ -63,7 +65,6 @@
vm.hideNavigation = $stateParams.hideNavigation;
vm.hideAccount = $stateParams.hideAccount;
vm.navbarIconsOnly = false;
vm.isEndpointsDashboardAvailable = appUtilsService.isPluginAvailable('endpointsDashboard');

vm.login = login;
vm.logout = logout;
Expand Down Expand Up @@ -184,61 +185,49 @@
*/
var account = modelManager.retrieve('app.model.account');

// Fetch the list of services instances
var serviceInstanceModel = modelManager.retrieve('app.model.serviceInstance');
var userServiceInstanceModel = modelManager.retrieve('app.model.serviceInstance.user');
/* eslint-disable */
// TODO: If this fails, we should show a notification message
/* eslint-enable */
modelManager.retrieve('app.model.serviceInstance')
.list()
.then(function onSuccess(data) {
var noEndpoints = data.numAvailable === 0;
// Admin
if (account.isAdmin()) {
// Go the endpoints dashboard if there are no CF clusters
if (noEndpoints) {
vm.redirectState = 'endpoint.dashboard';
if (!vm.isEndpointsDashboardAvailable) {
appEventService.$emit(appEventService.events.TRANSFER, 'error-page', {error: 'notSetup'});
continueLogin = false;
}
$q.all([
serviceInstanceModel.list(),
modelManager.retrieve('app.model.consoleInfo').getConsoleInfo(),
userServiceInstanceModel.list()
])
.then(function () {
var cfOnly = _.filter(serviceInstanceModel.serviceInstances, {cnsi_type: 'cf'}) || [];
var noEndpoints = cfOnly.length === 0;
var dashboardRedirect = appLoggedInService.getDashboardRoute();

if (noEndpoints) {
// Admin
if (account.isAdmin()) {
vm.redirectState = dashboardRedirect;
}
} else {
// Developer or Endpoint Dashboard plugin isn't loaded
if (noEndpoints) {
if (!vm.redirectState) {
// No CF instances, so the system is not setup and the user can't fix this
continueLogin = false;
appEventService.$emit(appEventService.events.TRANSFER, 'error-page', {error: 'notSetup'});
} else {
var userServiceInstanceModel = modelManager.retrieve('app.model.serviceInstance.user');
// Need to get the user's service list to determine if they have any connected
return userServiceInstanceModel.list().then(function () {
// Developer - allow user to connect services, if we have some and none are connected
if (userServiceInstanceModel.getNumValid() === 0) {
vm.redirectState = 'endpoint.dashboard';
if (!vm.isEndpointsDashboardAvailable) {
appEventService.$emit(appEventService.events.TRANSFER, 'error-page', {error: 'notConnected'});
continueLogin = false;
}
}
});
}
} else {
// Need to get the user's service list to determine if they have any connected
// Developer - allow user to connect services, if we have some and none are connected
if (userServiceInstanceModel.getNumValid() === 0) {
vm.redirectState = dashboardRedirect;
if (!vm.redirectState) {
appEventService.$emit(appEventService.events.TRANSFER, 'error-page', {error: 'notConnected'});
continueLogin = false;
}
}
}
})
.then(function () {
// Update consoleInfo
return modelManager.retrieve('app.model.consoleInfo').getConsoleInfo();
})
.then(function () {
// Get the user registered services once at login - only refreshed in endpoints dashboard
var userServiceInstanceModel = modelManager.retrieve('app.model.serviceInstance.user');
return userServiceInstanceModel.list();
})
.finally(function () {
vm.showGlobalSpinner = false;
if (continueLogin) {
// When we notify listeners that login has completed, in some cases we don't want them
// to redirect tp their page - we might want to control that the go to the endpoints dahsboard (for exmample).
// So, we pass this flag to tell them login happenned, but that they should not redirect
// to redirect to their page - we might want to control that they go to the endpoints dashboard (for example).
// So, we pass this flag to tell them login happened, but that they should not redirect
appEventService.$emit(appEventService.events.LOGIN, !!vm.redirectState);
// We need to do this after the login events are handled, so that ui-router states we might go to are registered
if (vm.redirectState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
applicationCtrl = $element.controller('application');
$httpBackend.when('GET', '/pp/v1/proxy/v2/info').respond(200, {});
$httpBackend.when('GET', '/pp/v1/proxy/v2/apps?page=1&results-per-page=48').respond(200, {guid: {}});
$httpBackend.when('GET', '/pp/v1/cnsis/registered').respond([]);

// For some tests, the redirected state depends on whether the endpoints dashboard is available
redirectStateName = $state.get('endpoint.dashboard') ? 'endpoint.dashboard' : 'error-page';
Expand Down Expand Up @@ -98,10 +97,11 @@
$httpBackend.when('POST', '/pp/v1/auth/login/uaa').respond(200, {account: 'dev', scope: 'foo'});
$httpBackend.when('GET', '/pp/v1/cnsis').respond(200, []);
$httpBackend.when('GET', '/pp/v1/info').respond(200, {});
$httpBackend.when('GET', '/pp/v1/cnsis/registered').respond(200, []);

$httpBackend.expectPOST('/pp/v1/auth/login/uaa');
// No endpoints are set up, so we should go to error page
$httpBackend.expectGET('/pp/v1/cnsis/registered').respond(200, []);
$httpBackend.expectGET('/pp/v1/cnsis/registered');

applicationCtrl.login('dev', 'dev');
$httpBackend.flush();
Expand Down Expand Up @@ -241,7 +241,7 @@
expect($state.current.name).toBe(redirectStateName);
});

it('should not show cluster registration if cluster count > 0', function () {
it('should go to endpoints dashboard if cluster count > 0 and none connected', function () {
var responseData = [
{id: 1, name: 'name', api_endpoint: {Scheme: 'http', Host: 'api.host.com'}, cnsi_type: 'cf'}
];
Expand All @@ -253,6 +253,27 @@
applicationCtrl.login('admin', 'admin');
$httpBackend.flush();

expect(applicationCtrl.redirectState).toBe('endpoint.dashboard');
expect(applicationCtrl.showGlobalSpinner).toBe(false);
});

it('should not go to endpoints dashboard if cluster count > 0 and at least one connected', function () {
var responseData = [
{id: 1, name: 'name', api_endpoint: {Scheme: 'http', Host: 'api.host.com'}, cnsi_type: 'cf'}
];
$httpBackend.when('GET', '/pp/v1/cnsis')
.respond(200, responseData);

var future = 50000 + (new Date()).getTime() / 1000;

$httpBackend.when('GET', '/pp/v1/info').respond(200, []);
$httpBackend.when('GET', '/pp/v1/cnsis/registered').respond(200, [
{ account: 'test', token_expiry: future, guid: 'service', cnsi_type: 'cf', name: 'test', api_endpoint: testAptEndpoint }
]);

applicationCtrl.login('admin', 'admin');
$httpBackend.flush();

expect(applicationCtrl.redirectState).toBe(false);
expect(applicationCtrl.showGlobalSpinner).toBe(false);
});
Expand All @@ -267,18 +288,35 @@
]);
});

it('should show service instance registration if we dont not have registered services', function () {
it('should show service instance registration if we don\'t have registered services', function () {
$httpBackend.when('GET', '/pp/v1/cnsis').respond(200, []);
$httpBackend.when('GET', '/pp/v1/info').respond(200, []);
$httpBackend.when('GET', '/pp/v1/cnsis/registered').respond(200, []);

applicationCtrl.login('dev', 'dev');
$httpBackend.flush();

expect(applicationCtrl.redirectState).toBe('endpoint.dashboard');
expect(applicationCtrl.showGlobalSpinner).toBe(false);
});

it('should not show service instance registration if we have registered services', function () {
it('should show service instance registration if we don\'t have connected services', function () {
var responseData = [
{id: 1, name: 'name', api_endpoint: {Scheme: 'http', Host: 'api.host.com'}, cnsi_type: 'cf'}
];
$httpBackend.when('GET', '/pp/v1/cnsis')
.respond(200, responseData);
$httpBackend.when('GET', '/pp/v1/info').respond(200, []);
$httpBackend.when('GET', '/pp/v1/cnsis/registered').respond(200, []);

applicationCtrl.login('dev', 'dev');
$httpBackend.flush();

expect(applicationCtrl.redirectState).toBe('endpoint.dashboard');
expect(applicationCtrl.showGlobalSpinner).toBe(false);
});

it('should not show service instance registration if we have connected services', function () {
var future = 50000 + (new Date()).getTime() / 1000;

$httpBackend.when('GET', '/pp/v1/info').respond(200, []);
Expand All @@ -289,6 +327,7 @@
applicationCtrl.login('dev', 'dev');
$httpBackend.flush();

expect(applicationCtrl.redirectState).toBe(false);
expect(applicationCtrl.showGlobalSpinner).toBe(false);
});
});
Expand Down
26 changes: 22 additions & 4 deletions components/cloud-foundry-hosting/backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ import (
)

const (
VCapApplication = "VCAP_APPLICATION"
CFApiURLOverride = "CF_API_URL"
CFApiForceSecure = "CF_API_FORCE_SECURE"
cfSessionCookieName = "JSESSIONID"
VCapApplication = "VCAP_APPLICATION"
CFApiURLOverride = "CF_API_URL"
CFApiForceSecure = "CF_API_FORCE_SECURE"
cfSessionCookieName = "JSESSIONID"
ForceEndpointDashboard = "FORCE_ENDPOINT_DASHBOARD"
)

type CFHosting struct {
Expand Down Expand Up @@ -100,6 +101,23 @@ func (ch *CFHosting) Init() error {
log.Info("No forced override to HTTPS")
}

disableEndpointDashboard := true
if config.IsSet(ForceEndpointDashboard) {
// Force the Endpoint Dashboard to be visible?
if forceStr, err := config.GetValue(ForceEndpointDashboard); err == nil {
if force, err := strconv.ParseBool(forceStr); err == nil {
disableEndpointDashboard = !force
}
}
}

if disableEndpointDashboard {
log.Info("Endpoint Dashboard has been DISABLED")
} else {
log.Info("Endpoint Dashboard has been ENABLED")
}
ch.portalProxy.GetConfig().PluginConfig["endpointsDashboardDisabled"] = strconv.FormatBool(disableEndpointDashboard)

log.Infof("Using Cloud Foundry API URL: %s", appData.API)
cfEndpointSpec, _ := ch.portalProxy.GetEndpointTypeSpec("cf")
newCNSI, _, err := cfEndpointSpec.Info(appData.API, true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
appWallConfigNoClusters(ngMockE2E.$httpBackend);
helpers.setBrowserNormal();
helpers.loadApp();
applicationWall.showApplications();
});

afterAll(function () {
Expand Down
1 change: 1 addition & 0 deletions components/endpoints-dashboard/i18n/en_US/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"start": "To enable developers to use the [[@:console]] to interact with [[@:product.name]],",
"link": "please register endpoints.",
"end": "The process of registering these endpoints will make them discoverable for anyone who logs into the [[@:product.console]]. Once you register an endpoint, we recommend connecting it to your account so you can manage it.",
"admin": "To access your cloud native workloads and other related third party services, connect with your personal credentials to the corresponding registered services.",
"non-admin": "To access your cloud native workloads and other related third party services, connect with your personal credentials to the corresponding registered services. Registered services are provided by your systems administrator."
},
"no-endpoints": {
Expand Down
Loading