diff --git a/app/hydrator/main.js b/app/hydrator/main.js
index e2ee9005798..9e5799831b7 100644
--- a/app/hydrator/main.js
+++ b/app/hydrator/main.js
@@ -201,37 +201,12 @@ angular
window.CaskCommon.StatusFactory.startPollingForBackendStatus();
})
- .run(function (MYSOCKET_EVENT, myAlert, EventPipe) {
-
- EventPipe.on(MYSOCKET_EVENT.message, function (data) {
- if (data.statusCode > 399 && !data.resource.suppressErrors) {
- myAlert({
- title: data.statusCode.toString(),
- content: data.response || 'Server had an issue, please try refreshing the page',
- type: 'danger'
- });
- }
-
- // The user doesn't need to know that the backend node
- // is unable to connect to CDAP. Error messages add no
- // more value than the pop showing that the FE is waiting
- // for system to come back up. Most of the issues are with
- // connect, other than that pass everything else to user.
- if (data.warning && data.error.syscall !== 'connect') {
- myAlert({
- content: data.warning,
- type: 'warning'
- });
- }
- });
- })
-
/**
* BodyCtrl
* attached to the
tag, mostly responsible for
* setting the className based events from $state and caskTheme
*/
- .controller('BodyCtrl', function ($scope, $cookies, $cookieStore, caskTheme, CASK_THEME_EVENT, $rootScope, $state, $log, MYSOCKET_EVENT, MyCDAPDataSource, MY_CONFIG, MYAUTH_EVENT, EventPipe, myAuth, $window, myAlertOnValium, myLoadingService, myHelpers, $http) {
+ .controller('BodyCtrl', function ($scope, $cookies, $cookieStore, caskTheme, CASK_THEME_EVENT, $rootScope, $state, $log, MY_CONFIG, MYAUTH_EVENT, EventPipe, myAuth, $window, myAlertOnValium, myLoadingService, myHelpers, $http) {
window.CaskCommon.CDAPHelpers.setupExperiments();
var activeThemeClass = caskTheme.getClassName();
getVersion();
diff --git a/app/hydrator/routes.js b/app/hydrator/routes.js
index b35c37c7153..27c3458c691 100644
--- a/app/hydrator/routes.js
+++ b/app/hydrator/routes.js
@@ -289,10 +289,11 @@ angular.module(PKG.name + '.feature.hydrator')
});
return defer.promise;
},
- rVersion: function($state, MyCDAPDataSource) {
- var dataSource = new MyCDAPDataSource();
- return dataSource.request({
+ rVersion: function($state, $http, myCdapUrl) {
+ return $http.get(myCdapUrl.constructUrl({
_cdapPath: '/version'
+ })).then(function(res) {
+ return res.data;
});
}
},
diff --git a/app/services/cask-angular-socket-datasource/datasource.js b/app/services/cask-angular-socket-datasource/datasource.js
deleted file mode 100644
index 8465009c005..00000000000
--- a/app/services/cask-angular-socket-datasource/datasource.js
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright © 2015-2018 Cask Data, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-var socketDataSource = angular.module(PKG.name+'.services');
-
- /**
- Example Usage:
-
- MyCDAPDataSource // usage in a controller:
-
- var dataSrc = new MyCDAPDataSource($scope);
-
- // polling a namespaced resource example:
- dataSrc.poll({
- method: 'GET',
- _cdapNsPath: '/foo/bar',
- interval: 5000 // in milliseconds.
- },
- function(result) {
- $scope.foo = result;
- }
- ); // will poll :/v3/namespaces//foo/bar
-
- // posting to a systemwide resource:
- dataSrc.request({
- method: 'POST',
- _cdapPath: '/system/config',
- body: {
- foo: 'bar'
- }
- },
- function(result) {
- $scope.foo = result;
- }
- ); // will post to :/v3/system/config
-
- */
-
- socketDataSource.factory('uuid', function ($window) {
- return $window.uuid;
- });
-
-
- socketDataSource.provider('MyDataSource', function () {
-
- this.defaultPollInterval = 10;
-
- this.$get = function($rootScope, caskWindowManager, mySocket, MYSOCKET_EVENT, $q, MyPromise, uuid, EventPipe) {
- var CDAP_API_VERSION = 'v3';
- // FIXME (CDAP-14836): Right now this is scattered across node and client. Need to consolidate this.
- const REQUEST_ORIGIN_ROUTER = 'ROUTER';
-
- var instances = {}; // keyed by scopeid
-
-
- function DataSource (scope) {
- scope = scope || $rootScope.$new();
-
- var id = scope.$id,
- self = this;
-
- if(instances[id]) {
- // Reuse the same instance if already created.
- return instances[id];
- }
-
- if (!(this instanceof DataSource)) {
- return new DataSource(scope);
- }
- instances[id] = self;
-
- this.scopeId = id;
- this.bindings = {};
-
- EventPipe.on(MYSOCKET_EVENT.message, function (data) {
- var hash;
- var isPoll;
- hash = data.resource.id;
-
- if (data.statusCode>299 || data.warning) {
- if (self.bindings[hash]) {
- if (self.bindings[hash].errorCallback) {
- $rootScope.$apply(self.bindings[hash].errorCallback.bind(null, data.error || data.response));
- } else if (self.bindings[hash].reject) {
- $rootScope.$apply(self.bindings[hash].reject.bind(null, {data: data.error || data.response, statusCode: data.statusCode }));
- }
- }
- } else if (self.bindings[hash]) {
- if (self.bindings[hash].callback) {
- data.response = data.response || {};
- data.response.__pollId__ = hash;
- scope.$apply(self.bindings[hash].callback.bind(null, data.response));
- } else if (self.bindings[hash].resolve) {
- // https://github.com/angular/angular.js/wiki/When-to-use-$scope.$apply%28%29
- scope.$apply(self.bindings[hash].resolve.bind(null, {data: data.response, id: hash, statusCode: data.statusCode }));
- }
- /*
- At first glance this condition check might be redundant with line 157,
- however in the resolve or callback function if the user initiates a stop-poll call then
- the execution goes to stopPoll function in line 264 and there we delete the entry from bindings
- as we no longer need it. After the stopPoll request has gone out the execution continues back
- here and we can do self.bindings[hash].poll as self.bindings[hash] is already deleted in stopPoll.
- */
- if (!self.bindings[hash]) {
- return;
- }
- isPoll = self.bindings[hash].poll;
- if (!isPoll) {
- // We can remove the entry from the self bindings if its not a poll.
- // Is not going to be used for anything else.
- delete self.bindings[hash];
- } else {
- if (self.bindings[hash] && self.bindings[hash].type === 'POLL') {
- self.bindings[hash].resource.interval = startClientPoll(hash, self.bindings, self.bindings[hash].resource.intervalTime);
- }
- }
- }
- return;
- });
-
- EventPipe.on(MYSOCKET_EVENT.reconnected, () => {
- Object.keys(this.bindings).forEach((reqId) => {
- const req = self.bindings[reqId];
-
- if (req.poll) {
- pausePoll(self.bindings);
- }
- mySocket.send({
- action: 'request',
- resource: req.resource,
- });
- });
- });
-
- EventPipe.on(MYSOCKET_EVENT.closed, () => {
- pausePoll(self.bindings);
- });
-
- scope.$on('$destroy', function () {
- Object.keys(self.bindings).forEach(function(key) {
- var b = self.bindings[key];
- if (b.poll) {
- stopPoll(self.bindings, b.resource.id);
- }
- });
-
- delete instances[self.scopeId];
- });
-
- scope.$on(caskWindowManager.event.blur, function () {
- pausePoll(self.bindings);
- });
-
- scope.$on(caskWindowManager.event.focus, function () {
- resumePoll(self.bindings);
- });
-
- }
-
- function startClientPoll(resourceId, bindings, interval) {
- const intervalTimer = setTimeout(() => {
- const resource = bindings[resourceId]? bindings[resourceId].resource : undefined;
- if (!resource) {
- clearTimeout(intervalTimer);
- return;
- }
- mySocket.send({
- action: 'request',
- resource
- });
- }, interval);
- return intervalTimer;
- }
-
- function stopPoll(bindings, resourceId) {
- let id;
- if (typeof resourceId === 'object' && resourceId !== null) {
- id = resourceId.params.pollId;
- } else {
- id = resourceId;
- }
-
- if (bindings[id]) {
- clearTimeout(bindings[id].resource.interval);
- delete bindings[id];
- }
- }
-
- function pausePoll(bindings) {
- Object.keys(bindings)
- .filter(resourceId => bindings[resourceId].type === 'POLL')
- .forEach(resourceId => {
- clearTimeout(bindings[resourceId].resource.interval);
- });
- }
-
- function resumePoll(bindings) {
- Object.keys(bindings)
- .filter(resourceId => bindings[resourceId].type === 'POLL')
- .forEach(resourceId => {
- bindings[resourceId].resource.interval = startClientPoll(resourceId, bindings, bindings[resourceId].resource);
- });
- }
-
- /**
- * Start polling of a resource when in scope.
- */
- DataSource.prototype.poll = function (resource, cb, errorCb) {
- var self = this;
- var generatedResource = {};
- const intervalTime = resource.interval || (resource.options && resource.options.interval) || $rootScope.defaultPollInterval;
- var promise = new MyPromise(function(resolve, reject) {
- const resourceId = uuid.v4();
- generatedResource = {
- id: resourceId,
- json: resource.json,
- intervalTime,
- interval: startClientPoll(resourceId, self.bindings, intervalTime),
- body: resource.body,
- method: resource.method || 'GET',
- suppressErrors: resource.suppressErrors || false
- };
-
- if (resource.headers) {
- generatedResource.headers = resource.headers;
- }
-
- let apiVersion = resource.apiVersion || CDAP_API_VERSION;
- if (!resource.requestOrigin || resource.requestOrigin === REQUEST_ORIGIN_ROUTER) {
- resource.url = `/${apiVersion}${resource.url}`;
- }
-
- if (resource.requestOrigin) {
- generatedResource.requestOrigin = resource.requestOrigin;
- } else {
- generatedResource.requestOrigin = REQUEST_ORIGIN_ROUTER;
- }
-
- generatedResource.url = buildUrl(resource.url, resource.params || {});
- self.bindings[generatedResource.id] = {
- poll: true,
- type: 'POLL',
- callback: cb,
- resource: generatedResource,
- errorCallback: errorCb,
- resolve: resolve,
- reject: reject
- };
-
- mySocket.send({
- action: 'request',
- resource: generatedResource
- });
- }, true);
-
- if (!resource.$isResource) {
- promise = promise.then(function(res) {
- res = res.data;
- res.__pollId__ = generatedResource.id;
- return $q.when(res);
- });
- }
- promise.__pollId__ = generatedResource.id;
- return promise;
- };
-
- /**
- * Stop polling of a resource when requested.
- * (when scope is destroyed Line 196 takes care of deleting the polling resource)
- */
- DataSource.prototype.stopPoll = function(resourceId) {
- // Duck Typing for angular's $resource.
- var defer = $q.defer();
- var id, resource;
- if (angular.isObject(resourceId)) {
- id = resourceId.params.pollId;
- } else {
- id = resourceId;
- }
-
- var match = this.bindings[resourceId];
-
- if (match) {
- resource = match.resource;
- stopPoll(this.bindings, resourceId);
- defer.resolve({});
- } else {
- defer.reject({});
- }
- return defer.promise;
- };
-
- /**
- * Fetch a template configuration on-demand. Send the action
- * 'template-config' to the node backend.
- */
- DataSource.prototype.config = function (resource, cb, errorCb) {
- var deferred = $q.defer();
-
- resource.suppressErrors = true;
- resource.id = uuid.v4();
- this.bindings[resource.id] = {
- resource: resource,
- callback: function (result) {
- if (cb) {
- cb.apply(null, result);
- }
- deferred.resolve(result);
- },
- errorCallback: function(err) {
- if (errorCb) {
- errorCb.apply(null, err);
- }
- deferred.reject(err);
- }
- };
-
- mySocket.send({
- action: resource.actionName,
- resource: resource
- });
- return deferred.promise;
- };
-
- /**
- * Fetch a resource on-demand. Send the action 'request' to
- * the node backend.
- */
- DataSource.prototype.request = function (resource, cb, errorCb) {
- var self = this;
- var promise = new MyPromise(function(resolve, reject) {
-
- var generatedResource = {
- json: resource.json,
- method: resource.method || 'GET',
- suppressErrors: resource.suppressErrors || false
- };
- if (resource.body) {
- generatedResource.body = resource.body;
- }
-
- if (resource.data) {
- generatedResource.body = resource.data;
- }
-
- if (resource.headers) {
- generatedResource.headers = resource.headers;
- }
- if (resource.contentType) {
- generatedResource.headers['Content-Type'] = resource.contentType;
- }
-
- let apiVersion = resource.apiVersion || CDAP_API_VERSION;
- if (!resource.requestOrigin || resource.requestOrigin === REQUEST_ORIGIN_ROUTER) {
- resource.url = `/${apiVersion}${resource.url}`;
- }
- if (resource.requestOrigin) {
- generatedResource.requestOrigin = resource.requestOrigin;
- } else {
- generatedResource.requestOrigin = REQUEST_ORIGIN_ROUTER;
- }
- generatedResource.url = buildUrl(resource.url, resource.params || {});
- generatedResource.id = uuid.v4();
- self.bindings[generatedResource.id] = {
- type: 'REQUEST',
- callback: cb,
- errorCallback: errorCb,
- resource: generatedResource,
- resolve: resolve,
- reject: reject
- };
-
- mySocket.send({
- action: 'request',
- resource: generatedResource
- });
- }, false);
-
- if (!resource.$isResource) {
- promise = promise.then(function(res) {
- res = res.data;
- return $q.when(res);
- });
- }
-
- return promise;
- };
-
- return DataSource;
-
- };
-
-
- });
-
-// Lifted from $http as a helper method to parse '@params' in the url for $resource.
-function buildUrl(url, params) {
- if (!params) {
- return url;
- }
- var parts = [];
-
- function forEachSorted(obj, iterator, context) {
- var keys = Object.keys(params).sort();
- for (var i = 0; i < keys.length; i++) {
- iterator.call(context, obj[keys[i]], keys[i]);
- }
- return keys;
- }
-
- function encodeUriQuery(val, pctEncodeSpaces) {
- return encodeURIComponent(val).
- replace(/%40/gi, '@').
- replace(/%3A/gi, ':').
- replace(/%24/g, '$').
- replace(/%2C/gi, ',').
- replace(/%3B/gi, ';').
- replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
- }
-
- forEachSorted(params, function(value, key) {
- if (value === null || angular.isUndefined(value)) {
- return;
- }
- if (!angular.isArray(value)) {
- value = [value];
- }
-
- angular.forEach(value, function(v) {
- if (angular.isObject(v)) {
- if (angular.isDate(v)) {
- v = v.toISOString();
- } else {
- v = angular.toJson(v);
- }
- }
- parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(v));
- });
- });
- if (parts.length > 0) {
- url += ((url.indexOf('?') === -1) ? '?' : '&') + parts.join('&');
- }
- return url;
-}
diff --git a/app/services/cask-angular-socket-datasource/socket.js b/app/services/cask-angular-socket-datasource/socket.js
deleted file mode 100644
index ca1a3c1a925..00000000000
--- a/app/services/cask-angular-socket-datasource/socket.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright © 2015-2018 Cask Data, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-angular.module(PKG.name+'.services')
-
-.factory('SockJS', function ($window) {
- return $window.SockJS;
-})
-
-.constant('MYSOCKET_EVENT', {
- message: 'mysocket-message',
- closed: 'mysocket-closed',
- reconnected: 'mysocket-reconnected'
-})
-
-.provider('mySocket', function () {
-
- this.prefix = '/_sock';
-
- this.$get = function (MYSOCKET_EVENT, SockJS, $log, EventPipe) {
-
- var self = this,
- socket = null,
- buffer = [],
- firstTime = true;
-
- function init (attempt) {
- $log.log('[mySocket] init');
-
- attempt = attempt || 1;
- socket = new SockJS(self.prefix);
-
- socket.onmessage = function (event) {
- try {
- var data = JSON.parse(event.data);
- $log.debug('[mySocket] ←', data);
- EventPipe.emit(MYSOCKET_EVENT.message, data);
- }
- catch(e) {
- $log.error(e);
- }
- };
-
- socket.onopen = function () {
- if (!firstTime) {
- window.CaskCommon.SessionTokenStore.fetchSessionToken().then(() => {
- EventPipe.emit(MYSOCKET_EVENT.reconnected);
- attempt = 1;
- }, () => {
- console.log('Failed to fetch session token');
- });
- }
- firstTime = false;
-
- $log.info('[mySocket] opened');
- angular.forEach(buffer, send);
- buffer = [];
- };
-
- socket.onclose = function (event) {
- $log.error(event.reason);
- EventPipe.emit('backendDown', 'User interface service is down');
-
- if(attempt<2) {
- EventPipe.emit(MYSOCKET_EVENT.closed, event);
- }
-
- // reconnect with exponential backoff
- var d = Math.max(500, Math.round(
- (Math.random() + 1) * 500 * Math.pow(2, attempt)
- ));
- $log.log('[mySocket] will try again in ',d+'ms');
- setTimeout(function () {
- init(attempt+1);
- }, d);
- };
-
- }
-
- function send(obj) {
- if(!socket.readyState) {
- buffer.push(obj);
- return false;
- }
-
- doSend(obj);
-
- return true;
- }
-
- function doSend(obj) {
- var msg = obj,
- r = obj.resource;
-
- if(r) {
- msg.resource = r;
-
- // Majority of the time, we send data as json and expect a json response, but not always (i.e. stream ingest).
- // Default to json content-type.
- if (msg.resource.json === undefined) {
- msg.resource.json = true;
- }
-
- if (!r.method) {
- msg.resource.method = 'GET';
- }
-
- $log.debug('[mySocket] →', msg.action, r.method, r.url);
- }
- msg.sessionToken = window.CaskCommon.SessionTokenStore.default.getState();
-
- socket.send(JSON.stringify(msg));
- }
-
- init();
-
- return {
- init: init,
- send: send,
- close: function () {
- return socket.close.apply(socket, arguments);
- }
- };
- };
-
-});
diff --git a/app/services/dashboard/dashboardhelper.js b/app/services/dashboard/dashboardhelper.js
deleted file mode 100644
index c90a9d31806..00000000000
--- a/app/services/dashboard/dashboardhelper.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright © 2015 Cask Data, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-angular.module(PKG.name + '.services')
- .factory('DashboardHelper', function (MyCDAPDataSource, MyChartHelpers, MyMetricsQueryHelper) {
- var dataSrc = new MyCDAPDataSource();
-
- function startPolling (widget) {
- widget.pollId = dataSrc.poll({
- _cdapPath: '/metrics/query',
- method: 'POST',
- interval: widget.settings.interval,
- body: MyMetricsQueryHelper.constructQuery(
- 'qid',
- MyMetricsQueryHelper.contextToTags(widget.metric.context),
- widget.metric
- )
- }, function (res) {
-
- widget.formattedData = formatData(res, widget);
- }).__pollId__;
- }
-
-
- function stopPolling (widget) {
- dataSrc.stopPoll(widget.pollId);
- }
-
-
- function startPollDashboard (dashboard) {
- angular.forEach(dashboard.columns, function (widget) {
- startPolling(widget);
- });
- }
-
- function stopPollDashboard (dashboard) {
- angular.forEach(dashboard.columns, function (widget) {
- stopPolling(widget);
- });
- }
-
- function fetchData (widget) {
- return dataSrc.request({
- _cdapPath: '/metrics/query',
- method: 'POST',
- body: MyMetricsQueryHelper.constructQuery(
- 'qid',
- MyMetricsQueryHelper.contextToTags(widget.metric.context),
- widget.metric
- )
- })
- .then(function (res) {
- widget.formattedData = formatData(res, widget);
- });
- }
-
- function pollData (widget) {
- return dataSrc.poll({
- _cdapPath: '/metrics/query',
- method: 'POST',
- body: MyMetricsQueryHelper.constructQuery(
- 'qid',
- MyMetricsQueryHelper.contextToTags(widget.metric.context),
- widget.metric
- )
- })
- .then(function (res) {
- widget.formattedData = formatData(res, widget);
- });
- }
-
- function fetchDataDashboard (dashboard) {
- angular.forEach(dashboard.columns, function (widget) {
- fetchData(widget);
- });
- }
-
- function formatData (res, widget) {
- var processedData = MyChartHelpers.processData(
- res,
- 'qid',
- widget.metric.names,
- widget.metric.resolution,
- widget.settings.aggregate
- );
-
- processedData = MyChartHelpers.c3ifyData(processedData, widget.metric, widget.metricAlias);
- var data = {
- x: 'x',
- columns: processedData.columns,
- keys: {
- x: 'x'
- }
- };
-
- return data;
- }
-
- return {
- startPolling: startPolling,
- stopPolling: stopPolling,
- startPollDashboard: startPollDashboard,
- stopPollDashboard: stopPollDashboard,
- fetchData: fetchData,
- pollData: pollData,
- fetchDataDashboard: fetchDataDashboard
- };
-
- });
diff --git a/app/services/data/my-cdap-datasource.js b/app/services/data/my-cdap-datasource.js
deleted file mode 100644
index 92da5124247..00000000000
--- a/app/services/data/my-cdap-datasource.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright © 2015 Cask Data, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-angular.module(PKG.name + '.services')
- .factory('MyCDAPDataSource', function(MyDataSource, $rootScope, myCdapUrl, $cookies) {
- function MyCDAPDataSource(scope) {
- scope = scope || $rootScope.$new();
-
- if (!(this instanceof MyCDAPDataSource)) {
- return new MyCDAPDataSource(scope);
- }
-
- this.MyDataSource = new MyDataSource(scope);
- }
-
- MyCDAPDataSource.prototype.poll = function (resource, cb, errorCb) {
- resource.headers = {};
-
- if (!resource.url) {
- resource.url = myCdapUrl.constructUrl(resource);
- }
-
- return this.MyDataSource.poll(resource, cb, errorCb);
- };
-
- MyCDAPDataSource.prototype.stopPoll = function (resourceId) {
- return this.MyDataSource.stopPoll(resourceId);
- };
-
- MyCDAPDataSource.prototype.config = function(resource, cb, errorCb) {
- resource.actionName = 'template-config';
- return this.MyDataSource.config(resource, cb, errorCb);
- };
-
- MyCDAPDataSource.prototype.request = function(resource, cb, errorCb) {
- resource.headers = {};
-
- if (!resource.url) {
- resource.url = myCdapUrl.constructUrl(resource);
- }
-
- return this.MyDataSource.request(resource, cb, errorCb);
- };
-
- return MyCDAPDataSource;
-
- });
diff --git a/app/services/namespace.js b/app/services/namespace.js
index 531aa0d8239..6098dab7319 100644
--- a/app/services/namespace.js
+++ b/app/services/namespace.js
@@ -15,7 +15,7 @@
*/
angular.module(PKG.name + '.services')
- .service('myNamespace', function myNamespace($q, MyCDAPDataSource, EventPipe, $http, $rootScope, myAuth, myHelpers, $state) {
+ .service('myNamespace', function myNamespace($q, EventPipe, $http, $rootScope, myAuth, myHelpers, $state) {
this.namespaceList = [];
var prom,
diff --git a/app/services/settings.js b/app/services/settings.js
index 79075f1ebd3..4b697c08cc7 100644
--- a/app/services/settings.js
+++ b/app/services/settings.js
@@ -20,9 +20,7 @@ angular.module(PKG.name + '.services')
return new MyPersistentStorage('user');
})
- .factory('MyPersistentStorage', function MyPersistentStorageFactory($q, MyCDAPDataSource, myHelpers, $rootScope, MYAUTH_EVENT) {
-
- var data = new MyCDAPDataSource();
+ .factory('MyPersistentStorage', function MyPersistentStorageFactory($q, $http, myCdapUrl, myHelpers, $rootScope, MYAUTH_EVENT) {
function MyPersistentStorage (type) {
this.endpoint = '/configuration/' + type;
this.headers = {
@@ -54,14 +52,16 @@ angular.module(PKG.name + '.services')
if (window.CaskCommon.CDAPHelpers.isAuthSetToManagedMode()) {
this.headers['Authorization'] = ($rootScope.currentUser.token ? 'Bearer ' + $rootScope.currentUser.token: null);
}
- return data.request(
+ return $http(
{
method: 'PUT',
- _cdapPath: this.endpoint,
+ url: myCdapUrl.constructUrl({ _cdapPath: this.endpoint }),
headers: this.headers,
- body: this.data
+ data: this.data
}
- );
+ ).then(function(res) {
+ return res.data;
+ });
};
@@ -97,14 +97,15 @@ angular.module(PKG.name + '.services')
this.pending = $q.defer();
- data.request(
+ $http(
{
method: 'GET',
headers: this.headers,
- _cdapPath: this.endpoint
- },
+ url: myCdapUrl.constructUrl({ _cdapPath: this.endpoint })
+ }
+ ).then(
function (res) {
- self.data = res.property;
+ self.data = res.data.property;
self.pending.resolve(
myHelpers.deepGet(self.data, key, true)
);
diff --git a/package.json b/package.json
index 5f704835af6..ba4b222f86f 100644
--- a/package.json
+++ b/package.json
@@ -290,8 +290,6 @@
"selenium-webdriver": "^4.1.1",
"serve-favicon": "2.5.0",
"shepherd.js": "2.0.0-beta.17",
- "sockjs": "0.3.19",
- "sockjs-client": "1.4.0",
"styled-components": "5.3.1",
"svg4everybody": "2.1.9",
"typescript": "4.0.5",
diff --git a/server.js b/server.js
index 659ee3354e5..188eee5cbd2 100644
--- a/server.js
+++ b/server.js
@@ -14,7 +14,6 @@
* the License.
*/
-import sockjs from 'sockjs';
import http from 'http';
import fs from 'fs';
import log4js from 'log4js';
@@ -22,7 +21,6 @@ import https from 'https';
import ip from 'ip';
import cookie from 'cookie';
import { getApp } from 'server/express';
-import Aggregator from 'server/aggregator';
import { extractConfig } from 'server/config/parser';
import { getCDAPConfig } from 'server/cdap-config';
import { applyGraphQLMiddleware } from 'gql/graphql';
@@ -32,7 +30,6 @@ import middleware404 from 'server/middleware-404';
var cdapConfig,
securityConfig,
allowedOrigin = [],
- wsConnections = {},
hostname,
hostIP = ip.address();
@@ -195,82 +192,9 @@ getCDAPConfig()
})
.then(async function(server) {
- var sockServer = sockjs.createServer({
- log: function(lvl, msg) {
- log.trace(msg);
- },
- });
- /**
- * Node server now supports Proxy mode. This means, between the client and the node proxy
- * there can be another proxy that handle authentication and pass on the user id and auth token.
- * This means the client will not know anything about the user but the node proxy and the backend
- * will be configured to pass on the auth token and user id from the proxy for authentication.
- *
- * This is the journey of an auth token and user id in proxy mode.
- *
- * 1. CDAP starts in k8s which spins up UI in a pod with
- * security.authentication.mode: PROXY
- * security.authentication.proxy.user.identity.header: x-inverting-proxy-user-id
- * 2. Once node proxy goes to PROXY mode, it will get the auth token only for the http
- * requests.
- * 3. The client will not know about the auth token either.
- * 4. Once the client reaches CDAP UI, the proxy would have already authenticated the user.
- * 5. The request to upgrade websocket connection should already have the auth token and the user id
- * 6. We take those values and add to the connection object (sockjs connection object)
- * 7. This then gets picked up at the aggregator module that actually makes the call to the
- * backend along with these in the request header.
- * 8. Upon receiving the response, we remove these from the request object and send it back
- * to the client as if no authentication exists.
- */
- let authToken, userid;
- sockServer.on('connection', function(c) {
- if (!c) {
- log.error('Connection requested, but no connection available');
- return;
- }
- log.debug('[SOCKET OPEN] Connection to client "' + c.id + '" opened');
- // @ts-ignore
- var a = new Aggregator(c, { ...cdapConfig, ...securityConfig });
- c.authToken = authToken;
- c.userid = userid;
- wsConnections[c.id] = c;
- c.on('close', function() {
- log.debug('Cleaning out aggregator: ' + JSON.stringify(a.connection.id));
- a = null;
- c.end();
- c.destroy();
- delete wsConnections[c.id];
- });
- });
-
- sockServer.installHandlers(server, { prefix: '/_sock' });
- server.addListener('upgrade', function(req, socket) {
- req.headers.authorization = getAuthHeaderFromRawCookies(req);
- authToken = req.headers.authorization;
- const userIdProperty = cdapConfig['security.authentication.proxy.user.identity.header'];
- userid = req.headers[userIdProperty];
-
- if (allowedOrigin.indexOf(req.headers.origin) === -1) {
- log.info('Unknown Origin: ' + req.headers.origin);
- log.info('Denying socket connection and closing the channel');
- socket.end();
- socket.destroy();
- return;
- }
- });
function gracefulShutdown() {
- log.info('Caught SIGTERM. Closing http & ws server');
+ log.info('Caught SIGTERM. Closing http server');
server.close();
- if (typeof wsConnections === 'object' && Object.keys(wsConnections).length) {
- log.debug(`Closing ${Object.keys(wsConnections).length} open websocket connections`)
- Object.values(wsConnections).forEach((connection) => {
- log.debug('Ending and destroying all graceful shutdown: ' + connection.readyState);
- connection.end();
- connection.destroy();
- });
- log.debug('Closed all open websocket connections');
- wsConnections = {};
- }
process.exit(0);
}
process.on('SIGTERM', gracefulShutdown);
diff --git a/server/aggregator.js b/server/aggregator.js
deleted file mode 100644
index 90bd1b47a15..00000000000
--- a/server/aggregator.js
+++ /dev/null
@@ -1,353 +0,0 @@
-// @ts-nocheck
-/*
- * Copyright © 2015-2020 Cask Data, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-import request from 'request';
-import fs from 'fs';
-import log4js from 'log4js';
-import { REQUEST_ORIGIN_ROUTER, REQUEST_ORIGIN_MARKET, constructUrl, deconstructUrl, isVerifiedMarketHost} from 'server/url-helper';
-import * as sessionToken from 'server/token';
-import { stripAuthHeadersInProxyMode } from 'server/express';
-const log = log4js.getLogger('default');
-/**
- * Aggregator
- * receives resourceObj, aggregate them,
- * and send poll responses back through socket
- *
- * @param {Object} SockJS connection
- */
-function Aggregator(conn, cdapConfig) {
- // make 'new' optional
- if (!(this instanceof Aggregator)) {
- return new Aggregator(conn);
- }
- this.cdapConfig = cdapConfig;
- this.connection = conn;
-
- this.initializeEventListeners();
- this.isSessionValid = false;
-}
-
-Aggregator.prototype.stripAuthHeaderInProxyMode = stripAuthHeadersInProxyMode;
-
-Aggregator.prototype.initializeEventListeners = function() {
- /**
- * Handler for data from client via websocket connection
- * Checks for the session token in the first message.
- * If valid sets the isSessionValid flag to true and proceeds to skip
- * validations for subsequent messages.
- */
- this.connection.on('data', (message) => {
- if (this.isSessionValid) {
- return onSocketData.call(this, message);
- }
- if (!this.validateSession(message)) {
- return;
- }
- this.isSessionValid = true;
- onSocketData.call(this, message);
- });
- this.connection.on('close', onSocketClose.bind(this));
-};
-
-Aggregator.prototype.validateSession = function(message) {
- let messageJSON;
- try {
- /**
- * Closes the connection if the session is not valid.
- */
- messageJSON = JSON.parse(message);
- let authToken = '';
- if (
- messageJSON.resource &&
- messageJSON.resource.headers &&
- messageJSON.resource.headers.Authorization
- ) {
- authToken = messageJSON.resource.headers.Authorization;
- }
- if (!sessionToken.validateToken(messageJSON.sessionToken, this.cdapConfig, log, authToken)) {
- log.error('Found invalid session token. Closing websocket connection');
- this.connection.end();
- onSocketClose.call(this);
- return false;
- }
- } catch (e) {
- log.error('Unable to parse message : ' + e);
- return false;
- }
- return true;
-};
-
-/**
- * Pushes the ETL Application configuration for templates and plugins to the
- * FE. These configurations are UI specific and hences need to be supported
- * here.
- */
-Aggregator.prototype.pushConfiguration = function(resource) {
- var templateid = resource.templateid;
- var pluginid = resource.pluginid;
- var configString;
- var config = {};
- var statusCode = 404;
- var filePaths = [];
- var isConfigSemanticsValid;
- // Some times there might a plugin that is common across multiple templates
- // in which case, this is stored within the common directory. So, if the
- // template specific plugin check fails, then attempt to get it from common.
- filePaths.push(
- __dirname + '/../templates/' + templateid + '/' + pluginid + '.json',
- __dirname + '/../templates/common/' + pluginid + '.json'
- );
- var i,
- paths = filePaths.length;
- var fileFound = true;
-
- // Check if the configuration is present within the plugin for a template
- for (i = 0; i < paths; i++) {
- try {
- configString = fs.readFileSync(filePaths[i], 'utf8');
- statusCode = 200;
- fileFound = true;
- break;
- } catch (e) {
- if (e.code === 'ENOENT') {
- fileFound = false;
- }
- }
- }
- if (!fileFound) {
- statusCode = 404;
- config = 'NO_JSON_FOUND';
- } else {
- try {
- config = JSON.parse(configString);
- statusCode = 200;
- } catch (e) {
- statusCode = 500;
- config = 'CONFIG_SYNTAX_JSON_ERROR';
- }
- }
-
- if (statusCode === 200 && !(config.metadata && config.metadata['spec-version'])) {
- isConfigSemanticsValid = validateSemanticsOfConfigJSON(config);
- if (!isConfigSemanticsValid) {
- statusCode = 500;
- config = 'CONFIG_SEMANTICS_JSON_ERROR';
- }
- }
-
- this.connection.write(
- JSON.stringify({
- resource: this.stripAuthHeaderInProxyMode(this.cdapConfig, resource),
- statusCode: statusCode,
- response: config,
- })
- );
-};
-
-function validateSemanticsOfConfigJSON(config) {
- var groups = config.groups.position;
- var groupsMap = config.groups;
- var i, j;
- var isValid = true;
- var fields, fieldsMap;
-
- for (i = 0; i < groups.length; i++) {
- if (!groupsMap[groups[i]] || !isValid) {
- isValid = false;
- break;
- }
-
- fields = groupsMap[groups[i]].position;
- fieldsMap = groupsMap[groups[i]].fields;
-
- if (!fields || !fieldsMap) {
- isValid = false;
- } else {
- for (j = 0; j < fields.length; j++) {
- if (!fieldsMap[fields[j]]) {
- isValid = false;
- break;
- }
- }
- }
- }
-
- return isValid;
-}
-
-/**
- * Helps avoid sending certain properties to the browser (meta attributes used only in the node server)
- */
-function stripResource(key, value) {
- // note that 'stop' is not the stop timestamp, but rather a stop flag/signal (unlike the startTs)
- if (key === 'timerId' || key === 'startTs' || key === 'stop') {
- return undefined;
- }
- return value;
-}
-
-/**
- * @private emitResponse
- *
- * sends data back to the client through socket
- *
- * @param {object} resource that was requested
- * @param {error|null} error
- * @param {object} response
- * @param {string} body
- */
-function emitResponse(resource, error, response, body) {
- var timeDiff = Date.now() - resource.startTs;
- let authMode = this.cdapConfig['security.authentication.mode'];
- /**
- * In proxy mode, we stub the 401 response from backend with 500.
- * This is because the proxy is still using an auth token that is expired.
- * The client (broweser UI) does not understand this and will redirect to login page
- * But since security is not enabled from a ui perspective it will again redirect
- * to the destination page causing an infinite loop.
- *
- * This is to break the cycle. This will never happen in an ideal case. This is an
- * escape hatch when we go to the worst case.
- * @param {*} response - response from backend
- */
- const getResponseCode = (response) => {
- if (authMode === 'PROXY' && response && response.statusCode === 401) {
- return 500;
- }
- return response && response.statusCode;
- };
- if (error) {
- log.debug('[ERROR]: (id: ' + resource.id + ', url: ' + resource.url + ')');
- log.trace(
- '[ERROR]: (id: ' +
- resource.id +
- ', url: ' +
- resource.url +
- ') body : (' +
- error.toString() +
- ')'
- );
-
- let newResource = Object.assign({}, resource, {
- url: deconstructUrl(this.cdapConfig, resource.url, resource.requestOrigin),
- });
- this.connection.write(
- JSON.stringify(
- {
- resource: this.stripAuthHeaderInProxyMode(this.cdapConfig, newResource),
- error: error,
- warning: error.toString(),
- statusCode: getResponseCode(response),
- response: response && response.body,
- },
- stripResource
- )
- );
- } else {
- log.debug('[SUCCESS]: (id: ' + resource.id + ', url: ' + resource.url + ')');
- log.trace(
- '[' +
- timeDiff +
- 'ms] Success (' +
- resource.id +
- ',' +
- resource.url +
- ') body : (' +
- JSON.stringify(body) +
- ')'
- );
- let newResource = Object.assign({}, resource, {
- url: deconstructUrl(this.cdapConfig, resource.url, resource.requestOrigin),
- });
- log.debug('[RESPONSE]: (id: ' + newResource.id + ', url: ' + newResource.url + ')');
- this.connection.write(
- JSON.stringify(
- {
- resource: this.stripAuthHeaderInProxyMode(this.cdapConfig, newResource),
- statusCode: getResponseCode(response),
- response: body,
- },
- stripResource
- )
- );
- }
-}
-
-/**
- * @private onSocketData
- * @param {string} message received via socket
- */
-function onSocketData(message) {
- try {
- message = JSON.parse(message);
- var r = message.resource;
- // early out if market place url is invalid. The server won't attempt to request the specified url.
- if (r.requestOrigin === REQUEST_ORIGIN_MARKET && !isVerifiedMarketHost(this.cdapConfig, r.url)) {
- log.debug('[REQUEST]: (method: ' + r.method + ', id: ' + r.id + ', url: ' + r.url + ')');
- const invalidMarketRequestError = new Error('invalid market request');
- emitResponse.call(this, r, invalidMarketRequestError, {statusCode: 403, body: invalidMarketRequestError.message});
- log.error('[ERROR]: (url: ' + r.url + ') ' + invalidMarketRequestError.message);
- return;
- }
- r.url = constructUrl(
- this.cdapConfig,
- r.url,
- r.requestOrigin || REQUEST_ORIGIN_ROUTER
- );
- switch (message.action) {
- case 'template-config':
- log.debug(
- 'ETL application config request (' +
- r.method +
- ',' +
- r.id +
- ',' +
- r.templateid +
- ',' +
- r.pluginid
- );
- this.pushConfiguration(r);
- break;
- case 'request':
- r.startTs = Date.now();
- if (!r.requestOrigin || r.requestOrigin === REQUEST_ORIGIN_ROUTER) {
- if (!r.headers) {
- r.headers = {};
- }
- r.headers.Authorization = this.connection.authToken;
- r.headers.authorization = this.connection.authToken;
- r.headers[this.cdapConfig['security.authentication.proxy.user.identity.header']] = this.connection.userid;
- }
- log.debug('[REQUEST]: (method: ' + r.method + ', id: ' + r.id + ', url: ' + r.url + ')');
- request(r, emitResponse.bind(this, r)).on('error', function(err) {
- log.error('[ERROR]: (url: ' + r.url + ') ' + err.message);
- });
- break;
- }
- } catch (e) {
- log.warn(e);
- }
-}
-
-/**
- * @private onSocketClose
- */
-function onSocketClose() {
- log.debug('[SOCKET CLOSE] Connection to client "' + this.connection.id + '" closed');
-}
-
-export default Aggregator;