Commit 04fde4bd by Samuel Padgett

Avoid runtime errors when requested resource doesn't exist

Update DataService to tolerate requests for resources that were not
found during discovery. This will show an error notification and reject
the promise rather than resulting in a runtime error.
parent 5ea67be6
...@@ -1521,6 +1521,27 @@ angular.module('openshiftCommonServices') ...@@ -1521,6 +1521,27 @@ angular.module('openshiftCommonServices')
addQueuedNotifications(); addQueuedNotifications();
}; };
var unknownResourceError = function(resource, opts) {
var message;
if (!resource) {
message = 'Internal error: API resource not specified.';
} else {
// APIService ResourceGroupVersion objects implement toString()
message = "Unknown resource: " + resource.toString();
}
if (_.get(opts, 'errorNotification', true)) {
// No HTTP status since no request was made.
showRequestError(message);
}
return $q.reject({
data: {
message: message
}
});
}
function DataService() { function DataService() {
this._listDeferredMap = {}; this._listDeferredMap = {};
this._watchCallbacksMap = {}; this._watchCallbacksMap = {};
...@@ -1613,12 +1634,16 @@ angular.module('openshiftCommonServices') ...@@ -1613,12 +1634,16 @@ angular.module('openshiftCommonServices')
data.gracePeriodSeconds = opts.gracePeriodSeconds; data.gracePeriodSeconds = opts.gracePeriodSeconds;
} }
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns)
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'DELETE', method: 'DELETE',
auth: {}, auth: {},
data: data, data: data,
headers: headers, headers: headers,
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data); deferred.resolve(data);
...@@ -1648,11 +1673,15 @@ angular.module('openshiftCommonServices') ...@@ -1648,11 +1673,15 @@ angular.module('openshiftCommonServices')
var deferred = $q.defer(); var deferred = $q.defer();
var self = this; var self = this;
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns);
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'PUT', method: 'PUT',
auth: {}, auth: {},
data: object, data: object,
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data); deferred.resolve(data);
...@@ -1717,11 +1746,15 @@ angular.module('openshiftCommonServices') ...@@ -1717,11 +1746,15 @@ angular.module('openshiftCommonServices')
var deferred = $q.defer(); var deferred = $q.defer();
var self = this; var self = this;
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns);
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'POST', method: 'POST',
auth: {}, auth: {},
data: object, data: object,
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data); deferred.resolve(data);
...@@ -1840,10 +1873,14 @@ angular.module('openshiftCommonServices') ...@@ -1840,10 +1873,14 @@ angular.module('openshiftCommonServices')
else { else {
var self = this; var self = this;
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns);
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'GET', method: 'GET',
auth: {}, auth: {},
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
if (self._isImmutable(resource)) { if (self._isImmutable(resource)) {
...@@ -1888,9 +1925,14 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -1888,9 +1925,14 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
var makeStream = function() { var makeStream = function() {
return self._getNamespace(resource, context, {}) return self._getNamespace(resource, context, {})
.then(function(params) { .then(function(params) {
var url = self._urlForResource(resource, name, context, true, _.extend(params, opts));
if (!url) {
return unknownResourceError(resource, opts);
}
var cumulativeBytes = 0; var cumulativeBytes = 0;
return $ws({ return $ws({
url: self._urlForResource(resource, name, context, true, _.extend(params, opts)), url: url,
auth: {}, auth: {},
onopen: function(evt) { onopen: function(evt) {
_.each(openQueue, function(fn) { _.each(openQueue, function(fn) {
...@@ -2100,7 +2142,7 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -2100,7 +2142,7 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
opts = opts || {}; opts = opts || {};
var key = this._uniqueKey(resource, name, context, opts); var key = this._uniqueKey(resource, name, context, opts);
var wrapperCallback; var wrapperCallback;
if (callback) { if (key && callback) {
// If we were given a callback, add it // If we were given a callback, add it
this._watchObjectCallbacks(key).add(callback); this._watchObjectCallbacks(key).add(callback);
var self = this; var self = this;
...@@ -2365,17 +2407,26 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -2365,17 +2407,26 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
// bool. Both websocket & http operations should respond with the same data from cache if key matches // bool. Both websocket & http operations should respond with the same data from cache if key matches
// so the unique key will always include http:// // so the unique key will always include http://
DataService.prototype._uniqueKey = function(resource, name, context, opts) { DataService.prototype._uniqueKey = function(resource, name, context, opts) {
var key;
var ns = context && context.namespace || var ns = context && context.namespace ||
_.get(context, 'project.metadata.name') || _.get(context, 'project.metadata.name') ||
context.projectName; context.projectName;
var params = _.get(opts, 'http.params'); var params = _.get(opts, 'http.params');
var url = this._urlForResource(resource, name, context, null, angular.extend({}, {}, {namespace: ns})).toString() + paramsForKey(params || {}); var url = this._urlForResource(resource, name, context, null, angular.extend({}, {}, {namespace: ns}));
if (url) {
key = url.toString();
} else {
// Fall back to the ResourceGroupVersion string, "resource/group/version", for resources that weren't
// found during discovery.
key = resource || '<unknown>';
}
key = key + paramsForKey(params || {});
if (_.get(opts, 'partialObjectMetadataList')) { if (_.get(opts, 'partialObjectMetadataList')) {
// Make sure partial objects get a different cache key. // Make sure partial objects get a different cache key.
return url + '#' + ACCEPT_PARTIAL_OBJECT_METADATA_LIST; return key + '#' + ACCEPT_PARTIAL_OBJECT_METADATA_LIST;
} }
return url; return key;
}; };
...@@ -2391,14 +2442,20 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -2391,14 +2442,20 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
headers.Accept = ACCEPT_PARTIAL_OBJECT_METADATA_LIST; headers.Accept = ACCEPT_PARTIAL_OBJECT_METADATA_LIST;
} }
var url;
var self = this; var self = this;
if (context.projectPromise && !resource.equals("projects")) { if (context.projectPromise && !resource.equals("projects")) {
context.projectPromise.done(function(project) { context.projectPromise.done(function(project) {
url = self._urlForResource(resource, null, context, false, _.assign({}, params, {namespace: project.metadata.name}))
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'GET', method: 'GET',
auth: {}, auth: {},
headers: headers, headers: headers,
url: self._urlForResource(resource, null, context, false, _.assign({}, params, {namespace: project.metadata.name})) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
self._listOpComplete(key, resource, context, opts, data); self._listOpComplete(key, resource, context, opts, data);
...@@ -2423,11 +2480,16 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -2423,11 +2480,16 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
}); });
} }
else { else {
url = this._urlForResource(resource, null, context, false, params);
if (!url) {
return unknownResourceError(resource, opts);
}
$http({ $http({
method: 'GET', method: 'GET',
auth: {}, auth: {},
headers: headers, headers: headers,
url: this._urlForResource(resource, null, context, false, params), url: url
}).success(function(data, status, headerFunc, config, statusText) { }).success(function(data, status, headerFunc, config, statusText) {
self._listOpComplete(key, resource, context, opts, data); self._listOpComplete(key, resource, context, opts, data);
}).error(function(data, status, headers, config) { }).error(function(data, status, headers, config) {
......
...@@ -3587,6 +3587,27 @@ angular.module('openshiftCommonServices') ...@@ -3587,6 +3587,27 @@ angular.module('openshiftCommonServices')
addQueuedNotifications(); addQueuedNotifications();
}; };
var unknownResourceError = function(resource, opts) {
var message;
if (!resource) {
message = 'Internal error: API resource not specified.';
} else {
// APIService ResourceGroupVersion objects implement toString()
message = "Unknown resource: " + resource.toString();
}
if (_.get(opts, 'errorNotification', true)) {
// No HTTP status since no request was made.
showRequestError(message);
}
return $q.reject({
data: {
message: message
}
});
}
function DataService() { function DataService() {
this._listDeferredMap = {}; this._listDeferredMap = {};
this._watchCallbacksMap = {}; this._watchCallbacksMap = {};
...@@ -3679,12 +3700,16 @@ angular.module('openshiftCommonServices') ...@@ -3679,12 +3700,16 @@ angular.module('openshiftCommonServices')
data.gracePeriodSeconds = opts.gracePeriodSeconds; data.gracePeriodSeconds = opts.gracePeriodSeconds;
} }
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns)
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'DELETE', method: 'DELETE',
auth: {}, auth: {},
data: data, data: data,
headers: headers, headers: headers,
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data); deferred.resolve(data);
...@@ -3714,11 +3739,15 @@ angular.module('openshiftCommonServices') ...@@ -3714,11 +3739,15 @@ angular.module('openshiftCommonServices')
var deferred = $q.defer(); var deferred = $q.defer();
var self = this; var self = this;
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns);
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'PUT', method: 'PUT',
auth: {}, auth: {},
data: object, data: object,
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data); deferred.resolve(data);
...@@ -3783,11 +3812,15 @@ angular.module('openshiftCommonServices') ...@@ -3783,11 +3812,15 @@ angular.module('openshiftCommonServices')
var deferred = $q.defer(); var deferred = $q.defer();
var self = this; var self = this;
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns);
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'POST', method: 'POST',
auth: {}, auth: {},
data: object, data: object,
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data); deferred.resolve(data);
...@@ -3906,10 +3939,14 @@ angular.module('openshiftCommonServices') ...@@ -3906,10 +3939,14 @@ angular.module('openshiftCommonServices')
else { else {
var self = this; var self = this;
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns);
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'GET', method: 'GET',
auth: {}, auth: {},
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
if (self._isImmutable(resource)) { if (self._isImmutable(resource)) {
...@@ -3954,9 +3991,14 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -3954,9 +3991,14 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
var makeStream = function() { var makeStream = function() {
return self._getNamespace(resource, context, {}) return self._getNamespace(resource, context, {})
.then(function(params) { .then(function(params) {
var url = self._urlForResource(resource, name, context, true, _.extend(params, opts));
if (!url) {
return unknownResourceError(resource, opts);
}
var cumulativeBytes = 0; var cumulativeBytes = 0;
return $ws({ return $ws({
url: self._urlForResource(resource, name, context, true, _.extend(params, opts)), url: url,
auth: {}, auth: {},
onopen: function(evt) { onopen: function(evt) {
_.each(openQueue, function(fn) { _.each(openQueue, function(fn) {
...@@ -4166,7 +4208,7 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -4166,7 +4208,7 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
opts = opts || {}; opts = opts || {};
var key = this._uniqueKey(resource, name, context, opts); var key = this._uniqueKey(resource, name, context, opts);
var wrapperCallback; var wrapperCallback;
if (callback) { if (key && callback) {
// If we were given a callback, add it // If we were given a callback, add it
this._watchObjectCallbacks(key).add(callback); this._watchObjectCallbacks(key).add(callback);
var self = this; var self = this;
...@@ -4431,17 +4473,26 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -4431,17 +4473,26 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
// bool. Both websocket & http operations should respond with the same data from cache if key matches // bool. Both websocket & http operations should respond with the same data from cache if key matches
// so the unique key will always include http:// // so the unique key will always include http://
DataService.prototype._uniqueKey = function(resource, name, context, opts) { DataService.prototype._uniqueKey = function(resource, name, context, opts) {
var key;
var ns = context && context.namespace || var ns = context && context.namespace ||
_.get(context, 'project.metadata.name') || _.get(context, 'project.metadata.name') ||
context.projectName; context.projectName;
var params = _.get(opts, 'http.params'); var params = _.get(opts, 'http.params');
var url = this._urlForResource(resource, name, context, null, angular.extend({}, {}, {namespace: ns})).toString() + paramsForKey(params || {}); var url = this._urlForResource(resource, name, context, null, angular.extend({}, {}, {namespace: ns}));
if (url) {
key = url.toString();
} else {
// Fall back to the ResourceGroupVersion string, "resource/group/version", for resources that weren't
// found during discovery.
key = resource || '<unknown>';
}
key = key + paramsForKey(params || {});
if (_.get(opts, 'partialObjectMetadataList')) { if (_.get(opts, 'partialObjectMetadataList')) {
// Make sure partial objects get a different cache key. // Make sure partial objects get a different cache key.
return url + '#' + ACCEPT_PARTIAL_OBJECT_METADATA_LIST; return key + '#' + ACCEPT_PARTIAL_OBJECT_METADATA_LIST;
} }
return url; return key;
}; };
...@@ -4457,14 +4508,20 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -4457,14 +4508,20 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
headers.Accept = ACCEPT_PARTIAL_OBJECT_METADATA_LIST; headers.Accept = ACCEPT_PARTIAL_OBJECT_METADATA_LIST;
} }
var url;
var self = this; var self = this;
if (context.projectPromise && !resource.equals("projects")) { if (context.projectPromise && !resource.equals("projects")) {
context.projectPromise.done(function(project) { context.projectPromise.done(function(project) {
url = self._urlForResource(resource, null, context, false, _.assign({}, params, {namespace: project.metadata.name}))
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'GET', method: 'GET',
auth: {}, auth: {},
headers: headers, headers: headers,
url: self._urlForResource(resource, null, context, false, _.assign({}, params, {namespace: project.metadata.name})) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
self._listOpComplete(key, resource, context, opts, data); self._listOpComplete(key, resource, context, opts, data);
...@@ -4489,11 +4546,16 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -4489,11 +4546,16 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
}); });
} }
else { else {
url = this._urlForResource(resource, null, context, false, params);
if (!url) {
return unknownResourceError(resource, opts);
}
$http({ $http({
method: 'GET', method: 'GET',
auth: {}, auth: {},
headers: headers, headers: headers,
url: this._urlForResource(resource, null, context, false, params), url: url
}).success(function(data, status, headerFunc, config, statusText) { }).success(function(data, status, headerFunc, config, statusText) {
self._listOpComplete(key, resource, context, opts, data); self._listOpComplete(key, resource, context, opts, data);
}).error(function(data, status, headers, config) { }).error(function(data, status, headers, config) {
......
...@@ -1579,7 +1579,7 @@ t._websocketEventsMap = {}; ...@@ -1579,7 +1579,7 @@ t._websocketEventsMap = {};
}); });
} }
function g(e) { function g(e) {
return e.length >= y && Date.now() - e[0].time < 3e4; return e.length >= S && Date.now() - e[0].time < 3e4;
} }
function h(e) { function h(e) {
if (e.length < 5) return !1; if (e.length < 5) return !1;
...@@ -1617,6 +1617,13 @@ r.$emit("NotificationsService.addNotification", e), m = []; ...@@ -1617,6 +1617,13 @@ r.$emit("NotificationsService.addNotification", e), m = [];
maxWait: 1e3 maxWait: 1e3
}), b = function(e, t) { }), b = function(e, t) {
t && (e += " (status " + t + ")"), m.push(e), v(); t && (e += " (status " + t + ")"), m.push(e), v();
}, y = function(e, t) {
var n;
return n = e ? "Unknown resource: " + e.toString() : "Internal error: API resource not specified.", _.get(t, "errorNotification", !0) && b(n), o.reject({
data: {
message: n
}
});
}; };
f.prototype.list = function(e, t, n, r) { f.prototype.list = function(e, t, n, r) {
e = a.toResourceGroupVersion(e); e = a.toResourceGroupVersion(e);
...@@ -1633,12 +1640,14 @@ l = { ...@@ -1633,12 +1640,14 @@ l = {
"Content-Type": "application/json" "Content-Type": "application/json"
}; };
return _.has(i, "gracePeriodSeconds") && (u.gracePeriodSeconds = i.gracePeriodSeconds), this._getNamespace(e, r, i).then(function(o) { return _.has(i, "gracePeriodSeconds") && (u.gracePeriodSeconds = i.gracePeriodSeconds), this._getNamespace(e, r, i).then(function(o) {
var a = c._urlForResource(e, n, r, !1, o);
if (!a) return y(e, i);
t(angular.extend({ t(angular.extend({
method: "DELETE", method: "DELETE",
auth: {}, auth: {},
data: u, data: u,
headers: l, headers: l,
url: c._urlForResource(e, n, r, !1, o) url: a
}, i.http || {})).success(function(e, t, n, r, o) { }, i.http || {})).success(function(e, t, n, r, o) {
s.resolve(e); s.resolve(e);
}).error(function(e, t, n, r) { }).error(function(e, t, n, r) {
...@@ -1654,11 +1663,13 @@ config: r ...@@ -1654,11 +1663,13 @@ config: r
e = a.deriveTargetResource(e, r), s = s || {}; e = a.deriveTargetResource(e, r), s = s || {};
var c = o.defer(), l = this; var c = o.defer(), l = this;
return this._getNamespace(e, i, s).then(function(o) { return this._getNamespace(e, i, s).then(function(o) {
var a = l._urlForResource(e, n, i, !1, o);
if (!a) return y(e, s);
t(angular.extend({ t(angular.extend({
method: "PUT", method: "PUT",
auth: {}, auth: {},
data: r, data: r,
url: l._urlForResource(e, n, i, !1, o) url: a
}, s.http || {})).success(function(e, t, n, r, o) { }, s.http || {})).success(function(e, t, n, r, o) {
c.resolve(e); c.resolve(e);
}).error(function(e, t, n, r) { }).error(function(e, t, n, r) {
...@@ -1674,11 +1685,13 @@ config: r ...@@ -1674,11 +1685,13 @@ config: r
e = a.deriveTargetResource(e, r), s = s || {}; e = a.deriveTargetResource(e, r), s = s || {};
var c = o.defer(), l = this; var c = o.defer(), l = this;
return this._getNamespace(e, i, s).then(function(o) { return this._getNamespace(e, i, s).then(function(o) {
var a = l._urlForResource(e, n, i, !1, o);
if (!a) return y(e, s);
t(angular.extend({ t(angular.extend({
method: "POST", method: "POST",
auth: {}, auth: {},
data: r, data: r,
url: l._urlForResource(e, n, i, !1, o) url: a
}, s.http || {})).success(function(e, t, n, r, o) { }, s.http || {})).success(function(e, t, n, r, o) {
c.resolve(e); c.resolve(e);
}).error(function(e, t, n, r) { }).error(function(e, t, n, r) {
...@@ -1749,10 +1762,12 @@ l.resolve(u.by("metadata.name")[n]); ...@@ -1749,10 +1762,12 @@ l.resolve(u.by("metadata.name")[n]);
}, 0); else { }, 0); else {
var d = this; var d = this;
this._getNamespace(e, r, i).then(function(o) { this._getNamespace(e, r, i).then(function(o) {
var a = d._urlForResource(e, n, r, !1, o);
if (!a) return y(e, i);
t(angular.extend({ t(angular.extend({
method: "GET", method: "GET",
auth: {}, auth: {},
url: d._urlForResource(e, n, r, !1, o) url: a
}, i.http || {})).success(function(t, n, r, o, i) { }, i.http || {})).success(function(t, n, r, o, i) {
d._isImmutable(e) && (u ? u.update(t, "ADDED") : d._immutableData(s, [ t ])), l.resolve(t); d._isImmutable(e) && (u ? u.update(t, "ADDED") : d._immutableData(s, [ t ])), l.resolve(t);
}).error(function(t, r, o, a) { }).error(function(t, r, o, a) {
...@@ -1771,9 +1786,11 @@ var c = this; ...@@ -1771,9 +1786,11 @@ var c = this;
e = a.toResourceGroupVersion(e); e = a.toResourceGroupVersion(e);
var d, p = i ? "binary.k8s.io" : "base64.binary.k8s.io", f = {}, g = {}, h = {}, m = {}, v = function() { var d, p = i ? "binary.k8s.io" : "base64.binary.k8s.io", f = {}, g = {}, h = {}, m = {}, v = function() {
return c._getNamespace(e, r, {}).then(function(a) { return c._getNamespace(e, r, {}).then(function(a) {
var d = 0; var d = c._urlForResource(e, t, r, !0, _.extend(a, o));
if (!d) return y(e, o);
var v = 0;
return n({ return n({
url: c._urlForResource(e, t, r, !0, _.extend(a, o)), url: d,
auth: {}, auth: {},
onopen: function(e) { onopen: function(e) {
_.each(f, function(t) { _.each(f, function(t) {
...@@ -1783,8 +1800,8 @@ t(e); ...@@ -1783,8 +1800,8 @@ t(e);
onmessage: function(e) { onmessage: function(e) {
if (_.isString(e.data)) { if (_.isString(e.data)) {
var t; var t;
i || (t = l.decode(u.pad(e.data)), d += t.length), _.each(g, function(n) { i || (t = l.decode(u.pad(e.data)), v += t.length), _.each(g, function(n) {
i ? n(e.data) : n(t, e.data, d); i ? n(e.data) : n(t, e.data, v);
}); });
} else s.log("log stream response is not a string", e.data); } else s.log("log stream response is not a string", e.data);
}, },
...@@ -1870,7 +1887,7 @@ opts: r ...@@ -1870,7 +1887,7 @@ opts: r
}, f.prototype.watchObject = function(e, t, n, r, o) { }, f.prototype.watchObject = function(e, t, n, r, o) {
e = a.toResourceGroupVersion(e), o = o || {}; e = a.toResourceGroupVersion(e), o = o || {};
var i, s = this._uniqueKey(e, t, n, o); var i, s = this._uniqueKey(e, t, n, o);
if (r) { if (s && r) {
this._watchObjectCallbacks(s).add(r); this._watchObjectCallbacks(s).add(r);
var c = this; var c = this;
i = function(e, n, r) { i = function(e, n, r) {
...@@ -1929,72 +1946,76 @@ this._watchPollTimeoutsMap[e] = t; ...@@ -1929,72 +1946,76 @@ this._watchPollTimeoutsMap[e] = t;
if (!t) return this._watchWebsocketsMap[e]; if (!t) return this._watchWebsocketsMap[e];
this._watchWebsocketsMap[e] = t; this._watchWebsocketsMap[e] = t;
}; };
var y = 10; var S = 10;
f.prototype._addWebsocketEvent = function(e, t) { f.prototype._addWebsocketEvent = function(e, t) {
var n = this._websocketEventsMap[e]; var n = this._websocketEventsMap[e];
for (n || (n = this._websocketEventsMap[e] = []), n.push({ for (n || (n = this._websocketEventsMap[e] = []), n.push({
type: t, type: t,
time: Date.now() time: Date.now()
}); n.length > y; ) n.shift(); }); n.length > S; ) n.shift();
}, f.prototype._isTooManyWebsocketRetries = function(e) { }, f.prototype._isTooManyWebsocketRetries = function(e) {
var t = this._websocketEventsMap[e]; var t = this._websocketEventsMap[e];
return !!t && (g(t) ? (s.log("Too many websocket open or close events for resource/context in a short period", e, t), !0) : !!h(t) && (s.log("Too many consecutive websocket close events for resource/context", e, t), !0)); return !!t && (g(t) ? (s.log("Too many websocket open or close events for resource/context in a short period", e, t), !0) : !!h(t) && (s.log("Too many consecutive websocket close events for resource/context", e, t), !0));
}; };
var S = function(e) { var w = function(e) {
var t = _.keysIn(_.pick(e, [ "fieldSelector", "labelSelector" ])).sort(); var t = _.keysIn(_.pick(e, [ "fieldSelector", "labelSelector" ])).sort();
return _.reduce(t, function(n, r, o) { return _.reduce(t, function(n, r, o) {
return n + r + "=" + encodeURIComponent(e[r]) + (o < t.length - 1 ? "&" : ""); return n + r + "=" + encodeURIComponent(e[r]) + (o < t.length - 1 ? "&" : "");
}, "?"); }, "?");
}; };
f.prototype._uniqueKey = function(e, t, n, r) { f.prototype._uniqueKey = function(e, t, n, r) {
var o = n && n.namespace || _.get(n, "project.metadata.name") || n.projectName, i = _.get(r, "http.params"), a = this._urlForResource(e, t, n, null, angular.extend({}, {}, { var o, i = n && n.namespace || _.get(n, "project.metadata.name") || n.projectName, a = _.get(r, "http.params"), s = this._urlForResource(e, t, n, null, angular.extend({}, {}, {
namespace: o namespace: i
})).toString() + S(i || {}); }));
return _.get(r, "partialObjectMetadataList") ? a + "#application/json;as=PartialObjectMetadataList;v=v1alpha1;g=meta.k8s.io" : a; return o = s ? s.toString() : e || "<unknown>", o += w(a || {}), _.get(r, "partialObjectMetadataList") ? o + "#application/json;as=PartialObjectMetadataList;v=v1alpha1;g=meta.k8s.io" : o;
}, f.prototype._startListOp = function(e, n, r) { }, f.prototype._startListOp = function(e, n, r) {
r = r || {}; r = r || {};
var o = _.get(r, "http.params") || {}, i = this._uniqueKey(e, null, n, r); var o = _.get(r, "http.params") || {}, i = this._uniqueKey(e, null, n, r);
this._listInFlight(i, !0); this._listInFlight(i, !0);
var a = {}; var a = {};
r.partialObjectMetadataList && (a.Accept = "application/json;as=PartialObjectMetadataList;v=v1alpha1;g=meta.k8s.io"); r.partialObjectMetadataList && (a.Accept = "application/json;as=PartialObjectMetadataList;v=v1alpha1;g=meta.k8s.io");
var s = this; var s, c = this;
n.projectPromise && !e.equals("projects") ? n.projectPromise.done(function(c) { if (n.projectPromise && !e.equals("projects")) n.projectPromise.done(function(l) {
if (!(s = c._urlForResource(e, null, n, !1, _.assign({}, o, {
namespace: l.metadata.name
})))) return y(e, r);
t(angular.extend({ t(angular.extend({
method: "GET", method: "GET",
auth: {}, auth: {},
headers: a, headers: a,
url: s._urlForResource(e, null, n, !1, _.assign({}, o, { url: s
namespace: c.metadata.name }, r.http || {})).success(function(t, o, a, s, l) {
})) c._listOpComplete(i, e, n, r, t);
}, r.http || {})).success(function(t, o, a, c, l) {
s._listOpComplete(i, e, n, r, t);
}).error(function(t, n, o, a) { }).error(function(t, n, o, a) {
s._listInFlight(i, !1); c._listInFlight(i, !1);
var c = s._listDeferred(i); var s = c._listDeferred(i);
delete s._listDeferredMap[i], c.reject({ delete c._listDeferredMap[i], s.reject({
data: t, data: t,
status: n, status: n,
headers: o, headers: o,
config: a config: a
}), _.get(r, "errorNotification", !0) && b("Failed to list " + e, n); }), _.get(r, "errorNotification", !0) && b("Failed to list " + e, n);
}); });
}) : t({ }); else {
if (!(s = this._urlForResource(e, null, n, !1, o))) return y(e, r);
t({
method: "GET", method: "GET",
auth: {}, auth: {},
headers: a, headers: a,
url: this._urlForResource(e, null, n, !1, o) url: s
}).success(function(t, o, a, c, l) { }).success(function(t, o, a, s, l) {
s._listOpComplete(i, e, n, r, t); c._listOpComplete(i, e, n, r, t);
}).error(function(t, n, o, a) { }).error(function(t, n, o, a) {
s._listInFlight(i, !1); c._listInFlight(i, !1);
var c = s._listDeferred(i); var s = c._listDeferred(i);
delete s._listDeferredMap[i], c.reject({ delete c._listDeferredMap[i], s.reject({
data: t, data: t,
status: n, status: n,
headers: o, headers: o,
config: a config: a
}), _.get(r, "errorNotification", !0) && b("Failed to list " + e, n); }), _.get(r, "errorNotification", !0) && b("Failed to list " + e, n);
}); });
}
}, f.prototype._listOpComplete = function(e, t, n, r, o) { }, f.prototype._listOpComplete = function(e, t, n, r, o) {
o.items || console.warn("List request for " + t + " returned a null items array. This is an invalid API response."); o.items || console.warn("List request for " + t + " returned a null items array. This is an invalid API response.");
var i = o.items || []; var i = o.items || [];
...@@ -2129,11 +2150,11 @@ return this._getAPIServerVersion("/version/openshift"); ...@@ -2129,11 +2150,11 @@ return this._getAPIServerVersion("/version/openshift");
}, f.prototype.createData = function(e) { }, f.prototype.createData = function(e) {
return new d(e); return new d(e);
}; };
var w = { var k = {
imagestreamimages: !0 imagestreamimages: !0
}; };
return f.prototype._isImmutable = function(e) { return f.prototype._isImmutable = function(e) {
return !!w[e.resource]; return !!k[e.resource];
}, f.prototype._hasImmutable = function(e, t, n) { }, f.prototype._hasImmutable = function(e, t, n) {
return this._isImmutable(e) && t && t.by("metadata.name")[n]; return this._isImmutable(e) && t && t.by("metadata.name")[n];
}, f.prototype._getNamespace = function(e, t, n) { }, f.prototype._getNamespace = function(e, t, n) {
......
...@@ -125,6 +125,27 @@ angular.module('openshiftCommonServices') ...@@ -125,6 +125,27 @@ angular.module('openshiftCommonServices')
addQueuedNotifications(); addQueuedNotifications();
}; };
var unknownResourceError = function(resource, opts) {
var message;
if (!resource) {
message = 'Internal error: API resource not specified.';
} else {
// APIService ResourceGroupVersion objects implement toString()
message = "Unknown resource: " + resource.toString();
}
if (_.get(opts, 'errorNotification', true)) {
// No HTTP status since no request was made.
showRequestError(message);
}
return $q.reject({
data: {
message: message
}
});
}
function DataService() { function DataService() {
this._listDeferredMap = {}; this._listDeferredMap = {};
this._watchCallbacksMap = {}; this._watchCallbacksMap = {};
...@@ -217,12 +238,16 @@ angular.module('openshiftCommonServices') ...@@ -217,12 +238,16 @@ angular.module('openshiftCommonServices')
data.gracePeriodSeconds = opts.gracePeriodSeconds; data.gracePeriodSeconds = opts.gracePeriodSeconds;
} }
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns)
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'DELETE', method: 'DELETE',
auth: {}, auth: {},
data: data, data: data,
headers: headers, headers: headers,
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data); deferred.resolve(data);
...@@ -252,11 +277,15 @@ angular.module('openshiftCommonServices') ...@@ -252,11 +277,15 @@ angular.module('openshiftCommonServices')
var deferred = $q.defer(); var deferred = $q.defer();
var self = this; var self = this;
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns);
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'PUT', method: 'PUT',
auth: {}, auth: {},
data: object, data: object,
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data); deferred.resolve(data);
...@@ -321,11 +350,15 @@ angular.module('openshiftCommonServices') ...@@ -321,11 +350,15 @@ angular.module('openshiftCommonServices')
var deferred = $q.defer(); var deferred = $q.defer();
var self = this; var self = this;
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns);
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'POST', method: 'POST',
auth: {}, auth: {},
data: object, data: object,
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data); deferred.resolve(data);
...@@ -444,10 +477,14 @@ angular.module('openshiftCommonServices') ...@@ -444,10 +477,14 @@ angular.module('openshiftCommonServices')
else { else {
var self = this; var self = this;
this._getNamespace(resource, context, opts).then(function(ns){ this._getNamespace(resource, context, opts).then(function(ns){
var url = self._urlForResource(resource, name, context, false, ns);
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'GET', method: 'GET',
auth: {}, auth: {},
url: self._urlForResource(resource, name, context, false, ns) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
if (self._isImmutable(resource)) { if (self._isImmutable(resource)) {
...@@ -492,9 +529,14 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -492,9 +529,14 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
var makeStream = function() { var makeStream = function() {
return self._getNamespace(resource, context, {}) return self._getNamespace(resource, context, {})
.then(function(params) { .then(function(params) {
var url = self._urlForResource(resource, name, context, true, _.extend(params, opts));
if (!url) {
return unknownResourceError(resource, opts);
}
var cumulativeBytes = 0; var cumulativeBytes = 0;
return $ws({ return $ws({
url: self._urlForResource(resource, name, context, true, _.extend(params, opts)), url: url,
auth: {}, auth: {},
onopen: function(evt) { onopen: function(evt) {
_.each(openQueue, function(fn) { _.each(openQueue, function(fn) {
...@@ -704,7 +746,7 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -704,7 +746,7 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
opts = opts || {}; opts = opts || {};
var key = this._uniqueKey(resource, name, context, opts); var key = this._uniqueKey(resource, name, context, opts);
var wrapperCallback; var wrapperCallback;
if (callback) { if (key && callback) {
// If we were given a callback, add it // If we were given a callback, add it
this._watchObjectCallbacks(key).add(callback); this._watchObjectCallbacks(key).add(callback);
var self = this; var self = this;
...@@ -969,17 +1011,26 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -969,17 +1011,26 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
// bool. Both websocket & http operations should respond with the same data from cache if key matches // bool. Both websocket & http operations should respond with the same data from cache if key matches
// so the unique key will always include http:// // so the unique key will always include http://
DataService.prototype._uniqueKey = function(resource, name, context, opts) { DataService.prototype._uniqueKey = function(resource, name, context, opts) {
var key;
var ns = context && context.namespace || var ns = context && context.namespace ||
_.get(context, 'project.metadata.name') || _.get(context, 'project.metadata.name') ||
context.projectName; context.projectName;
var params = _.get(opts, 'http.params'); var params = _.get(opts, 'http.params');
var url = this._urlForResource(resource, name, context, null, angular.extend({}, {}, {namespace: ns})).toString() + paramsForKey(params || {}); var url = this._urlForResource(resource, name, context, null, angular.extend({}, {}, {namespace: ns}));
if (url) {
key = url.toString();
} else {
// Fall back to the ResourceGroupVersion string, "resource/group/version", for resources that weren't
// found during discovery.
key = resource || '<unknown>';
}
key = key + paramsForKey(params || {});
if (_.get(opts, 'partialObjectMetadataList')) { if (_.get(opts, 'partialObjectMetadataList')) {
// Make sure partial objects get a different cache key. // Make sure partial objects get a different cache key.
return url + '#' + ACCEPT_PARTIAL_OBJECT_METADATA_LIST; return key + '#' + ACCEPT_PARTIAL_OBJECT_METADATA_LIST;
} }
return url; return key;
}; };
...@@ -995,14 +1046,20 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -995,14 +1046,20 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
headers.Accept = ACCEPT_PARTIAL_OBJECT_METADATA_LIST; headers.Accept = ACCEPT_PARTIAL_OBJECT_METADATA_LIST;
} }
var url;
var self = this; var self = this;
if (context.projectPromise && !resource.equals("projects")) { if (context.projectPromise && !resource.equals("projects")) {
context.projectPromise.done(function(project) { context.projectPromise.done(function(project) {
url = self._urlForResource(resource, null, context, false, _.assign({}, params, {namespace: project.metadata.name}))
if (!url) {
return unknownResourceError(resource, opts);
}
$http(angular.extend({ $http(angular.extend({
method: 'GET', method: 'GET',
auth: {}, auth: {},
headers: headers, headers: headers,
url: self._urlForResource(resource, null, context, false, _.assign({}, params, {namespace: project.metadata.name})) url: url
}, opts.http || {})) }, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) { .success(function(data, status, headerFunc, config, statusText) {
self._listOpComplete(key, resource, context, opts, data); self._listOpComplete(key, resource, context, opts, data);
...@@ -1027,11 +1084,16 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR ...@@ -1027,11 +1084,16 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
}); });
} }
else { else {
url = this._urlForResource(resource, null, context, false, params);
if (!url) {
return unknownResourceError(resource, opts);
}
$http({ $http({
method: 'GET', method: 'GET',
auth: {}, auth: {},
headers: headers, headers: headers,
url: this._urlForResource(resource, null, context, false, params), url: url
}).success(function(data, status, headerFunc, config, statusText) { }).success(function(data, status, headerFunc, config, statusText) {
self._listOpComplete(key, resource, context, opts, data); self._listOpComplete(key, resource, context, opts, data);
}).error(function(data, status, headers, config) { }).error(function(data, status, headers, config) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment