Dashboard: fixed the diagnostics feature (#7199)

* code clean-up

Signed-off-by: Oleksii Kurinnyi <okurinny@redhat.com>

* CHE-6874: fix rerun of diagnostics

Signed-off-by: Oleksii Kurinnyi <okurinny@redhat.com>

* CHE-6919: fix the diagnostics feature

Signed-off-by: Oleksii Kurinnyi <okurinny@redhat.com>
6.19.x
Oleksii Kurinnyi 2017-11-06 14:22:30 +02:00 committed by GitHub
parent 53172e37bf
commit c9be731ff3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 386 additions and 389 deletions

View File

@ -8,6 +8,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
/**
* Defines the state of the diagnostic callback
* @author Florent Benoit

View File

@ -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<any>;
/**
* List of all channels on which we're listening for websockets.
*/
private listeningChannels : Array<string>;
private listeningChannels: Array<string>;
/**
* All timeouts that we're starting as part of this callback. They need to be stopped at the end.
*/
private timeoutPromises : Array<ng.IPromise>;
private timeoutPromises: Array<ng.IPromise<any>>;
/**
* Map used to send data across different fonctions.
*/
private sharedMap : Map<string, any>;
private sharedMap: Map<string, any>;
/**
* 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<DiagnosticItem>;
private items: Array<DiagnosticItem>;
/**
* Constructor.
*/
constructor($q : ng.IQService, cheWebsocket : CheWebsocket, $timeout : ng.ITimeoutService, name: string, sharedMap : Map<string, any>, builder : any, diagnosticPart : DiagnosticPart) {
constructor($q: ng.IQService, cheWebsocket: CheWebsocket, $timeout: ng.ITimeoutService, name: string, sharedMap: Map<string, any>, builder: any, diagnosticPart: DiagnosticPart) {
this.$q = $q;
this.cheWebsocket = cheWebsocket;
this.$timeout = $timeout;
this.defered = $q.defer();
this.listeningChannels = new Array<string>();
this.timeoutPromises = new Array<ng.IPromise>();
this.timeoutPromises = new Array<ng.IPromise<any>>();
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<any>}
*/
public getPromise() : ng.IPromise {
public getPromise(): ng.IPromise<any> {
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<any>) => {
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;
}
}

View File

@ -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';
}
}

View File

@ -8,6 +8,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
/**
* Defines the state of the diagnostic part
* @author Florent Benoit

View File

@ -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<DiagnosticItem>;
private items: Array<DiagnosticItem>;
/**
* All callbacks attached to this category.
*/
private callbacks : Array<DiagnosticCallback>;
private callbacks: Array<DiagnosticCallback>;
/**
* Current promises of all callbacks
*/
private callbackPromises : Array<ng.IPromise>;
private callbackPromises: Array<ng.IPromise<any>>;
/**
* 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<DiagnosticCallback>;
private callbacksEnded: Array<DiagnosticCallback>;
/**
* Constructor.
@ -80,7 +80,7 @@ export class DiagnosticPart {
this.items = new Array<DiagnosticItem>();
this.callbacks = new Array<DiagnosticCallback>();
this.callbacksEnded = new Array<DiagnosticCallback>();
this.callbackPromises = new Array<ng.IPromise>();
this.callbackPromises = new Array<ng.IPromise<any>>();
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;
}

View File

@ -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'

View File

@ -48,9 +48,9 @@
</div>
<div class="diagnostic-button" layout="row" layout-align="end center">
<che-button-default che-button-title="{{diagnosticsController.isLogDisplayed === false ? 'Show Logs' : 'Hide Logs'}}"
che-button-icon="fa fa-file-text-o"
ng-click="diagnosticsController.showLogs()"
ng-if="!diagnosticsController.isReady()"></che-button-default>
che-button-icon="fa fa-file-text-o"
ng-click="diagnosticsController.showLogs()"
ng-if="!diagnosticsController.isReady()"></che-button-default>
</div>
</div>
</div>

View File

@ -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<string, any>;
private sharedMap: Map<string, any>;
/**
* Reference to the diagnostic workspace checker.
*/
private diagnosticsRunningWorkspaceCheck : DiagnosticsRunningWorkspaceCheck;
private diagnosticsRunningWorkspaceCheck: DiagnosticsRunningWorkspaceCheck;
/**
* List of all parts.
*/
private parts : Array<DiagnosticPart>;
private parts: Array<DiagnosticPart>;
/**
* 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<T[]>}
* @returns {ng.IPromise<any>}
*/
waitAllCompleted(promises : Array<ng.IPromise>) : 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<any>>): ng.IPromise<any> {
const allCompletedDefered = this.$q.defer();
let finished: number = 0;
let toFinish: number = promises.length;
let error: boolean = false;
promises.forEach((promise: ng.IPromise<any>) => {
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<any>}
*/
public checkWorkspaceMaster() : ng.IPromise {
public checkWorkspaceMaster(): ng.IPromise<any> {
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<any> = 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<any>}
*/
public checkWorkspaceAgent() : ng.IPromise {
public checkWorkspaceAgent(): ng.IPromise<any> {
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<any> = 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<any>}
*/
public checkWorkspaceCheck() : ng.IPromise {
public checkWorkspaceCheck(): ng.IPromise<any> {
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<any>}
*/
public checkWebSocketWsAgent() : ng.IPromise {
public checkWebSocketWsAgent(): ng.IPromise<any> {
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;
}

View File

@ -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 = {};
}
}

View File

@ -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<any>} when test is finished
*/
start(diagnosticCallback : DiagnosticCallback) : ng.IPromise {
start(diagnosticCallback: DiagnosticCallback): ng.IPromise<any> {
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();
}
}

View File

@ -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<any>}
*/
checkAgentWithBrowserHost(diagnosticCallback : DiagnosticCallback) : ng.IPromise {
checkAgentWithBrowserHost(diagnosticCallback: DiagnosticCallback): ng.IPromise<any> {
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<any> = 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<any>}
*/
checkWsAgent(diagnosticCallback : DiagnosticCallback, errorInsteadOfFailure : boolean) : ng.IPromise {
checkWsAgent(diagnosticCallback: DiagnosticCallback, errorInsteadOfFailure: boolean): ng.IPromise<any> {
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<any>} when test is finished
*/
checkWebSocketWsAgent(diagnosticCallback : DiagnosticCallback) : ng.IPromise {
let workspace: che.IWorkspace = diagnosticCallback.getShared('workspace');
checkWebSocketWsAgent(diagnosticCallback: DiagnosticCallback): ng.IPromise<any> {
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<any> {
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;
}
}

View File

@ -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<any>}
*/
deleteDiagnosticWorkspaceIfPresent(diagnosticCallback : DiagnosticCallback) : ng.IPromise {
deleteDiagnosticWorkspaceIfPresent(diagnosticCallback: DiagnosticCallback): ng.IPromise<any> {
let defered = this.$q.defer();
this.cheWorkspace.fetchWorkspaces().finally(() => {
let workspaces: Array<che.IWorkspace> = 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<T>}
* @param {DiagnosticCallback} diagnosticCallback
* @returns {ng.IPromise<che.IWorkspace>}
*/
recreateDiagnosticWorkspace(diagnosticCallback : DiagnosticCallback) : ng.IPromise<che.IWorkspace> {
recreateDiagnosticWorkspace(diagnosticCallback: DiagnosticCallback): ng.IPromise<che.IWorkspace> {
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<any>}
*/
start(diagnosticCallback : DiagnosticCallback) : ng.IPromise {
start(diagnosticCallback: DiagnosticCallback): ng.IPromise<any> {
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();
}
}

View File

@ -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();
});
});