github.com/hernad/nomad@v1.6.112/ui/tests/unit/abilities/job-test.js (about) 1 /** 2 * Copyright (c) HashiCorp, Inc. 3 * SPDX-License-Identifier: MPL-2.0 4 */ 5 6 /* eslint-disable ember/avoid-leaking-state-in-ember-objects */ 7 import { module, test } from 'qunit'; 8 import { setupTest } from 'ember-qunit'; 9 import Service from '@ember/service'; 10 import setupAbility from 'nomad-ui/tests/helpers/setup-ability'; 11 12 module('Unit | Ability | job', function (hooks) { 13 setupTest(hooks); 14 setupAbility('job')(hooks); 15 16 test('it permits job run when ACLs are disabled', function (assert) { 17 const mockToken = Service.extend({ 18 aclEnabled: false, 19 }); 20 21 this.owner.register('service:token', mockToken); 22 23 assert.ok(this.ability.canRun); 24 }); 25 26 test('it permits job run for management tokens', function (assert) { 27 const mockToken = Service.extend({ 28 aclEnabled: true, 29 selfToken: { type: 'management' }, 30 }); 31 32 this.owner.register('service:token', mockToken); 33 34 assert.ok(this.ability.canRun); 35 }); 36 37 test('it permits job run for client tokens with a policy that has namespace submit-job', function (assert) { 38 const mockSystem = Service.extend({ 39 aclEnabled: true, 40 }); 41 42 const mockToken = Service.extend({ 43 aclEnabled: true, 44 selfToken: { type: 'client' }, 45 selfTokenPolicies: [ 46 { 47 rulesJSON: { 48 Namespaces: [ 49 { 50 Name: 'aNamespace', 51 Capabilities: ['submit-job'], 52 }, 53 ], 54 }, 55 }, 56 ], 57 }); 58 59 this.owner.register('service:system', mockSystem); 60 this.owner.register('service:token', mockToken); 61 62 assert.ok(this.can.can('run job', null, { namespace: 'aNamespace' })); 63 }); 64 65 test('it permits job run for client tokens with a policy that has default namespace submit-job and no capabilities for active namespace', function (assert) { 66 const mockSystem = Service.extend({ 67 aclEnabled: true, 68 }); 69 70 const mockToken = Service.extend({ 71 aclEnabled: true, 72 selfToken: { type: 'client' }, 73 selfTokenPolicies: [ 74 { 75 rulesJSON: { 76 Namespaces: [ 77 { 78 Name: 'aNamespace', 79 Capabilities: [], 80 }, 81 { 82 Name: 'default', 83 Capabilities: ['submit-job'], 84 }, 85 ], 86 }, 87 }, 88 ], 89 }); 90 91 this.owner.register('service:system', mockSystem); 92 this.owner.register('service:token', mockToken); 93 94 assert.ok(this.can.can('run job', null, { namespace: 'anotherNamespace' })); 95 }); 96 97 test('it blocks job run for client tokens with a policy that has no submit-job capability', function (assert) { 98 const mockSystem = Service.extend({ 99 aclEnabled: true, 100 }); 101 102 const mockToken = Service.extend({ 103 aclEnabled: true, 104 selfToken: { type: 'client' }, 105 selfTokenPolicies: [ 106 { 107 rulesJSON: { 108 Namespaces: [ 109 { 110 Name: 'aNamespace', 111 Capabilities: ['list-jobs'], 112 }, 113 ], 114 }, 115 }, 116 ], 117 }); 118 119 this.owner.register('service:system', mockSystem); 120 this.owner.register('service:token', mockToken); 121 122 assert.ok(this.can.cannot('run job', null, { namespace: 'aNamespace' })); 123 }); 124 125 test('job scale requires a client token with the submit-job or scale-job capability', function (assert) { 126 const makePolicies = (namespace, ...capabilities) => [ 127 { 128 rulesJSON: { 129 Namespaces: [ 130 { 131 Name: namespace, 132 Capabilities: capabilities, 133 }, 134 ], 135 }, 136 }, 137 ]; 138 139 const mockSystem = Service.extend({ 140 aclEnabled: true, 141 }); 142 143 const mockToken = Service.extend({ 144 aclEnabled: true, 145 selfToken: { type: 'client' }, 146 selfTokenPolicies: makePolicies('aNamespace'), 147 }); 148 149 this.owner.register('service:system', mockSystem); 150 this.owner.register('service:token', mockToken); 151 const tokenService = this.owner.lookup('service:token'); 152 153 assert.ok(this.can.cannot('scale job', null, { namespace: 'aNamespace' })); 154 155 tokenService.set( 156 'selfTokenPolicies', 157 makePolicies('aNamespace', 'scale-job') 158 ); 159 assert.ok(this.can.can('scale job', null, { namespace: 'aNamespace' })); 160 161 tokenService.set( 162 'selfTokenPolicies', 163 makePolicies('aNamespace', 'submit-job') 164 ); 165 assert.ok(this.can.can('scale job', null, { namespace: 'aNamespace' })); 166 167 tokenService.set( 168 'selfTokenPolicies', 169 makePolicies('bNamespace', 'scale-job') 170 ); 171 assert.ok(this.can.cannot('scale job', null, { namespace: 'aNamespace' })); 172 }); 173 174 test('job dispatch requires a client token with the dispatch-job capability', function (assert) { 175 const makePolicies = (namespace, ...capabilities) => [ 176 { 177 rulesJSON: { 178 Namespaces: [ 179 { 180 Name: namespace, 181 Capabilities: capabilities, 182 }, 183 ], 184 }, 185 }, 186 ]; 187 188 const mockSystem = Service.extend({ 189 aclEnabled: true, 190 }); 191 192 const mockToken = Service.extend({ 193 aclEnabled: true, 194 selfToken: { type: 'client' }, 195 selfTokenPolicies: makePolicies('aNamespace'), 196 }); 197 198 this.owner.register('service:system', mockSystem); 199 this.owner.register('service:token', mockToken); 200 const tokenService = this.owner.lookup('service:token'); 201 202 assert.ok( 203 this.can.cannot('dispatch job', null, { namespace: 'aNamespace' }) 204 ); 205 206 tokenService.set( 207 'selfTokenPolicies', 208 makePolicies('aNamespace', 'dispatch-job') 209 ); 210 assert.ok(this.can.can('dispatch job', null, { namespace: 'aNamespace' })); 211 }); 212 213 test('it handles globs in namespace names', function (assert) { 214 const mockSystem = Service.extend({ 215 aclEnabled: true, 216 }); 217 218 const mockToken = Service.extend({ 219 aclEnabled: true, 220 selfToken: { type: 'client' }, 221 selfTokenPolicies: [ 222 { 223 rulesJSON: { 224 Namespaces: [ 225 { 226 Name: 'production-*', 227 Capabilities: ['submit-job'], 228 }, 229 { 230 Name: 'production-api', 231 Capabilities: ['submit-job'], 232 }, 233 { 234 Name: 'production-web', 235 Capabilities: [], 236 }, 237 { 238 Name: '*-suffixed', 239 Capabilities: ['submit-job'], 240 }, 241 { 242 Name: '*-more-suffixed', 243 Capabilities: [], 244 }, 245 { 246 Name: '*-abc-*', 247 Capabilities: ['submit-job'], 248 }, 249 ], 250 }, 251 }, 252 ], 253 }); 254 255 this.owner.register('service:system', mockSystem); 256 this.owner.register('service:token', mockToken); 257 258 assert.ok( 259 this.can.can( 260 'run job', 261 null, 262 { namespace: 'production-web' }, 263 'The existence of a single namespace where a job can be run means that can run is enabled' 264 ) 265 ); 266 assert.ok(this.can.can('run job', null, { namespace: 'production-api' })); 267 assert.ok(this.can.can('run job', null, { namespace: 'production-other' })); 268 assert.ok( 269 this.can.can('run job', null, { namespace: 'something-suffixed' }) 270 ); 271 assert.ok( 272 this.can.can('run job', null, { namespace: '000-abc-999' }), 273 'expected to be able to match against more than one wildcard' 274 ); 275 }); 276 });