Unverified Commit f6077444 by Sam Padgett Committed by GitHub

Merge pull request #304 from spadgett/unknown-resource

Avoid runtime errors when requested resource doesn't exist
parents 5ea67be6 04fde4bd
...@@ -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