ui: Metrics - Provide a fetch-like http client that automatically adds the current ACL token (#9094)

* Remove local httpGet and shim one in from options

* Add custom httpGet to pass through to provider

* Make a fetch wrapper that adds your token

* Pass the fetch like fetchWithToken wrapper through to the provider

* Fix up httpGet to encode query params again and use fetch-like
This commit is contained in:
John Cowen 2020-11-04 09:33:37 +00:00 committed by GitHub
parent 1a5d4cfe43
commit 0f6c0a5c13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 38 deletions

View File

@ -152,6 +152,17 @@ export default Service.extend({
params.headers[CONTENT_TYPE] = 'application/json; charset=utf-8';
return params;
},
fetchWithToken: function(path, params) {
return this.settings.findBySlug('token').then(token => {
return fetch(`${path}`, {
...params,
headers: {
'X-Consul-Token': typeof token.SecretID === 'undefined' ? '' : token.SecretID,
...params.headers,
},
});
});
},
request: function(cb) {
const client = this;
return cb(function(strs, ...values) {

View File

@ -11,6 +11,7 @@ const meta = {
export default RepositoryService.extend({
cfg: service('ui-config'),
client: service('client/http'),
error: null,
init: function() {
@ -20,6 +21,9 @@ export default RepositoryService.extend({
// JSON options the user provided.
const opts = uiCfg.metrics_provider_options || {};
opts.metrics_proxy_enabled = uiCfg.metrics_proxy_enabled;
// Inject a convenience function for dialing through the metrics proxy.
opts.fetch = (path, params) =>
this.client.fetchWithToken(`/v1/internal/ui/metrics-proxy${path}`, params);
// Inject the base app URL
const provider = uiCfg.metrics_provider || 'prometheus';

View File

@ -11,8 +11,14 @@
* options.providerOptions contains any operator configured parameters
* specified in the Consul agent config that is serving the UI.
*
* Consul will provider a boolean options.metrics_proxy_enabled to indicate
* whether the agent has a metrics proxy configured.
* Consul will provide:
*
* 1. A boolean options.metrics_proxy_enabled to indicate whether the agent
* has a metrics proxy configured.
* 2. A fetch-like options.fetch which is a thin fetch wrapper that prefixes
* any url with the url of Consul's proxy endpoint and adds your current
* Consul ACL token to the request headers. Otherwise it functions like the
* browsers native fetch
*
* The provider should throw an Exception if the options are not valid for
* example because it requires a metrics proxy and one is not configured.
@ -24,6 +30,34 @@
}
},
// simple httpGet function that also encodes query parameters
// before passing the constructed url through to native fetch
// any errors should throw an error with a statusCode property
httpGet: function(url, queryParams, headers) {
if (queryParams) {
var separator = url.indexOf('?') !== -1 ? '&' : '?';
var qs = Object.keys(queryParams).
map(function(key) {
return encodeURIComponent(key) + "=" + encodeURIComponent(queryParams[key]);
}).
join("&");
url = url + separator + qs;
}
// fetch the url along with any headers
return this.options.fetch(url, {headers: headers || {}}).then(
function(response) {
if(response.ok) {
return response.json();
} else {
// throw a statusCode error if any errors are received
var e = new Error('HTTP Error: ' + response.statusText);
e.statusCode = response.status;
throw e;
}
}
);
},
/**
* serviceRecentSummarySeries should return time series for a recent time
* period summarizing the usage of the named service in the indicated
@ -656,42 +690,6 @@
return this.httpGet("/api/v1/query_range", params)
},
httpGet: function(path, params) {
var xhr = new XMLHttpRequest();
var self = this
return new Promise(function(resolve, reject){
xhr.onreadystatechange = function(){
if (xhr.readyState !== 4) return;
if (xhr.status == 200) {
// Attempt to parse response as JSON and return the object
var o = JSON.parse(xhr.responseText)
resolve(o)
}
const e = new Error(xhr.statusText);
e.statusCode = xhr.status;
reject(e);
}
var url = self.baseURL()+path;
if (params) {
var qs = Object.keys(params).
map(function(key){
return encodeURIComponent(key)+"="+encodeURIComponent(params[key])
}).
join("&")
url = url+"?"+qs
}
xhr.open("GET", url, true);
xhr.send();
});
},
baseURL: function() {
// TODO support configuring a direct Prometheus via
// metrics_provider_options_json.
return "/v1/internal/ui/metrics-proxy"
}
}
// Helper functions