From c9be731ff37b8be9be9250ef681be79f0ba4600e Mon Sep 17 00:00:00 2001 From: Oleksii Kurinnyi Date: Mon, 6 Nov 2017 14:22:30 +0200 Subject: [PATCH] Dashboard: fixed the diagnostics feature (#7199) * code clean-up Signed-off-by: Oleksii Kurinnyi * CHE-6874: fix rerun of diagnostics Signed-off-by: Oleksii Kurinnyi * CHE-6919: fix the diagnostics feature Signed-off-by: Oleksii Kurinnyi --- .../diagnostics/diagnostic-callback-state.ts | 1 + .../app/diagnostics/diagnostic-callback.ts | 152 +++++------ .../src/app/diagnostics/diagnostic-item.ts | 32 +-- .../app/diagnostics/diagnostic-part-state.ts | 1 + .../src/app/diagnostics/diagnostic-part.ts | 60 ++--- .../src/app/diagnostics/diagnostics-config.ts | 4 +- .../app/diagnostics/diagnostics-widget.html | 6 +- .../app/diagnostics/diagnostics.controller.ts | 114 ++++----- .../app/diagnostics/diagnostics.directive.ts | 7 +- .../diagnostics-websocket-wsmaster.factory.ts | 15 +- ...stics-workspace-check-workspace.factory.ts | 142 +++++------ ...agnostics-workspace-start-check.factory.ts | 239 +++++++++--------- dashboard/src/app/index.module.ts | 2 +- 13 files changed, 386 insertions(+), 389 deletions(-) diff --git a/dashboard/src/app/diagnostics/diagnostic-callback-state.ts b/dashboard/src/app/diagnostics/diagnostic-callback-state.ts index 8eca047675..0ed663cbdd 100644 --- a/dashboard/src/app/diagnostics/diagnostic-callback-state.ts +++ b/dashboard/src/app/diagnostics/diagnostic-callback-state.ts @@ -8,6 +8,7 @@ * Contributors: * Red Hat, Inc. - initial API and implementation */ + /** * Defines the state of the diagnostic callback * @author Florent Benoit diff --git a/dashboard/src/app/diagnostics/diagnostic-callback.ts b/dashboard/src/app/diagnostics/diagnostic-callback.ts index 1bc7300317..f98c37d7bb 100644 --- a/dashboard/src/app/diagnostics/diagnostic-callback.ts +++ b/dashboard/src/app/diagnostics/diagnostic-callback.ts @@ -23,57 +23,57 @@ export class DiagnosticCallback { /** * Parent item. */ - private diagnosticPart : DiagnosticPart; + private diagnosticPart: DiagnosticPart; /** * Promise service handling. */ - private $q : ng.IQService; + private $q: ng.IQService; /** * Websocket API used to deal with websockets. */ - private cheWebsocket : CheWebsocket; + private cheWebsocket: CheWebsocket; /** * Angular Timeout service */ - private $timeout : ng.ITimeoutService; + private $timeout: ng.ITimeoutService; /** * defered object instance from q service */ - private defered : ng.IDeferred; + private defered: ng.IDeferred; /** * List of all channels on which we're listening for websockets. */ - private listeningChannels : Array; + private listeningChannels: Array; /** * All timeouts that we're starting as part of this callback. They need to be stopped at the end. */ - private timeoutPromises : Array; + private timeoutPromises: Array>; /** * Map used to send data across different fonctions. */ - private sharedMap : Map; + private sharedMap: Map; /** * Builder when a new sibling callback is required to be added/build. */ - private builder : DiagnosticsController; + private builder: DiagnosticsController; /** * Allow to override the messagebus (originally it's grabbing it from cheWebsocket service) */ - private messageBus : MessageBus; + private messageBus: MessageBus; /** * Name of the callback. */ - private name : string; + private name: string; /** * Content associated to the callback. @@ -83,19 +83,19 @@ export class DiagnosticCallback { /** * All items attached to this category. */ - private items : Array; + private items: Array; /** * Constructor. */ - constructor($q : ng.IQService, cheWebsocket : CheWebsocket, $timeout : ng.ITimeoutService, name: string, sharedMap : Map, builder : any, diagnosticPart : DiagnosticPart) { + constructor($q: ng.IQService, cheWebsocket: CheWebsocket, $timeout: ng.ITimeoutService, name: string, sharedMap: Map, builder: any, diagnosticPart: DiagnosticPart) { this.$q = $q; this.cheWebsocket = cheWebsocket; this.$timeout = $timeout; this.defered = $q.defer(); this.listeningChannels = new Array(); - this.timeoutPromises = new Array(); + this.timeoutPromises = new Array>(); this.name = name; this.sharedMap = sharedMap; this.builder = builder; @@ -105,61 +105,39 @@ export class DiagnosticCallback { /** * Add the given value under the given key name. - * @param key the key for the storage (a string) - * @param value the value object + * @param {string} key the key for the storage (a string) + * @param {any} value the value object */ - public shared(key:string, value : any) : void { + public shared(key: string, value: any): void { this.sharedMap.set(key, value); } /** * Allow to retrieved an object based on its key (string) - * @param key the string name + * @param {string} key the string name * @returns {undefined|any} */ - public getShared(key:string) : any { + public getShared(key: string): any { return this.sharedMap.get(key); } - /** - * Build a new item instance - * @param message the message to store in the item - * @param hint any hint to add to the item - * @param state the state of this newly item - * @returns {DiagnosticItem} the newly created object - */ - private newItem(message, hint : string, state : DiagnosticCallbackState) { - let diagnosticItem = new DiagnosticItem(); - diagnosticItem.title = this.name; - diagnosticItem.message = message; - if (hint) { - diagnosticItem.hint = hint; - } - diagnosticItem.state = state; - diagnosticItem.content = this.content; - this.diagnosticPart.addItem(diagnosticItem); - this.items.push(diagnosticItem); - return diagnosticItem; - } - /** * Adds a running state item [like a new service that is now running received by server side event] - * @param message the message to display - * @param hint extra hint + * @param {string} message the message to display + * @param {string=}hint extra hint */ - public stateRunning(message : string, hint? : string) : void { + public stateRunning(message: string, hint?: string): void { this.newItem(message, hint, DiagnosticCallbackState.RUNNING); this.cleanup(); this.defered.resolve(message); } - /** * Adds a success item [like the result of a test] - * @param message the message to display - * @param hint extra hint + * @param {string} message the message to display + * @param {string} hint extra hint */ - public success(message : string, hint? : string) : void { + public success(message: string, hint?: string): void { this.newItem(message, hint, DiagnosticCallbackState.OK); this.cleanup(); this.defered.resolve(message); @@ -167,27 +145,27 @@ export class DiagnosticCallback { /** * Notify a failure. note: it doesn't stop the execution flow. A success or an error will come after a failure. - * @param message the message to display - * @param hint extra hint + * @param {string} message the message to display + * @param {string} hint extra hint */ - notifyFailure(message : string, hint? : string) : void { + notifyFailure(message: string, hint?: string): void { this.newItem(message, hint, DiagnosticCallbackState.FAILURE); } /** * Only notify a hint. - * @param hint the hint to display + * @param {string} hint the hint to display */ - notifyHint(hint : string) : void { + notifyHint(hint: string): void { this.newItem('', hint, DiagnosticCallbackState.HINT); } /** * Adds an error item [like the result of a test]. Note: it will break the current flow and cancel all existing promises. - * @param message the message to display - * @param hint extra hint + * @param {string} message the message to display + * @param {string} hint extra hint */ - public error(message : string, hint? : string) : void { + public error(message: string, hint?: string): void { this.newItem(message, hint, DiagnosticCallbackState.ERROR); this.cleanup(); this.defered.reject(message); @@ -195,9 +173,9 @@ export class DiagnosticCallback { /** * Add content to the callback - * @param content the content to add + * @param {string} content the content to add */ - public addContent(content : string) : void { + public addContent(content: string): void { if (!this.content) { this.content = content; } else { @@ -207,9 +185,9 @@ export class DiagnosticCallback { /** * Promise associated to this callback - * @returns {IPromise} + * @returns {ng.IPromise} */ - public getPromise() : ng.IPromise { + public getPromise(): ng.IPromise { return this.defered.promise; } @@ -217,7 +195,7 @@ export class DiagnosticCallback { * MessageBus used to connect with websockets. * @returns {MessageBus} */ - public getMessageBus() : MessageBus { + public getMessageBus(): MessageBus { if (this.messageBus) { return this.messageBus; } else { @@ -227,26 +205,28 @@ export class DiagnosticCallback { /** * Override the current messagebus - * @param messageBus + * @param {messageBus} messageBus */ - public setMessageBus(messageBus : MessageBus) { + public setMessageBus(messageBus: MessageBus) { this.messageBus = messageBus; } /** * Delay an error after a timeout. Allow to stop a test if there is no answer after some time. - * @param message - * @param delay the number of seconds to wait + * @param {string} message + * @param {number} delay the number of seconds to wait */ delayError(message: string, delay: number) { - let promise = this.$timeout(() => {this.error(message)}, delay); + let promise = this.$timeout(() => { + this.error(message); + }, delay); this.timeoutPromises.push(promise); } /** * Delay a function after a timeout. - * @param funct the callback function - * @param delay the number of seconds to wait + * @param {any} funct the callback function + * @param {number} delay the number of seconds to wait */ delayFunction(funct: any, delay: number) { let promise = this.$timeout(funct, delay); @@ -255,18 +235,21 @@ export class DiagnosticCallback { /** * Subscribe on message bus channel + * @param {string} channel + * @param {any} callback */ - public subscribeChannel(channel : string, callback : any) : void { + public subscribeChannel(channel: string, callback: any): void { this.getMessageBus().subscribe(channel, callback); this.listeningChannels.push(channel); } /** * Unsubscribe from message bus channel + * @param {string} channel */ - public unsubscribeChannel(channel : string) : void { + public unsubscribeChannel(channel: string): void { this.getMessageBus().unsubscribe(channel); - let index : number = this.listeningChannels.indexOf(channel); + let index: number = this.listeningChannels.indexOf(channel); if (index >= 0) { delete this.listeningChannels[index]; } @@ -275,8 +258,8 @@ export class DiagnosticCallback { /** * Cleanup all resources (like current promises) */ - protected cleanup() : void { - this.timeoutPromises.forEach((promise: ng.IPromise) => { + protected cleanup(): void { + this.timeoutPromises.forEach((promise: ng.IPromise) => { this.$timeout.cancel(promise); }); this.timeoutPromises.length = 0; @@ -290,11 +273,32 @@ export class DiagnosticCallback { /** * Builder of a sibling callback - * @param text + * @param {string} text * @returns {DiagnosticCallback} */ - newCallback(text : string) : DiagnosticCallback{ + newCallback(text: string): DiagnosticCallback { return this.builder.newItem(text, this.diagnosticPart); } + /** + * Build a new item instance + * @param {any} message the message to store in the item + * @param {string} hint any hint to add to the item + * @param {DiagnosticCallbackState} state the state of this newly item + * @returns {DiagnosticItem} the newly created object + */ + private newItem(message: any, hint: string, state: DiagnosticCallbackState) { + let diagnosticItem = new DiagnosticItem(); + diagnosticItem.title = this.name; + diagnosticItem.message = message; + if (hint) { + diagnosticItem.hint = hint; + } + diagnosticItem.state = state; + diagnosticItem.content = this.content; + this.diagnosticPart.addItem(diagnosticItem); + this.items.push(diagnosticItem); + return diagnosticItem; + } + } diff --git a/dashboard/src/app/diagnostics/diagnostic-item.ts b/dashboard/src/app/diagnostics/diagnostic-item.ts index f01a887121..300483409c 100644 --- a/dashboard/src/app/diagnostics/diagnostic-item.ts +++ b/dashboard/src/app/diagnostics/diagnostic-item.ts @@ -24,28 +24,28 @@ export class DiagnosticItem { /** * Message used to be displayed after the title of the item. */ - public message : string; + public message: string; /** * State of the current item. */ - public state : DiagnosticCallbackState; + public state: DiagnosticCallbackState; /** * Content is extra verbose stuff that could be displayed as part of the logs of the item. */ - public content : string; + public content: string; /** * Hint to report to the end-user. Something that could be helpful regarding the item. */ - public hint : string; + public hint: string; /** * Checks the state of the item * @returns {boolean} true if state is OK */ - public isOk() : boolean { + public isOk(): boolean { return DiagnosticCallbackState.OK === this.state; } @@ -53,7 +53,7 @@ export class DiagnosticItem { * Checks the state of the item * @returns {boolean} true if state is OK */ - public isSuccess() : boolean { + public isSuccess(): boolean { return DiagnosticCallbackState.OK === this.state; } @@ -61,7 +61,7 @@ export class DiagnosticItem { * Checks the state of the item * @returns {boolean} true if state is ERROR */ - public isError() : boolean { + public isError(): boolean { return DiagnosticCallbackState.ERROR === this.state; } @@ -69,7 +69,7 @@ export class DiagnosticItem { * Checks the state of the item * @returns {boolean} true if state is FAILURE */ - public isFailure() : boolean { + public isFailure(): boolean { return DiagnosticCallbackState.FAILURE === this.state; } @@ -77,7 +77,7 @@ export class DiagnosticItem { * Checks the state of the item * @returns {boolean} true if state is RUNNING */ - public isRunning() : boolean{ + public isRunning(): boolean { return DiagnosticCallbackState.RUNNING === this.state; } @@ -85,7 +85,7 @@ export class DiagnosticItem { * Checks the state of the item * @returns {boolean} true if state is HINT */ - public isHint() : boolean { + public isHint(): boolean { return DiagnosticCallbackState.HINT === this.state; } @@ -93,18 +93,18 @@ export class DiagnosticItem { * Convert state to friendly text. * @returns {any} */ - public stateToText() : string { + public stateToText(): string { switch (this.state) { case DiagnosticCallbackState.RUNNING : - return "STATE_RUNNING"; + return 'STATE_RUNNING'; case DiagnosticCallbackState.HINT : - return "HINT"; + return 'HINT'; case DiagnosticCallbackState.OK : - return "SUCCESS"; + return 'SUCCESS'; case DiagnosticCallbackState.FAILURE : - return "FAILURE"; + return 'FAILURE'; case DiagnosticCallbackState.ERROR : - return "ERROR" + return 'ERROR'; } } diff --git a/dashboard/src/app/diagnostics/diagnostic-part-state.ts b/dashboard/src/app/diagnostics/diagnostic-part-state.ts index e708229d1c..38da22803a 100644 --- a/dashboard/src/app/diagnostics/diagnostic-part-state.ts +++ b/dashboard/src/app/diagnostics/diagnostic-part-state.ts @@ -8,6 +8,7 @@ * Contributors: * Red Hat, Inc. - initial API and implementation */ + /** * Defines the state of the diagnostic part * @author Florent Benoit diff --git a/dashboard/src/app/diagnostics/diagnostic-part.ts b/dashboard/src/app/diagnostics/diagnostic-part.ts index 65ad006812..0d18908643 100644 --- a/dashboard/src/app/diagnostics/diagnostic-part.ts +++ b/dashboard/src/app/diagnostics/diagnostic-part.ts @@ -26,52 +26,52 @@ export class DiagnosticPart { /** * An optional subtitle of this part. */ - subtitle : string; + subtitle: string; /** * The current state of this category */ - state : DiagnosticPartState; + state: DiagnosticPartState; /** * Display icon of this part. */ - icon : string; + icon: string; /** * All items attached to this category. */ - private items : Array; + private items: Array; /** * All callbacks attached to this category. */ - private callbacks : Array; + private callbacks: Array; /** * Current promises of all callbacks */ - private callbackPromises : Array; + private callbackPromises: Array>; /** * Number of callbacks (tests) that have finished. */ - private nbEndedCallbacks : number; + private nbEndedCallbacks: number; /** * Number of callbacks (tests) that have been successful. */ - private nbSuccessCallbacks : number; + private nbSuccessCallbacks: number; /** * Number of callbacks that had errors */ - private nbErrorCallbacks : number; + private nbErrorCallbacks: number; /** * Callbacks that have ended */ - private callbacksEnded : Array; + private callbacksEnded: Array; /** * Constructor. @@ -80,7 +80,7 @@ export class DiagnosticPart { this.items = new Array(); this.callbacks = new Array(); this.callbacksEnded = new Array(); - this.callbackPromises = new Array(); + this.callbackPromises = new Array>(); this.nbEndedCallbacks = 0; this.nbSuccessCallbacks = 0; this.nbErrorCallbacks = 0; @@ -88,17 +88,17 @@ export class DiagnosticPart { /** * Add an item to this part. - * @param item the item to add + * @param {DiagnosticItem} item the item to add */ - addItem(item : DiagnosticItem) : void { + addItem(item: DiagnosticItem): void { this.items.push(item); } /** * Test callback to add to this part - * @param callback the test callback to add. + * @param {DiagnosticCallback} callback the test callback to add. */ - addCallback(callback: DiagnosticCallback) : void { + addCallback(callback: DiagnosticCallback): void { callback.getPromise().then(() => { this.nbSuccessCallbacks++; @@ -121,7 +121,7 @@ export class DiagnosticPart { * Checks the state of the part * @returns {boolean} true if state is READY */ - public isReady() : boolean { + public isReady(): boolean { return DiagnosticPartState.READY === this.state; } @@ -129,7 +129,7 @@ export class DiagnosticPart { * Checks the state of the part * @returns {boolean} true if state is IN_PROGRESS */ - public isInProgress() : boolean { + public isInProgress(): boolean { return DiagnosticPartState.IN_PROGRESS === this.state; } @@ -137,7 +137,7 @@ export class DiagnosticPart { * Checks the state of the part * @returns {boolean} true if state is SUCCESS */ - public isSuccess() : boolean { + public isSuccess(): boolean { return DiagnosticPartState.SUCCESS === this.state; } @@ -145,7 +145,7 @@ export class DiagnosticPart { * Checks the state of the part * @returns {boolean} true if state is FAILURE */ - public isFailure() : boolean { + public isFailure(): boolean { return DiagnosticPartState.FAILURE === this.state; } @@ -153,33 +153,33 @@ export class DiagnosticPart { * Checks the state of the part * @returns {boolean} true if state is ERROR */ - public isError() : boolean { + public isError(): boolean { return DiagnosticPartState.ERROR === this.state; } /** * Convert state to friendly text. - * @returns {any} + * @returns {string} */ - public stateToText() : string { + public stateToText(): string { switch (this.state) { case DiagnosticPartState.READY : - return "READY (planned)"; + return 'READY (planned)'; case DiagnosticPartState.IN_PROGRESS : - return "IN PROGRESS"; + return 'IN PROGRESS'; case DiagnosticPartState.SUCCESS : - return "SUCCESS"; + return 'SUCCESS'; case DiagnosticPartState.FAILURE : - return "FAILURE"; + return 'FAILURE'; case DiagnosticPartState.ERROR : - return "ERROR" + return 'ERROR'; } } /** * Clear the values */ - clear() : void { + clear(): void { this.nbEndedCallbacks = 0; this.nbSuccessCallbacks = 0; this.nbErrorCallbacks = 0; @@ -193,7 +193,7 @@ export class DiagnosticPart { * Gets the total number of callbacks * @returns {number} */ - public getNumberOfCallbacks() : number { + public getNumberOfCallbacks(): number { return this.callbacks.length; } @@ -201,7 +201,7 @@ export class DiagnosticPart { * Gets the total number of ended callbacks * @returns {number} */ - public getNumberOfEndedCallbacks() : number { + public getNumberOfEndedCallbacks(): number { return this.nbEndedCallbacks; } diff --git a/dashboard/src/app/diagnostics/diagnostics-config.ts b/dashboard/src/app/diagnostics/diagnostics-config.ts index c2d022b50a..c0cf2e72ea 100644 --- a/dashboard/src/app/diagnostics/diagnostics-config.ts +++ b/dashboard/src/app/diagnostics/diagnostics-config.ts @@ -23,7 +23,7 @@ import {DiagnosticsRunningWorkspaceCheck} from './test/diagnostics-workspace-che */ export class DiagnosticsConfig { - constructor(register) { + constructor(register: che.IRegisterService) { register.factory('diagnosticsWebsocketWsMaster', DiagnosticsWebsocketWsMaster); register.factory('diagnosticsWorkspaceStartCheck', DiagnosticsWorkspaceStartCheck); @@ -33,7 +33,7 @@ export class DiagnosticsConfig { register.controller('DiagnosticsController', DiagnosticsController); // config routes - register.app.config(($routeProvider) => { + register.app.config(($routeProvider: che.route.IRouteProvider) => { $routeProvider.accessWhen('/diagnostic', { title: 'Diagnostic', templateUrl: 'app/diagnostics/diagnostics.html' diff --git a/dashboard/src/app/diagnostics/diagnostics-widget.html b/dashboard/src/app/diagnostics/diagnostics-widget.html index 1e2fba4aae..183a9e7fca 100644 --- a/dashboard/src/app/diagnostics/diagnostics-widget.html +++ b/dashboard/src/app/diagnostics/diagnostics-widget.html @@ -48,9 +48,9 @@
+ che-button-icon="fa fa-file-text-o" + ng-click="diagnosticsController.showLogs()" + ng-if="!diagnosticsController.isReady()">
diff --git a/dashboard/src/app/diagnostics/diagnostics.controller.ts b/dashboard/src/app/diagnostics/diagnostics.controller.ts index 2ad22228cd..6d4e8a2bea 100644 --- a/dashboard/src/app/diagnostics/diagnostics.controller.ts +++ b/dashboard/src/app/diagnostics/diagnostics.controller.ts @@ -44,52 +44,52 @@ export class DiagnosticsController { /** * Instance of checker for websockets */ - private diagnosticsWebsocketWsMaster : DiagnosticsWebsocketWsMaster; + private diagnosticsWebsocketWsMaster: DiagnosticsWebsocketWsMaster; /** * Instance of checker for workspace */ - private diagnosticsWorkspaceStartCheck : DiagnosticsWorkspaceStartCheck; + private diagnosticsWorkspaceStartCheck: DiagnosticsWorkspaceStartCheck; /** * Websocket library. */ - private cheWebsocket : CheWebsocket; + private cheWebsocket: CheWebsocket; /** * Angular timeout service. */ - private $timeout : ng.ITimeoutService; + private $timeout: ng.ITimeoutService; /** * Shared Map across all parts. */ - private sharedMap : Map; + private sharedMap: Map; /** * Reference to the diagnostic workspace checker. */ - private diagnosticsRunningWorkspaceCheck : DiagnosticsRunningWorkspaceCheck; + private diagnosticsRunningWorkspaceCheck: DiagnosticsRunningWorkspaceCheck; /** * List of all parts. */ - private parts : Array; + private parts: Array; /** * Link to the workspace master part */ - private wsMasterPart : DiagnosticPart; + private wsMasterPart: DiagnosticPart; /** * Link to the workspace agent part */ - private wsAgentPart : DiagnosticPart; + private wsAgentPart: DiagnosticPart; /** * Alias for the current part being tested */ - private currentPart : DiagnosticPart; + private currentPart: DiagnosticPart; /** * Allow to turn on/off details @@ -99,34 +99,34 @@ export class DiagnosticsController { /** * Global state */ - private state : DiagnosticPartState; + private state: DiagnosticPartState; /** * Text to be displayed as global status */ - private globalStatusText : string; + private globalStatusText: string; /** * Branding info. */ - private cheBranding : CheBranding; + private cheBranding: CheBranding; /** * Show/hide logs */ - private isLogDisplayed : boolean; + private isLogDisplayed: boolean; /** * Default constructor that is using resource * @ngInject for Dependency injection */ constructor($log: ng.ILogService, $q: ng.IQService, lodash: any, - $timeout : ng.ITimeoutService, - diagnosticsWebsocketWsMaster : DiagnosticsWebsocketWsMaster, + $timeout: ng.ITimeoutService, + diagnosticsWebsocketWsMaster: DiagnosticsWebsocketWsMaster, cheWebsocket: CheWebsocket, - cheBranding : CheBranding, - diagnosticsRunningWorkspaceCheck : DiagnosticsRunningWorkspaceCheck, - diagnosticsWorkspaceStartCheck : DiagnosticsWorkspaceStartCheck) { + cheBranding: CheBranding, + diagnosticsRunningWorkspaceCheck: DiagnosticsRunningWorkspaceCheck, + diagnosticsWorkspaceStartCheck: DiagnosticsWorkspaceStartCheck) { this.$q = $q; this.$log = $log; this.lodash = lodash; @@ -158,7 +158,7 @@ export class DiagnosticsController { /** * Start the tests. */ - public start() : void { + public start(): void { this.sharedMap.clear(); this.globalStatusText = 'Running Tests'; this.state = DiagnosticPartState.IN_PROGRESS; @@ -166,39 +166,37 @@ export class DiagnosticsController { this.parts.length = 0; this.parts.push(this.wsMasterPart); this.parts.push(this.wsAgentPart); - this.parts.forEach((part) => { + this.parts.forEach((part: DiagnosticPart) => { part.clear(); }); this.currentPart = this.wsMasterPart; - - // First check websocket on workspace master + // first check websocket on workspace master this.checkWorkspaceMaster().then(() => { return this.checkWorkspaceAgent(); }).then(() => { return this.waitAllCompleted([this.checkWorkspaceCheck(), this.checkWebSocketWsAgent()]); - }).then(()=> { + }).then(() => { this.globalStatusText = 'Completed Diagnostics'; this.state = DiagnosticPartState.SUCCESS; - }).catch(error => { + }).catch((error: any) => { this.globalStatusText = 'Diagnostics Finished With Error'; this.state = DiagnosticPartState.ERROR; - } - ) + }); } /** * Wait for all promises to be terminate and not stop at the first error * @param promises an array of promises - * @returns {IPromise} + * @returns {ng.IPromise} */ - waitAllCompleted(promises : Array) : ng.IPromise { - var allCompletedDefered = this.$q.defer(); - let finished : number = 0; - let toFinish : number = promises.length; - let error : boolean = false; - promises.forEach((promise) => { + waitAllCompleted(promises: Array>): ng.IPromise { + const allCompletedDefered = this.$q.defer(); + let finished: number = 0; + let toFinish: number = promises.length; + let error: boolean = false; + promises.forEach((promise: ng.IPromise) => { promise.catch(() => { error = true; }).finally(() => { @@ -211,20 +209,19 @@ export class DiagnosticsController { allCompletedDefered.resolve('success'); } } - }) + }); }); return allCompletedDefered.promise; } - /** * Build a new callback item * @param text the text to set in the callback * @param diagnosticPart the diagnostic part * @returns {DiagnosticCallback} the newly callback */ - public newItem(text: string, diagnosticPart : DiagnosticPart) : DiagnosticCallback { - let callback : DiagnosticCallback = new DiagnosticCallback(this.$q, this.cheWebsocket, this.$timeout, text, this.sharedMap, this, diagnosticPart); + public newItem(text: string, diagnosticPart: DiagnosticPart): DiagnosticCallback { + let callback: DiagnosticCallback = new DiagnosticCallback(this.$q, this.cheWebsocket, this.$timeout, text, this.sharedMap, this, diagnosticPart); diagnosticPart.addCallback(callback); return callback; } @@ -233,22 +230,22 @@ export class DiagnosticsController { * Sets the details part. * @param part the part to be displayed for the details */ - public setDetailsPart(part : DiagnosticPart) : void { + public setDetailsPart(part: DiagnosticPart): void { this.currentPart = part; } /** * Checks the workspace master. - * @returns {ng.IPromise} + * @returns {ng.IPromise} */ - public checkWorkspaceMaster() : ng.IPromise { + public checkWorkspaceMaster(): ng.IPromise { this.currentPart = this.wsMasterPart; this.wsMasterPart.state = DiagnosticPartState.IN_PROGRESS; - let promiseWorkspaceMaster : ng.IPromise = this.diagnosticsWebsocketWsMaster.start(this.newItem('Websockets', this.wsMasterPart)); + let promiseWorkspaceMaster: ng.IPromise = this.diagnosticsWebsocketWsMaster.start(this.newItem('Websockets', this.wsMasterPart)); promiseWorkspaceMaster.then(() => { this.wsMasterPart.state = DiagnosticPartState.SUCCESS; - }).catch(error => { + }).catch((error: any) => { this.wsMasterPart.state = DiagnosticPartState.ERROR; }); @@ -257,16 +254,16 @@ export class DiagnosticsController { /** * Checks the workspace agent. - * @returns {ng.IPromise} + * @returns {ng.IPromise} */ - public checkWorkspaceAgent() : ng.IPromise { + public checkWorkspaceAgent(): ng.IPromise { this.currentPart = this.wsAgentPart; this.wsAgentPart.state = DiagnosticPartState.IN_PROGRESS; - let promiseWorkspaceAgent : ng.IPromise = this.diagnosticsWorkspaceStartCheck.start(this.newItem('Create Workspace', this.wsAgentPart)); + let promiseWorkspaceAgent: ng.IPromise = this.diagnosticsWorkspaceStartCheck.start(this.newItem('Create Workspace', this.wsAgentPart)); promiseWorkspaceAgent.then(() => { this.wsAgentPart.state = DiagnosticPartState.SUCCESS; - }).catch(error => { + }).catch((error: any) => { this.wsAgentPart.state = DiagnosticPartState.ERROR; }); @@ -275,25 +272,24 @@ export class DiagnosticsController { /** * Check the REST API on ws agent - * @returns {ng.IPromise} + * @returns {ng.IPromise} */ - public checkWorkspaceCheck() : ng.IPromise { + public checkWorkspaceCheck(): ng.IPromise { return this.diagnosticsRunningWorkspaceCheck.checkWsAgent(this.newItem('REST Call on Workspace Agent', this.wsAgentPart), true); } /** * Check the websockets on ws agent - * @returns {ng.IPromise} + * @returns {ng.IPromise} */ - public checkWebSocketWsAgent() : ng.IPromise { + public checkWebSocketWsAgent(): ng.IPromise { return this.diagnosticsRunningWorkspaceCheck.checkWebSocketWsAgent(this.newItem('Websocket on Workspace Agent', this.wsAgentPart)); } /** * Allow to toggle details - * @returns {ng.IPromise} */ - public toggleDetails() : void { + public toggleDetails(): void { this.showDetails = !this.showDetails; } @@ -301,7 +297,7 @@ export class DiagnosticsController { * Checks the state of the controller * @returns {boolean} true if state is READY */ - public isReady() : boolean { + public isReady(): boolean { return DiagnosticPartState.READY === this.state; } @@ -309,7 +305,7 @@ export class DiagnosticsController { * Checks the state of the controller * @returns {boolean} true if state is IN_PROGRESS */ - public isInProgress() : boolean { + public isInProgress(): boolean { return DiagnosticPartState.IN_PROGRESS === this.state; } @@ -317,7 +313,7 @@ export class DiagnosticsController { * Checks the state of the controller * @returns {boolean} true if state is SUCCESS */ - public isSuccess() : boolean { + public isSuccess(): boolean { return DiagnosticPartState.SUCCESS === this.state; } @@ -325,7 +321,7 @@ export class DiagnosticsController { * Checks the state of the controller * @returns {boolean} true if state is FAILURE */ - public isFailure() : boolean { + public isFailure(): boolean { return DiagnosticPartState.FAILURE === this.state; } @@ -333,14 +329,14 @@ export class DiagnosticsController { * Checks the state of the controller * @returns {boolean} true if state is ERROR */ - public isError() : boolean { + public isError(): boolean { return DiagnosticPartState.ERROR === this.state; } /** * Toggle log display. */ - public showLogs() : void { + public showLogs(): void { this.isLogDisplayed = !this.isLogDisplayed; } diff --git a/dashboard/src/app/diagnostics/diagnostics.directive.ts b/dashboard/src/app/diagnostics/diagnostics.directive.ts index 61ca392eda..7d67b443f4 100644 --- a/dashboard/src/app/diagnostics/diagnostics.directive.ts +++ b/dashboard/src/app/diagnostics/diagnostics.directive.ts @@ -26,7 +26,7 @@ */ export class Diagnostics { - replace : boolean = false; + replace: boolean = false; restrict: string = 'E'; templateUrl: string = 'app/diagnostics/diagnostics-widget.html'; controller: string = 'DiagnosticsController'; @@ -41,10 +41,9 @@ export class Diagnostics { * Default constructor that is using resource * @ngInject for Dependency injection */ - constructor () { + constructor() { // scope values - this.scope = { - }; + this.scope = {}; } } diff --git a/dashboard/src/app/diagnostics/test/diagnostics-websocket-wsmaster.factory.ts b/dashboard/src/app/diagnostics/test/diagnostics-websocket-wsmaster.factory.ts index bdaa129858..dbd8eb446b 100644 --- a/dashboard/src/app/diagnostics/test/diagnostics-websocket-wsmaster.factory.ts +++ b/dashboard/src/app/diagnostics/test/diagnostics-websocket-wsmaster.factory.ts @@ -21,28 +21,28 @@ export class DiagnosticsWebsocketWsMaster { /** * Websocket handling. */ - private cheWebsocket : CheWebsocket; + private cheWebsocket: CheWebsocket; /** * Timeout handling. */ - private $timeout : ng.ITimeoutService; + private $timeout: ng.ITimeoutService; /** * Default constructor * @ngInject for Dependency injection */ - constructor (cheWebsocket: CheWebsocket, $timeout : ng.ITimeoutService) { + constructor(cheWebsocket: CheWebsocket, $timeout: ng.ITimeoutService) { this.cheWebsocket = cheWebsocket; this.$timeout = $timeout; } /** * Start the diagnostic and report all progress through the callback - * @param diagnosticCallback - * @returns {IPromise} when test is finished + * @param {DiagnosticCallback} diagnosticCallback + * @returns {ng.IPromise} when test is finished */ - start(diagnosticCallback : DiagnosticCallback) : ng.IPromise { + start(diagnosticCallback: DiagnosticCallback): ng.IPromise { try { // define callback @@ -62,11 +62,10 @@ export class DiagnosticsWebsocketWsMaster { // send the message diagnosticCallback.getMessageBus().ping(); - } catch (error : any) { + } catch (error) { diagnosticCallback.error('Unable to connect with websocket to ' + this.cheWebsocket.wsUrl + ': ' + error); } return diagnosticCallback.getPromise(); } - } diff --git a/dashboard/src/app/diagnostics/test/diagnostics-workspace-check-workspace.factory.ts b/dashboard/src/app/diagnostics/test/diagnostics-workspace-check-workspace.factory.ts index 0314bd041f..6fe89c4810 100644 --- a/dashboard/src/app/diagnostics/test/diagnostics-workspace-check-workspace.factory.ts +++ b/dashboard/src/app/diagnostics/test/diagnostics-workspace-check-workspace.factory.ts @@ -23,7 +23,7 @@ export class DiagnosticsRunningWorkspaceCheck { /** * Q service for creating delayed promises. */ - private $q : ng.IQService; + private $q: ng.IQService; /** * Workspace API used to grab details. @@ -33,108 +33,76 @@ export class DiagnosticsRunningWorkspaceCheck { /** * Lodash utility. */ - private lodash : any; + private lodash: any; /** * Resource service used in tests. */ - private $resource : ng.resource.IResourceService; + private $resource: ng.resource.IResourceService; /** * Location service used to get data from browser URL. */ - private $location : ng.ILocationService; + private $location: ng.ILocationService; /** * Websocket handling. */ - private cheWebsocket : CheWebsocket; + private cheWebsocket: CheWebsocket; /** * Branding info. */ - private cheBranding : CheBranding; + private cheBranding: CheBranding; /** * Default constructor * @ngInject for Dependency injection */ - constructor ($q : ng.IQService, lodash : any, cheWebsocket : CheWebsocket, cheWorkspace: CheWorkspace, - $resource : ng.resource.IResourceService, $location : ng.ILocationService, cheBranding : CheBranding) { - this.$q =$q; + constructor($q: ng.IQService, lodash: any, cheWebsocket: CheWebsocket, cheWorkspace: CheWorkspace, + $resource: ng.resource.IResourceService, $location: ng.ILocationService, cheBranding: CheBranding) { + this.$q = $q; this.lodash = lodash; this.cheWorkspace = cheWorkspace; this.cheWebsocket = cheWebsocket; this.cheBranding = cheBranding; this.$resource = $resource; this.$location = $location; - } /** * Check WS Agent by using the browser host - * @param diagnosticCallback - * @returns {ng.IPromise} + * @param {DiagnosticCallback} diagnosticCallback + * @returns {ng.IPromise} */ - checkAgentWithBrowserHost(diagnosticCallback : DiagnosticCallback) : ng.IPromise { + checkAgentWithBrowserHost(diagnosticCallback: DiagnosticCallback): ng.IPromise { let wsAgentHRef = this.getWsAgentURL(diagnosticCallback); let parser = document.createElement('a'); parser.href = wsAgentHRef; wsAgentHRef = parser.protocol + '//' + this.$location.host() + ':' + parser.port + parser.pathname; - let promise : ng.IPromise = this.callSCM(diagnosticCallback, wsAgentHRef, false); + let promise: ng.IPromise = this.callSCM(diagnosticCallback, wsAgentHRef, false); promise.then(() => { let hint: string; if (this.cheBranding.getName() === 'Eclipse Che') { - hint = 'CHE_DOCKER_IP_EXTERNAL property could be used or ' + hint = 'CHE_DOCKER_IP_EXTERNAL property could be used or '; } diagnosticCallback.notifyHint(this.cheBranding.getCLI().name + '_HOST value in `' + this.cheBranding.getCLI().configName + '` file should use the hostname ' + this.$location.host() + ' instead of ' + parser.hostname); }); return diagnosticCallback.getPromise(); } - /** - * Utility method used to get Workspace Agent URL from a callback shared data - * @param diagnosticCallback - */ - private getWsAgentURL(diagnosticCallback : DiagnosticCallback) : string { - let workspace : che.IWorkspace = diagnosticCallback.getShared('workspace'); - - let errMessage : string = 'Workspace has no runtime: unable to test workspace not started'; - let runtime : any = workspace.runtime; - if (!runtime) { - diagnosticCallback.error(errMessage); - throw errMessage; - } - let devMachine = runtime.devMachine; - if (!devMachine) { - diagnosticCallback.error(errMessage); - throw errMessage; - } - let servers : any = devMachine.runtime.servers; - if (!servers) { - diagnosticCallback.error(errMessage); - throw errMessage; - } - let wsAgentServer = this.lodash.find(servers, (server: any) => { - return server.ref === 'wsagent'; - }); - - - return wsAgentServer.url; - } - - /** * Check the Workspace Agent by calling REST API. - * @param diagnosticCallback - * @returns {ng.IPromise} + * @param {DiagnosticCallback} diagnosticCallback + * @param {boolean} errorInsteadOfFailure + * @returns {ng.IPromise} */ - checkWsAgent(diagnosticCallback : DiagnosticCallback, errorInsteadOfFailure : boolean) : ng.IPromise { + checkWsAgent(diagnosticCallback: DiagnosticCallback, errorInsteadOfFailure: boolean): ng.IPromise { let wsAgentHRef = this.getWsAgentURL(diagnosticCallback); let promise = this.callSCM(diagnosticCallback, wsAgentHRef, errorInsteadOfFailure); - promise.catch((error) => { + promise.catch((error: any) => { // try with browser host if different location let parser = document.createElement('a'); parser.href = wsAgentHRef; @@ -145,33 +113,22 @@ export class DiagnosticsRunningWorkspaceCheck { }); return diagnosticCallback.getPromise(); - } - - /** * Start the diagnostic and report all progress through the callback - * @param diagnosticCallback - * @returns {IPromise} when test is finished + * @param {DiagnosticCallback} diagnosticCallback + * @returns {ng.IPromise} when test is finished */ - checkWebSocketWsAgent(diagnosticCallback : DiagnosticCallback) : ng.IPromise { - let workspace: che.IWorkspace = diagnosticCallback.getShared('workspace'); + checkWebSocketWsAgent(diagnosticCallback: DiagnosticCallback): ng.IPromise { let machineToken: string = diagnosticCallback.getShared('machineToken'); - let wsAgentSocketWebLink = this.lodash.find(workspace.runtime.links, (link: any) => { - return link.rel === 'wsagent.websocket'; - }); - if (!wsAgentSocketWebLink) { - wsAgentSocketWebLink = this.getWsAgentURL(diagnosticCallback).replace('http', 'ws') + '/ws'; - } else { - wsAgentSocketWebLink = wsAgentSocketWebLink.href; - } + let wsAgentSocketWebLink = this.getWsAgentURL(diagnosticCallback).replace('http', 'ws') + '/ws'; if (machineToken) { wsAgentSocketWebLink += '?token=' + machineToken; } - let wsAgentRemoteBus : MessageBus = this.cheWebsocket.getRemoteBus(wsAgentSocketWebLink); + let wsAgentRemoteBus: MessageBus = this.cheWebsocket.getRemoteBus(wsAgentSocketWebLink); diagnosticCallback.setMessageBus(wsAgentRemoteBus); try { @@ -193,7 +150,7 @@ export class DiagnosticsRunningWorkspaceCheck { // send the message diagnosticCallback.getMessageBus().ping(); - } catch (error : any) { + } catch (error) { diagnosticCallback.error('Unable to connect with websocket to ' + wsAgentSocketWebLink + ': ' + error); } return diagnosticCallback.getPromise(); @@ -201,29 +158,30 @@ export class DiagnosticsRunningWorkspaceCheck { /** * Get data on API and retrieve SCM revision. - * @param diagnosticCallback - * @param wsAgentHRef + * @param {DiagnosticCallback} diagnosticCallback + * @param {string} wsAgentHRef + * @param {boolean} errorInsteadOfFailure * @returns {Promise} */ - callSCM(diagnosticCallback : DiagnosticCallback, wsAgentHRef : string, errorInsteadOfFailure : boolean) : ng.IPromise { + callSCM(diagnosticCallback: DiagnosticCallback, wsAgentHRef: string, errorInsteadOfFailure: boolean): ng.IPromise { - let uriWsAgent : string = wsAgentHRef + '/'; + let uriWsAgent: string = wsAgentHRef + '/'; let machineToken: string = diagnosticCallback.getShared('machineToken'); if (machineToken) { uriWsAgent += '?token=' + machineToken; } // connect to the workspace agent - let resourceAPI : any = this.$resource(uriWsAgent, {}, { - getDetails: {method: 'OPTIONS', timeout : 15000} + let resourceAPI: any = this.$resource(uriWsAgent, {}, { + getDetails: {method: 'OPTIONS', timeout: 15000} }, { stripTrailingSlashes: false }); - return resourceAPI.getDetails().$promise.then((data) => { + return resourceAPI.getDetails().$promise.then((data: any) => { diagnosticCallback.success(wsAgentHRef + '. Got SCM revision ' + angular.fromJson(data).scmRevision); - }).catch((error) => { - let errorMessage : string = 'Unable to perform call on ' + wsAgentHRef + ': Status ' + error.status + ', statusText:' + error.statusText + '/' + error.data; + }).catch((error: any) => { + let errorMessage: string = 'Unable to perform call on ' + wsAgentHRef + ': Status ' + error.status + ', statusText:' + error.statusText + '/' + error.data; if (errorInsteadOfFailure) { if (this.cheBranding.getName() === 'Eclipse Che') { diagnosticCallback.error(errorMessage, 'Workspace Agent is running but browser is unable to connect to it. Please check CHE_HOST and CHE_DOCKER_IP_EXTERNAL in che.env and the firewall settings.'); @@ -235,7 +193,37 @@ export class DiagnosticsRunningWorkspaceCheck { } throw error; }); + } + /** + * Utility method used to get Workspace Agent URL from a callback shared data + * @param {DiagnosticCallback} diagnosticCallback + * @returns {string} + */ + getWsAgentURL(diagnosticCallback: DiagnosticCallback): string { + let workspace: che.IWorkspace = diagnosticCallback.getShared('workspace'); + + let errMessage: string = 'Workspace has no runtime: unable to test workspace not started'; + let runtime: any = workspace.runtime; + if (!runtime) { + diagnosticCallback.error(errMessage); + throw errMessage; + } + + const devMachine = Object.keys(runtime.machines).map((machineName: string) => { + return runtime.machines[machineName]; + }).find((machine: any) => { + return Object.keys(machine.servers).some((serverName: string) => { + return serverName === 'wsagent/http'; + }); + }); + + if (!devMachine) { + diagnosticCallback.error(errMessage); + throw errMessage; + } + + return devMachine.servers['wsagent/http'].url; } } diff --git a/dashboard/src/app/diagnostics/test/diagnostics-workspace-start-check.factory.ts b/dashboard/src/app/diagnostics/test/diagnostics-workspace-start-check.factory.ts index 52bb3721d2..a2f8183e87 100644 --- a/dashboard/src/app/diagnostics/test/diagnostics-workspace-start-check.factory.ts +++ b/dashboard/src/app/diagnostics/test/diagnostics-workspace-start-check.factory.ts @@ -13,6 +13,8 @@ import {DiagnosticCallback} from '../diagnostic-callback'; import {CheWorkspace} from '../../../components/api/workspace/che-workspace.factory'; import {DiagnosticsRunningWorkspaceCheck} from './diagnostics-workspace-check-workspace.factory'; import {CheBranding} from '../../../components/branding/che-branding.factory'; +import {CheJsonRpcApi} from '../../../components/api/json-rpc/che-json-rpc-api.factory'; +import {CheJsonRpcMasterApi} from '../../../components/api/json-rpc/che-json-rpc-master-api'; /** * Test the start of a workspace @@ -23,7 +25,7 @@ export class DiagnosticsWorkspaceStartCheck { /** * Q service for creating delayed promises. */ - private $q : ng.IQService; + private $q: ng.IQService; /** * Workspace API used to grab details. @@ -33,56 +35,86 @@ export class DiagnosticsWorkspaceStartCheck { /** * Lodash utility. */ - private lodash : any; + private lodash: any; /** * Other checker used to spawn new tests. */ - private diagnosticsRunningWorkspaceCheck : DiagnosticsRunningWorkspaceCheck; + private diagnosticsRunningWorkspaceCheck: DiagnosticsRunningWorkspaceCheck; /** * Keep a reference to the workspace Agent callback */ - private wsAgentCallback : DiagnosticCallback; + private wsAgentCallback: DiagnosticCallback; /** * Keep a reference to the workspace callback */ - private workspaceCallback : DiagnosticCallback; + private workspaceCallback: DiagnosticCallback; /** * Keep a reference to the machine callback */ - private machineCallback : DiagnosticCallback; + private machineCallback: DiagnosticCallback; /** * Keep a reference to the exec agent callback */ - private execAgentCallback : DiagnosticCallback; + private execAgentCallback: DiagnosticCallback; /** * Branding info. */ - private cheBranding : CheBranding; + private cheBranding: CheBranding; + + /** + * Location service. + */ + private $location: ng.ILocationService; + + /** + * RPC API location string. + */ + private jsonRpcApiLocation: string; + + /** + * Workspace master interceptions. + */ + private cheJsonRpcMasterApi: CheJsonRpcMasterApi; /** * Default constructor * @ngInject for Dependency injection */ - constructor ($q : ng.IQService, lodash : any, cheWorkspace: CheWorkspace, diagnosticsRunningWorkspaceCheck : DiagnosticsRunningWorkspaceCheck, cheBranding : CheBranding) { - this.$q =$q; + constructor($q: ng.IQService, + lodash: any, + cheWorkspace: CheWorkspace, + diagnosticsRunningWorkspaceCheck: DiagnosticsRunningWorkspaceCheck, + cheBranding: CheBranding, + $location: ng.ILocationService, + cheJsonRpcApi: CheJsonRpcApi, + userDashboardConfig: any, + keycloakAuth: any, + proxySettings: string) { + this.$q = $q; this.lodash = lodash; this.cheWorkspace = cheWorkspace; this.cheBranding = cheBranding; + this.$location = $location; this.diagnosticsRunningWorkspaceCheck = diagnosticsRunningWorkspaceCheck; + + const keycloakToken = keycloakAuth.isPresent ? '?token=' + keycloakAuth.keycloak.token : ''; + this.jsonRpcApiLocation = this.cheWorkspace.formJsonRpcApiLocation($location, proxySettings, userDashboardConfig.developmentMode) + cheBranding.getWebsocketContext(); + this.jsonRpcApiLocation += keycloakToken; + this.cheJsonRpcMasterApi = cheJsonRpcApi.getJsonRpcMasterApi(this.jsonRpcApiLocation); } /** * Delete the diagnostic workspace (by stopping it first) if it's already running - * @param diagnosticCallback the callback used to send response - * @returns {IPromise} + * @param {DiagnosticCallback} diagnosticCallback the callback used to send response + * @returns {ng.IPromise} */ - deleteDiagnosticWorkspaceIfPresent(diagnosticCallback : DiagnosticCallback) : ng.IPromise { + deleteDiagnosticWorkspaceIfPresent(diagnosticCallback: DiagnosticCallback): ng.IPromise { let defered = this.$q.defer(); this.cheWorkspace.fetchWorkspaces().finally(() => { let workspaces: Array = this.cheWorkspace.getWorkspaces(); @@ -94,21 +126,22 @@ export class DiagnosticsWorkspaceStartCheck { // first stop if (workspace.status === 'RUNNING' || workspace.status === 'STARTING') { // listen on the events - let eventChannelLink = this.lodash.find(workspace.links, (link: any) => { - return link.rel === 'get workspace events channel'; - }); - let eventChannel = eventChannelLink ? eventChannelLink.parameters[0].defaultValue : null; - diagnosticCallback.subscribeChannel(eventChannel, (message: any) => { - if (message.eventType === 'STOPPED') { - diagnosticCallback.unsubscribeChannel(eventChannel); + const callback = (message: any) => { + if (message.status === 'STOPPED') { this.cheWorkspace.deleteWorkspaceConfig(workspace.id).finally(() => { defered.resolve(true); }); - } else if ('ERROR' === message.eventType) { + } else if ('ERROR' === message.status) { defered.reject(message.content); } + }; + this.cheJsonRpcMasterApi.subscribeWorkspaceStatus(workspace.id, callback); + defered.promise.then((wsIsStopped: boolean) => { + if (wsIsStopped) { + this.cheJsonRpcMasterApi.unSubscribeWorkspaceStatus(workspace.id, callback); + } }); - this.cheWorkspace.onStopWorkspace(workspace.id); + this.cheWorkspace.stopWorkspace(workspace.id); } else { this.cheWorkspace.deleteWorkspaceConfig(workspace.id).finally(() => { defered.resolve(true); @@ -117,7 +150,7 @@ export class DiagnosticsWorkspaceStartCheck { } else { defered.resolve(true); } - }).catch((error) => { + }).catch((error: any) => { defered.reject(error); }); return defered.promise; @@ -125,42 +158,42 @@ export class DiagnosticsWorkspaceStartCheck { /** * Always create a fresh workspace (by removing the old one if it exists) - * @param diagnosticCallback - * @returns {IPromise} + * @param {DiagnosticCallback} diagnosticCallback + * @returns {ng.IPromise} */ - recreateDiagnosticWorkspace(diagnosticCallback : DiagnosticCallback) : ng.IPromise { + recreateDiagnosticWorkspace(diagnosticCallback: DiagnosticCallback): ng.IPromise { let defered = this.$q.defer(); // delete if present this.deleteDiagnosticWorkspaceIfPresent(diagnosticCallback).then(() => { // now create workspace config let workspaceConfig: che.IWorkspaceConfig = { - "projects": [], - "environments": { - "diagnostics": { - "machines": { - "dev-machine": { - "agents": ["org.eclipse.che.ws-agent"], - "servers": {}, - "attributes": {"memoryLimitBytes": "1147483648"} + 'projects': [], + 'environments': { + 'diagnostics': { + 'machines': { + 'dev-machine': { + 'installers': ['org.eclipse.che.ws-agent'], + 'servers': {}, + 'attributes': {'memoryLimitBytes': '1147483648'} } }, - "recipe": { - "content": "FROM openjdk:8-jre-alpine\nCMD tail -f /dev/null\n", - "contentType": "text/x-dockerfile", - "type": "dockerfile" - } + 'recipe': { + 'content': 'FROM openjdk:8-jre-alpine\nRUN apk add --update bash\nCMD tail -f /dev/null\n', + 'contentType': 'text/x-dockerfile', + 'type': 'dockerfile' + }, + warnings: [] } }, - "name": "diagnostics", - "defaultEnv": "diagnostics", - "description": "Diagnostics Workspace", - "commands": [] + 'name': 'diagnostics', + 'defaultEnv': 'diagnostics', + 'commands': [] }; return this.cheWorkspace.createWorkspaceFromConfig(null, workspaceConfig); - }).then((workspace) => { + }).then((workspace: che.IWorkspace) => { defered.resolve(workspace); - }).catch((error) => { + }).catch((error: any) => { defered.reject(error); } ); @@ -169,39 +202,22 @@ export class DiagnosticsWorkspaceStartCheck { /** * Starts the test by adding new callbacks after this one - * @param diagnosticCallback the original check - * @returns {ng.IPromise} + * @param {DiagnosticCallback} diagnosticCallback the original check + * @returns {ng.IPromise} */ - start(diagnosticCallback : DiagnosticCallback) : ng.IPromise { + start(diagnosticCallback: DiagnosticCallback): ng.IPromise { this.workspaceCallback = diagnosticCallback.newCallback('Workspace State'); this.wsAgentCallback = diagnosticCallback.newCallback('Workspace Agent State'); this.machineCallback = diagnosticCallback.newCallback('Workspace Runtime State'); this.execAgentCallback = diagnosticCallback.newCallback('Workspace Exec Agent State'); - let workspaceIsStarted : boolean = false; - this.recreateDiagnosticWorkspace(diagnosticCallback).then((workspace : che.IWorkspace) => { - - let statusLink = this.lodash.find(workspace.links, (link: any) => { - return link.rel === 'environment/statusChannel'; - }); - - let eventChannelLink = this.lodash.find(workspace.links, (link: any) => { - return link.rel === 'get workspace events channel'; - }); - - let outputLink = this.lodash.find(workspace.links, (link: any) => { - return link.rel === 'environment/outputChannel'; - }); - - let eventChannel = eventChannelLink ? eventChannelLink.parameters[0].defaultValue : null; - let agentChannel = eventChannel + ':ext-server:output'; - let statusChannel = statusLink ? statusLink.parameters[0].defaultValue : null; - let outputChannel = outputLink ? outputLink.parameters[0].defaultValue : null; + let workspaceIsStarted: boolean = false; + this.recreateDiagnosticWorkspace(diagnosticCallback).then((workspace: che.IWorkspace) => { diagnosticCallback.shared('workspace', workspace); - diagnosticCallback.subscribeChannel(eventChannel, (message: any) => { + this.cheJsonRpcMasterApi.subscribeWorkspaceStatus(workspace.id, (message: any) => { diagnosticCallback.addContent('EventChannel : ' + JSON.stringify(message)); - if (message.eventType === 'RUNNING') { + if (message.status === 'RUNNING') { workspaceIsStarted = true; this.workspaceCallback.stateRunning('RUNNING'); this.cheWorkspace.fetchWorkspaces().then(() => { @@ -210,42 +226,40 @@ export class DiagnosticsWorkspaceStartCheck { this.cheWorkspace.fetchWorkspaceDetails(workspace.id).then(() => { let workspace = this.cheWorkspace.getWorkspaceById(workspaceId); diagnosticCallback.shared('workspace', workspace); - diagnosticCallback.shared('machineToken', workspace.runtime.devMachine.runtime.envVariables['CHE_MACHINE_TOKEN']); + diagnosticCallback.shared('machineToken', workspace.runtime.machineToken); diagnosticCallback.success('Starting workspace OK'); - }) + }); }); } }); - if (statusChannel) { - diagnosticCallback.subscribeChannel(statusChannel, (message: any) => { - if (message.eventType === 'DESTROYED' && message.workspaceId === workspace.id) { - diagnosticCallback.error('Error while starting the workspace : Workspace has been destroyed', 'Please check the diagnostic logs.'); - } - if (message.eventType === 'ERROR' && message.workspaceId === workspace.id) { - diagnosticCallback.error('Error while starting the workspace : ' + JSON.stringify(message)); - } + this.cheJsonRpcMasterApi.subscribeEnvironmentStatus(workspace.id, (message: any) => { + if (message.eventType === 'DESTROYED' && message.workspaceId === workspace.id) { + diagnosticCallback.error('Error while starting the workspace : Workspace has been destroyed', 'Please check the diagnostic logs.'); + } + if (message.eventType === 'ERROR' && message.workspaceId === workspace.id) { + diagnosticCallback.error('Error while starting the workspace : ' + JSON.stringify(message)); + } - if (message.eventType === 'RUNNING' && message.workspaceId === workspace.id && message.machineName === 'dev-machine') { - this.machineCallback.stateRunning('RUNNING'); - } + if (message.eventType === 'RUNNING' && message.workspaceId === workspace.id && message.machineName === 'dev-machine') { + this.machineCallback.stateRunning('RUNNING'); + } - diagnosticCallback.addContent('StatusChannel : ' + JSON.stringify(message)); + diagnosticCallback.addContent('StatusChannel : ' + JSON.stringify(message)); - }); - } + }); - diagnosticCallback.subscribeChannel(agentChannel, (message: any) => { + this.cheJsonRpcMasterApi.subscribeWsAgentOutput(workspace.id, (message: any) => { diagnosticCallback.addContent('agent channel :' + message); - if (message.indexOf(' Server startup') > 0) { + if (message.text.indexOf(' Server startup') > 0) { this.wsAgentCallback.stateRunning('RUNNING'); - // Server has been startup in the workspace agent and tries to reach workspace agent but is unable to do it + // server has been startup in the workspace agent and tries to reach workspace agent but is unable to do it // try with the browser ip diagnosticCallback.delayFunction(() => { - let hint : string = 'The workspace agent has started in the workspace, but the ' + this.cheBranding.getName() + ' server cannot verify this. There is a failure for ' + this.cheBranding.getName() + ' server to connect to your workspace\'s agent. Either your firewall is blocking essential ports or you can change '; + let hint: string = 'The workspace agent has started in the workspace, but the ' + this.cheBranding.getName() + ' server cannot verify this. There is a failure for ' + this.cheBranding.getName() + ' server to connect to your workspace\'s agent. Either your firewall is blocking essential ports or you can change '; if (this.cheBranding.getName() === 'Eclipse Che') { hint += 'CHE_DOCKER_IP and DOCKER_HOST to values '; } @@ -255,55 +269,50 @@ export class DiagnosticsWorkspaceStartCheck { this.cheWorkspace.fetchWorkspaceDetails(workspace.id).then(() => { let workspace = this.cheWorkspace.getWorkspaceById(workspaceId); diagnosticCallback.shared('workspace', workspace); - diagnosticCallback.shared('machineToken', workspace.runtime.devMachine.runtime.envVariables['CHE_MACHINE_TOKEN']); - let newCallback : DiagnosticCallback = diagnosticCallback.newCallback('Test connection from browser to workspace agent by using Workspace Agent IP'); + diagnosticCallback.shared('machineToken', workspace.runtime.machineToken); + let newCallback: DiagnosticCallback = diagnosticCallback.newCallback('Test connection from browser to workspace agent by using Workspace Agent IP'); this.diagnosticsRunningWorkspaceCheck.checkWsAgent(newCallback, false); - let websocketCallback : DiagnosticCallback = diagnosticCallback.newCallback('Test connection from browser to workspace agent with websocket'); + let websocketCallback: DiagnosticCallback = diagnosticCallback.newCallback('Test connection from browser to workspace agent with websocket'); this.diagnosticsRunningWorkspaceCheck.checkWebSocketWsAgent(websocketCallback); }); - }, 7000) + }, 7000); } diagnosticCallback.addContent(message); }); - if (outputChannel) { - diagnosticCallback.subscribeChannel(outputChannel, (message: any) => { - let content : string = angular.fromJson(message).content; - diagnosticCallback.addContent(content); + this.cheJsonRpcMasterApi.subscribeEnvironmentOutput(workspace.id, (message: any) => { + const content = message.text; + diagnosticCallback.addContent(content); - // check if connected (always pull) - if (content.indexOf('Client.Timeout exceeded while awaiting headers') > 0) { - diagnosticCallback.error('Network connection issue', 'Docker was unable to pull the right Docker image for the workspace. Either networking is not working from your Docker daemon or try disabling CHE_DOCKER_ALWAYSE__PULL__IMAGE in `che.env` to avoid pulling images over the network.'); - } + // check if connected (always pull) + if (content.indexOf('Client.Timeout exceeded while awaiting headers') > 0) { + diagnosticCallback.error('Network connection issue', 'Docker was unable to pull the right Docker image for the workspace. Either networking is not working from your Docker daemon or try disabling CHE_DOCKER_ALWAYSE__PULL__IMAGE in `che.env` to avoid pulling images over the network.'); + } - if (content.indexOf('dial tcp: lookup') > 0 && content.indexOf('server misbehaving') > 0) { - diagnosticCallback.error('Network connection issue', 'Docker is trying to connect to a Docker registry but the connection is failing. Check Docker\'s DNS settings and network connectivity.'); - } + if (content.indexOf('dial tcp: lookup') > 0 && content.indexOf('server misbehaving') > 0) { + diagnosticCallback.error('Network connection issue', 'Docker is trying to connect to a Docker registry but the connection is failing. Check Docker\'s DNS settings and network connectivity.'); + } - if (content.indexOf('Exec-agent configuration') > 0) { - this.execAgentCallback.stateRunning('RUNNING'); - } - diagnosticCallback.addContent('output channel message :' + JSON.stringify(message)); - }); - } + if (content.indexOf('Exec-agent configuration') > 0) { + this.execAgentCallback.stateRunning('RUNNING'); + } + diagnosticCallback.addContent('output channel message :' + JSON.stringify(message)); + }); diagnosticCallback.delayError('Test limit is for up to 5minutes. Time has exceed.', 5 * 60 * 1000); let startWorkspacePromise = this.cheWorkspace.startWorkspace(workspace.id, workspace.config.defaultEnv); - startWorkspacePromise.then((workspaceData) => { + startWorkspacePromise.then((workspaceData: che.IWorkspace) => { diagnosticCallback.shared('workspace', workspaceData); }); - }).catch((error) => { + }).catch((error: any) => { diagnosticCallback.error('Unable to start workspace: ' + error); }); - return diagnosticCallback.getPromise(); - } - } diff --git a/dashboard/src/app/index.module.ts b/dashboard/src/app/index.module.ts index f81db921ed..b9e56fc3cc 100755 --- a/dashboard/src/app/index.module.ts +++ b/dashboard/src/app/index.module.ts @@ -112,7 +112,7 @@ angular.element(document).ready(() => { }).catch((error: any) => { console.error('Keycloak initialization failed with error: ', error); }).then(() => { - angular.resumeBootstrap(); + (angular as any).resumeBootstrap(); }); });