8b5b2116ec
Without this, visiting any job detail page on Nomad OSS would crash with an error like this: Error: Ember Data Request GET /v1/recommendations?job=ping%F0%9F%A5%B3&namespace=default returned a 404 Payload (text/xml) The problem was twofold. 1. The recommendation ability didn’t include anything about checking whether the feature was present. This adds a request to /v1/operator/license on application load to determine which features are present and store them in the system service. The ability now looks for 'Dynamic Application Sizing' in that feature list. 2. Second, I didn’t check permissions at all in the job-fetching or job detail templates.
104 lines
3.4 KiB
JavaScript
104 lines
3.4 KiB
JavaScript
import { Ability } from 'ember-can';
|
|
import { inject as service } from '@ember/service';
|
|
import { computed, get } from '@ember/object';
|
|
import { equal, not } from '@ember/object/computed';
|
|
import classic from 'ember-classic-decorator';
|
|
|
|
@classic
|
|
export default class Abstract extends Ability {
|
|
@service system;
|
|
@service token;
|
|
|
|
@not('token.aclEnabled') bypassAuthorization;
|
|
@equal('token.selfToken.type', 'management') selfTokenIsManagement;
|
|
|
|
@computed('system.activeNamespace.name')
|
|
get activeNamespace() {
|
|
return this.get('system.activeNamespace.name') || 'default';
|
|
}
|
|
|
|
@computed('activeNamespace', 'token.selfTokenPolicies.[]')
|
|
get rulesForActiveNamespace() {
|
|
let activeNamespace = this.activeNamespace;
|
|
|
|
return (this.get('token.selfTokenPolicies') || []).toArray().reduce((rules, policy) => {
|
|
let policyNamespaces = get(policy, 'rulesJSON.Namespaces') || [];
|
|
|
|
let matchingNamespace = this._findMatchingNamespace(policyNamespaces, activeNamespace);
|
|
|
|
if (matchingNamespace) {
|
|
rules.push(policyNamespaces.find(namespace => namespace.Name === matchingNamespace));
|
|
}
|
|
|
|
return rules;
|
|
}, []);
|
|
}
|
|
|
|
@computed('token.selfTokenPolicies.[]')
|
|
get capabilitiesForAllNamespaces() {
|
|
return (this.get('token.selfTokenPolicies') || [])
|
|
.toArray()
|
|
.reduce((allCapabilities, policy) => {
|
|
(get(policy, 'rulesJSON.Namespaces') || []).forEach(({ Capabilities }) => {
|
|
allCapabilities = allCapabilities.concat(Capabilities);
|
|
});
|
|
return allCapabilities;
|
|
}, []);
|
|
}
|
|
|
|
activeNamespaceIncludesCapability(capability) {
|
|
return this.rulesForActiveNamespace.some(rules => {
|
|
let capabilities = get(rules, 'Capabilities') || [];
|
|
return capabilities.includes(capability);
|
|
});
|
|
}
|
|
|
|
@computed('system.features.[]')
|
|
get features() {
|
|
return this.system.features;
|
|
}
|
|
|
|
featureIsPresent(featureName) {
|
|
return this.features.includes(featureName);
|
|
}
|
|
|
|
// Chooses the closest namespace as described at the bottom here:
|
|
// https://learn.hashicorp.com/tutorials/nomad/access-control-policies?in=nomad/access-control#namespace-rules
|
|
_findMatchingNamespace(policyNamespaces, activeNamespace) {
|
|
let namespaceNames = policyNamespaces.mapBy('Name');
|
|
|
|
if (namespaceNames.includes(activeNamespace)) {
|
|
return activeNamespace;
|
|
}
|
|
|
|
let globNamespaceNames = namespaceNames.filter(namespaceName => namespaceName.includes('*'));
|
|
|
|
let matchingNamespaceName = globNamespaceNames.reduce(
|
|
(mostMatching, namespaceName) => {
|
|
// Convert * wildcards to .* for regex matching
|
|
let namespaceNameRegExp = new RegExp(namespaceName.replace(/\*/g, '.*'));
|
|
let characterDifference = activeNamespace.length - namespaceName.length;
|
|
|
|
if (
|
|
characterDifference < mostMatching.mostMatchingCharacterDifference &&
|
|
activeNamespace.match(namespaceNameRegExp)
|
|
) {
|
|
return {
|
|
mostMatchingNamespaceName: namespaceName,
|
|
mostMatchingCharacterDifference: characterDifference,
|
|
};
|
|
} else {
|
|
return mostMatching;
|
|
}
|
|
},
|
|
{ mostMatchingNamespaceName: null, mostMatchingCharacterDifference: Number.MAX_SAFE_INTEGER }
|
|
).mostMatchingNamespaceName;
|
|
|
|
if (matchingNamespaceName) {
|
|
return matchingNamespaceName;
|
|
} else if (namespaceNames.includes('default')) {
|
|
return 'default';
|
|
}
|
|
}
|
|
}
|