github.com/emate/nomad@v0.8.2-wo-binpacking/ui/mirage/config.js (about)

     1  import Ember from 'ember';
     2  import Response from 'ember-cli-mirage/response';
     3  import { HOSTS } from './common';
     4  import { logFrames, logEncode } from './data/logs';
     5  
     6  const { copy } = Ember;
     7  
     8  export function findLeader(schema) {
     9    const agent = schema.agents.first();
    10    return `${agent.address}:${agent.tags.port}`;
    11  }
    12  
    13  export default function() {
    14    this.timing = 0; // delay for each request, automatically set to 0 during testing
    15  
    16    this.namespace = 'v1';
    17    this.trackRequests = Ember.testing;
    18  
    19    const nomadIndices = {}; // used for tracking blocking queries
    20    const server = this;
    21    const withBlockingSupport = function(fn) {
    22      return function(schema, request) {
    23        // Get the original response
    24        let { url } = request;
    25        url = url.replace(/index=\d+[&;]?/, '');
    26        const response = fn.apply(this, arguments);
    27  
    28        // Get and increment the appropriate index
    29        nomadIndices[url] || (nomadIndices[url] = 2);
    30        const index = nomadIndices[url];
    31        nomadIndices[url]++;
    32  
    33        // Annotate the response with the index
    34        if (response instanceof Response) {
    35          response.headers['X-Nomad-Index'] = index;
    36          return response;
    37        }
    38        return new Response(200, { 'x-nomad-index': index }, response);
    39      };
    40    };
    41  
    42    this.get(
    43      '/jobs',
    44      withBlockingSupport(function({ jobs }, { queryParams }) {
    45        const json = this.serialize(jobs.all());
    46        const namespace = queryParams.namespace || 'default';
    47        return json
    48          .filter(
    49            job =>
    50              namespace === 'default'
    51                ? !job.NamespaceID || job.NamespaceID === namespace
    52                : job.NamespaceID === namespace
    53          )
    54          .map(job => filterKeys(job, 'TaskGroups', 'NamespaceID'));
    55      })
    56    );
    57  
    58    this.get(
    59      '/job/:id',
    60      withBlockingSupport(function({ jobs }, { params, queryParams }) {
    61        const job = jobs.all().models.find(job => {
    62          const jobIsDefault = !job.namespaceId || job.namespaceId === 'default';
    63          const qpIsDefault = !queryParams.namespace || queryParams.namespace === 'default';
    64          return (
    65            job.id === params.id &&
    66            (job.namespaceId === queryParams.namespace || (jobIsDefault && qpIsDefault))
    67          );
    68        });
    69  
    70        return job ? this.serialize(job) : new Response(404, {}, null);
    71      })
    72    );
    73  
    74    this.get(
    75      '/job/:id/summary',
    76      withBlockingSupport(function({ jobSummaries }, { params }) {
    77        return this.serialize(jobSummaries.findBy({ jobId: params.id }));
    78      })
    79    );
    80  
    81    this.get('/job/:id/allocations', function({ allocations }, { params }) {
    82      return this.serialize(allocations.where({ jobId: params.id }));
    83    });
    84  
    85    this.get('/job/:id/versions', function({ jobVersions }, { params }) {
    86      return this.serialize(jobVersions.where({ jobId: params.id }));
    87    });
    88  
    89    this.get('/job/:id/deployments', function({ deployments }, { params }) {
    90      return this.serialize(deployments.where({ jobId: params.id }));
    91    });
    92  
    93    this.post('/job/:id/periodic/force', function(schema, { params }) {
    94      // Create the child job
    95      const parent = schema.jobs.find(params.id);
    96  
    97      // Use the server instead of the schema to leverage the job factory
    98      server.create('job', 'periodicChild', {
    99        parentId: parent.id,
   100        namespaceId: parent.namespaceId,
   101        namespace: parent.namespace,
   102        createAllocations: parent.createAllocations,
   103      });
   104  
   105      // Return bogus, since the response is normally just eval information
   106      return new Response(200, {}, '{}');
   107    });
   108  
   109    this.delete('/job/:id', function(schema, { params }) {
   110      const job = schema.jobs.find(params.id);
   111      job.update({ status: 'dead' });
   112      return new Response(204, {}, '');
   113    });
   114  
   115    this.get('/deployment/:id');
   116  
   117    this.get('/job/:id/evaluations', function({ evaluations }, { params }) {
   118      return this.serialize(evaluations.where({ jobId: params.id }));
   119    });
   120  
   121    this.get('/evaluation/:id');
   122  
   123    this.get('/deployment/allocations/:id', function(schema, { params }) {
   124      const job = schema.jobs.find(schema.deployments.find(params.id).jobId);
   125      const allocations = schema.allocations.where({ jobId: job.id });
   126  
   127      return this.serialize(allocations.slice(0, 3));
   128    });
   129  
   130    this.get('/nodes', function({ nodes }) {
   131      const json = this.serialize(nodes.all());
   132      return json;
   133    });
   134  
   135    this.get('/node/:id');
   136  
   137    this.get('/node/:id/allocations', function({ allocations }, { params }) {
   138      return this.serialize(allocations.where({ nodeId: params.id }));
   139    });
   140  
   141    this.get('/allocations');
   142  
   143    this.get('/allocation/:id');
   144  
   145    this.get('/namespaces', function({ namespaces }) {
   146      const records = namespaces.all();
   147  
   148      if (records.length) {
   149        return this.serialize(records);
   150      }
   151  
   152      return new Response(501, {}, null);
   153    });
   154  
   155    this.get('/namespace/:id', function({ namespaces }, { params }) {
   156      if (namespaces.all().length) {
   157        return this.serialize(namespaces.find(params.id));
   158      }
   159  
   160      return new Response(501, {}, null);
   161    });
   162  
   163    this.get('/agent/members', function({ agents }) {
   164      return {
   165        Members: this.serialize(agents.all()),
   166      };
   167    });
   168  
   169    this.get('/status/leader', function(schema) {
   170      return JSON.stringify(findLeader(schema));
   171    });
   172  
   173    this.get('/acl/token/self', function({ tokens }, req) {
   174      const secret = req.requestHeaders['X-Nomad-Token'];
   175      const tokenForSecret = tokens.findBy({ secretId: secret });
   176  
   177      // Return the token if it exists
   178      if (tokenForSecret) {
   179        return this.serialize(tokenForSecret);
   180      }
   181  
   182      // Client error if it doesn't
   183      return new Response(400, {}, null);
   184    });
   185  
   186    this.get('/acl/token/:id', function({ tokens }, req) {
   187      const token = tokens.find(req.params.id);
   188      const secret = req.requestHeaders['X-Nomad-Token'];
   189      const tokenForSecret = tokens.findBy({ secretId: secret });
   190  
   191      // Return the token only if the request header matches the token
   192      // or the token is of type management
   193      if (token.secretId === secret || (tokenForSecret && tokenForSecret.type === 'management')) {
   194        return this.serialize(token);
   195      }
   196  
   197      // Return not authorized otherwise
   198      return new Response(403, {}, null);
   199    });
   200  
   201    this.get('/acl/policy/:id', function({ policies, tokens }, req) {
   202      const policy = policies.find(req.params.id);
   203      const secret = req.requestHeaders['X-Nomad-Token'];
   204      const tokenForSecret = tokens.findBy({ secretId: secret });
   205  
   206      // Return the policy only if the token that matches the request header
   207      // includes the policy or if the token that matches the request header
   208      // is of type management
   209      if (
   210        tokenForSecret &&
   211        (tokenForSecret.policies.includes(policy) || tokenForSecret.type === 'management')
   212      ) {
   213        return this.serialize(policy);
   214      }
   215  
   216      // Return not authorized otherwise
   217      return new Response(403, {}, null);
   218    });
   219  
   220    const clientAllocationStatsHandler = function({ clientAllocationStats }, { params }) {
   221      return this.serialize(clientAllocationStats.find(params.id));
   222    };
   223  
   224    const clientAllocationLog = function(server, { params, queryParams }) {
   225      const allocation = server.allocations.find(params.allocation_id);
   226      const tasks = allocation.taskStateIds.map(id => server.taskStates.find(id));
   227  
   228      if (!tasks.mapBy('name').includes(queryParams.task)) {
   229        return new Response(400, {}, 'must include task name');
   230      }
   231  
   232      if (queryParams.plain) {
   233        return logFrames.join('');
   234      }
   235  
   236      return logEncode(logFrames, logFrames.length - 1);
   237    };
   238  
   239    // Client requests are available on the server and the client
   240    this.get('/client/allocation/:id/stats', clientAllocationStatsHandler);
   241    this.get('/client/fs/logs/:allocation_id', clientAllocationLog);
   242  
   243    this.get('/client/v1/client/stats', function({ clientStats }, { queryParams }) {
   244      return this.serialize(clientStats.find(queryParams.node_id));
   245    });
   246  
   247    // TODO: in the future, this hack may be replaceable with dynamic host name
   248    // support in pretender: https://github.com/pretenderjs/pretender/issues/210
   249    HOSTS.forEach(host => {
   250      this.get(`http://${host}/v1/client/allocation/:id/stats`, clientAllocationStatsHandler);
   251      this.get(`http://${host}/v1/client/fs/logs/:allocation_id`, clientAllocationLog);
   252  
   253      this.get(`http://${host}/v1/client/stats`, function({ clientStats }) {
   254        return this.serialize(clientStats.find(host));
   255      });
   256    });
   257  }
   258  
   259  function filterKeys(object, ...keys) {
   260    const clone = copy(object, true);
   261  
   262    keys.forEach(key => {
   263      delete clone[key];
   264    });
   265  
   266    return clone;
   267  }