From 8a44830bb9bb8af8d10c260843add2549d6c8ed7 Mon Sep 17 00:00:00 2001 From: Florent BENOIT Date: Fri, 4 Nov 2016 11:41:22 +0100 Subject: [PATCH] CHE-2059 Add ssh view for workspace in UD - allow to view default ssh key for workspace - allow to remove this default key - allow to generate default key if not present Change-Id: Ifca18aed416f91846cf1adeb2a6e32389df196d3 Signed-off-by: Florent BENOIT --- dashboard/src/app/index.module.ts | 1 + .../workspace-details-ssh.controller.ts | 118 ++++++++++++++++++ .../workspace-details-ssh.directive.ts | 46 +++++++ .../workspace-ssh/workspace-details-ssh.html | 40 ++++++ .../workspace-ssh/workspace-details-ssh.styl | 26 ++++ .../src/app/workspaces/workspaces-config.ts | 5 + .../src/components/api/che-api-config.ts | 2 + .../src/components/api/che-api.factory.ts | 16 ++- .../src/components/api/che-ssh.factory.ts | 96 ++++++++++++++ 9 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.controller.ts create mode 100644 dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.directive.ts create mode 100644 dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.html create mode 100644 dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.styl create mode 100644 dashboard/src/components/api/che-ssh.factory.ts diff --git a/dashboard/src/app/index.module.ts b/dashboard/src/app/index.module.ts index edea2597f7f..bae894fcd17 100644 --- a/dashboard/src/app/index.module.ts +++ b/dashboard/src/app/index.module.ts @@ -115,6 +115,7 @@ initModule.run(['$rootScope', '$location', '$routeParams', 'routingRedirect', '$ $rootScope.showIDE = false; workspaceDetailsService.addSection('Projects', '', 'icon-ic_inbox_24px'); + workspaceDetailsService.addSection('SSH', '', 'icon-ic_vpn_key_24px'); // here only to create instances of these components cheIdeFetcher; diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.controller.ts b/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.controller.ts new file mode 100644 index 00000000000..8ea668aff54 --- /dev/null +++ b/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.controller.ts @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +import {CheWorkspace} from "../../../../components/api/che-workspace.factory"; +import {CheNotification} from "../../../../components/notification/che-notification.factory"; +import {CheSsh} from "../../../../components/api/che-ssh.factory"; +'use strict'; + +/** + * @ngdoc controller + * @name workspace.details.controller:WorkspaceDetailsSSHCtrl + * @description This class is handling the controller for details of workspace : section ssh + * @author Florent Benoit + */ +export class WorkspaceDetailsSshCtrl { + + /** + * Workspace. + */ + private cheWorkspace: CheWorkspace; + + /** + * SSH. + */ + private cheSsh: CheSsh; + + /** + * Notification. + */ + private cheNotification: CheNotification; + + /** + * Material Design Dialog Service + */ + private $mdDialog: ng.material.IDialogService; + + /** + * Angular Log service. + */ + private $log: ng.ILogService; + + /** + * Angular Q service. + */ + private $q: ng.IQService; + + private $timeout : ng.ITimeoutService; + + private privateKey : string; + private publicKey : string; + + private namespace : string; + private workspaceName : string; + private workspaceKey : string; + private workspace : any; + private workspaceId: string; + + private sshKeyPair : any; + + + /** + * Default constructor that is using resource + * @ngInject for Dependency injection + */ + constructor($route : ng.route.IRouteService, cheSsh: CheSsh, cheWorkspace: CheWorkspace, cheNotification, $mdDialog : ng.material.IDialogService, $log : ng.ILogService, $q : ng.IQService, $timeout : ng.ITimeoutService) { + this.cheWorkspace = cheWorkspace; + this.cheSsh = cheSsh; + this.cheNotification = cheNotification; + this.$mdDialog = $mdDialog; + this.$log = $log; + this.$q = $q; + + this.namespace = $route.current.params.namespace; + this.workspaceName = $route.current.params.workspaceName; + this.workspaceKey = this.namespace + ":" + this.workspaceName; + + this.updateData(); + + } + + + updateData() { + this.workspace = this.cheWorkspace.getWorkspaceByName(this.namespace, this.workspaceName); + this.workspaceId = this.workspace.id; + + // get ssh key + this.cheSsh.fetchKey("workspace", this.workspaceId).finally(() => { + this.sshKeyPair = this.cheSsh.getKey("workspace", this.workspaceId); + + }); + } + + /** + * Remove the default workspace keypair + */ + removeDefaultKey() { + this.cheSsh.removeKey("workspace", this.workspaceId).then( + () => {this.$timeout( this.updateData(), 3000)} + ); + } + + /** + * Generate a new default workspace keypair + */ + generateDefaultKey() { + this.cheSsh.generateKey("workspace", this.workspaceId).then(() => {this.$timeout( this.updateData(), 3000)}); + } + + + +} diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.directive.ts b/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.directive.ts new file mode 100644 index 00000000000..8c0a85c7bb1 --- /dev/null +++ b/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.directive.ts @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +'use strict'; + +/** + * @ngdoc directive + * @name workspaces.details.directive:workspaceDetailsSSH + * @restrict E + * @element + * + * @description + * ` for displaying workspace ssh entry. + * + * @usage + * + * + * @author Florent Benoit + */ +export class WorkspaceDetailsSsh { + + + restrict: string = 'E'; + templateUrl: string = 'app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.html'; + + controller: string = 'WorkspaceDetailsSshCtrl'; + controllerAs: string = 'workspaceDetailsSshCtrl'; + bindToController: boolean = true; + + + /** + * Default constructor that is using resource + * @ngInject for Dependency injection + */ + constructor () { + + } + +} diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.html b/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.html new file mode 100644 index 00000000000..f9bd053f1d0 --- /dev/null +++ b/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.html @@ -0,0 +1,40 @@ + + + + + +
+ + + + + +
+ + +
+ + There is no default SSH key associated to this current workspace. A new key can be generated. + Note: Workspace is currently in RUNNING state. It will require a restart of the workspace in order to be taken into account. +
+
+ +
+ diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.styl b/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.styl new file mode 100644 index 00000000000..b61bc8e4b97 --- /dev/null +++ b/dashboard/src/app/workspaces/workspace-details/workspace-ssh/workspace-details-ssh.styl @@ -0,0 +1,26 @@ +.workspace-ssh-content + margin 0 + button + margin 0 + + +.workspace-ssh-content + .che-text-info-mobile span, .che-text-info-desktop span + border-width 0 + padding-bottom 20px + + .che-text-info-mobile span label, .che-text-info-desktop span label + max-width 500px + word-wrap break-word + font-family Fixed, monospace + color $disabled-color + + .che-text-info .copy-clipboard + margin-top 50px + margin-left 20px + + .workspace-ssh-content-notice + padding-top 20px + +.workspace-ssh-content .workspace-ssh-content-private .che-text-info-desktop span label + white-space pre diff --git a/dashboard/src/app/workspaces/workspaces-config.ts b/dashboard/src/app/workspaces/workspaces-config.ts index 8a363da4bab..7fe526ac172 100644 --- a/dashboard/src/app/workspaces/workspaces-config.ts +++ b/dashboard/src/app/workspaces/workspaces-config.ts @@ -21,6 +21,8 @@ import {UsageChart} from './list-workspaces/workspace-item/usage-chart.directive import {WorkspaceItemCtrl} from './list-workspaces/workspace-item/workspace-item.controller'; import {WorkspaceEditModeOverlay} from './workspace-edit-mode/workspace-edit-mode-overlay.directive'; import {WorkspaceEditModeToolbarButton} from './workspace-edit-mode/workspace-edit-mode-toolbar-button.directive'; +import {WorkspaceDetailsSsh} from './workspace-details/workspace-ssh/workspace-details-ssh.directive'; +import {WorkspaceDetailsSshCtrl} from './workspace-details/workspace-ssh/workspace-details-ssh.controller'; import {WorkspaceDetailsProjectsCtrl} from './workspace-details/workspace-projects/workspace-details-projects.controller'; import {WorkspaceDetailsService} from './workspace-details/workspace-details.service'; import {ExportWorkspaceController} from './workspace-details/export-workspace/export-workspace.controller'; @@ -83,6 +85,9 @@ export class WorkspacesConfig { new CreateProjectStackLibrarySelectedStackFilter(register); + register.controller('WorkspaceDetailsSshCtrl', WorkspaceDetailsSshCtrl); + register.directive('workspaceDetailsSsh', WorkspaceDetailsSsh); + register.controller('ListWorkspacesCtrl', ListWorkspacesCtrl); register.controller('WorkspaceDetailsController', WorkspaceDetailsController); register.controller('WorkspaceStacksController', WorkspaceStacksController); diff --git a/dashboard/src/components/api/che-api-config.ts b/dashboard/src/components/api/che-api-config.ts index e6bde6c75b3..8a1a69d9117 100644 --- a/dashboard/src/components/api/che-api-config.ts +++ b/dashboard/src/components/api/che-api-config.ts @@ -30,6 +30,7 @@ import {CheRemote} from './remote/che-remote.factory'; import {CheOAuthProvider} from './che-o-auth-provider.factory'; import {CheEnvironmentRegistry} from './environment/che-environment-registry.factory'; import {CheAgent} from './che-agent.factory'; +import {CheSsh} from './che-ssh.factory'; import {CheNamespaceRegistry} from './namespace/che-namespace-registry.factory'; export class ApiConfig { @@ -54,6 +55,7 @@ export class ApiConfig { register.factory('cheOAuthProvider', CheOAuthProvider); register.factory('cheEnvironmentRegistry', CheEnvironmentRegistry); register.factory('cheAgent', CheAgent); + register.factory('cheSsh', CheSsh); register.factory('cheNamespaceRegistry', CheNamespaceRegistry); } } diff --git a/dashboard/src/components/api/che-api.factory.ts b/dashboard/src/components/api/che-api.factory.ts index 5dd504d41ae..29054bc3f63 100644 --- a/dashboard/src/components/api/che-api.factory.ts +++ b/dashboard/src/components/api/che-api.factory.ts @@ -8,6 +8,8 @@ * Contributors: * Codenvy, S.A. - initial API and implementation */ + +import {CheSsh} from "./che-ssh.factory"; 'use strict'; @@ -18,12 +20,15 @@ */ export class CheAPI { + + private cheSsh : CheSsh; + /** * Default constructor that is using resource * @ngInject for Dependency injection */ constructor(cheWorkspace, cheProfile, chePreferences, cheProjectTemplate, cheWebsocket, cheService, - cheAdminPlugins, cheAdminService, cheRecipe, cheRecipeTemplate, cheStack, cheOAuthProvider, cheAgent) { + cheAdminPlugins, cheAdminService, cheRecipe, cheRecipeTemplate, cheStack, cheOAuthProvider, cheAgent, cheSsh : CheSsh) { this.cheWorkspace = cheWorkspace; this.cheProfile = cheProfile; this.chePreferences = chePreferences; @@ -37,6 +42,7 @@ export class CheAPI { this.cheStack = cheStack; this.cheOAuthProvider = cheOAuthProvider; this.cheAgent = cheAgent; + this.cheSsh = cheSsh; } @@ -145,4 +151,12 @@ export class CheAPI { return this.cheAgent; } + /** + * Gets Che ssh API + * @returns {CheSsh} + */ + getSsh() { + return this.cheSsh; + } + } diff --git a/dashboard/src/components/api/che-ssh.factory.ts b/dashboard/src/components/api/che-ssh.factory.ts new file mode 100644 index 00000000000..ef237d1fe42 --- /dev/null +++ b/dashboard/src/components/api/che-ssh.factory.ts @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015-2016 Codenvy, S.A. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Codenvy, S.A. - initial API and implementation + */ +'use strict'; + +/** + * This class is handling the ssh keys + * @author Florent Benoit + */ +export class CheSsh { + + /** + * Angular Resource service. + */ + private $resource: ng.resource.IResourceService; + + /** + * Angular Promise service. + */ + private $q: ng.IQService; + + /** + * Remote API for SSH. + */ + private remoteSshAPI: ng.resource.IResourceClass>; + remoteSshAPI: { getKeyPair: Function; removeKey : Function, generateKey: Function}; + + private sshKeyPairs : Map; + + /** + * Default constructor that is using resource + * @ngInject for Dependency injection + */ + constructor($resource : ng.resource.IResourceService, $q : ng.IQService) { + + // keep resource + this.$resource = $resource; + this.$q = $q; + + + this.sshKeyPairs = new Map(); + + // remote call + this.remoteSshAPI = this.$resource('/api/ssh', {}, { + getKeyPair: { method: 'GET', url: '/api/ssh/:serviceId/:nameId'}, + removeKey: { method: 'DELETE', url: '/api/ssh/:serviceId/:nameId'}, + generateKey: { method: 'POST', url: '/api/ssh/generate'}, + }); + } + + /** + * Fetch the keyPair + */ + fetchKey(serviceId: string, nameId: string) { + var defer = this.$q.defer(); + let promise = this.remoteSshAPI.getKeyPair({serviceId: serviceId, nameId: nameId}).$promise; + + promise.then((sshKeyPair) => { + this.sshKeyPairs.set(serviceId + '/' + nameId, sshKeyPair); + defer.resolve(); + }, (error) => { + if (error.status != 304) { + this.sshKeyPairs.delete(serviceId + '/' + nameId); + defer.reject(error); + } else { + defer.resolve(); + } + }); + + return defer.promise; + } + + /** + * Get ssh keypair + * @returns + */ + getKey(serviceId: string, nameId: string) { + return this.sshKeyPairs.get(serviceId + '/' + nameId); + } + + removeKey(serviceId: string, nameId: string) { + return this.remoteSshAPI.removeKey({serviceId: serviceId, nameId: nameId}).$promise; + } + + generateKey(serviceId: string, nameId: string) { + return this.remoteSshAPI.generateKey({}, {service: serviceId, name: nameId}).$promise; + } + +}