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  });