The REST API

1. What is Axebow API

Note, some parts of the document refer to features not yet implemented as of the date of publication of the document. They are marked as NYI

AxebowAPI is the specification of the service that the Axebow platform exposes to its users (mostly excluding operators of the platform itself). It is in charge of attending requests to manage services, platform resources (volumes, secrets, …​), users and tenants.

The API can be divided in three main sections:

System Information

To retrieve information about the Axebow service and its underlying elements.

Tenants

To manage tenants, their services and resources.

Users

To manage users accessing Axebow.

In addition, The Tenant section is composed of several subsections

Resources

To manage registration, removal, and modifications, and sharing Kumori Resources.

Services

To manage the deployment of kumori applications and the lifecycle of the resulting services.

Accounts

To manage IaaS access to its resources.

Deployment environments

To define and manage IaaS environments where to run the services of the tenant.

(See Kumori Platform for information about the technology underlying Axebow)

Finally, The Resource section deals with the following elements

CA

to manage certificate authorities.

Certificates

to manage certificates.

Domains

to manage the internet domains used to access the deployed services through HTTP inbounds.

Ports

to manage the ports used to access the deployed services through TCP ports.

Secrets

to manage the secrets used in deployed services.

Volumes

to manage the volumes used by deployed services to store data.

2. API

AxebowAPI is HTTP based, routing different actions based on the request’s URL and the HTTP method being used.

Axebow authenticates its users by the use of mTLS client certs (only for operations) or through a set of federated ID providers. All calls to the API (except the call to get the information about Axebow) must be authenticated.

In general the API manipulates entities. For this API version, we consider the following entities:

platform

The platform instance itself.

tenant

Organizations contracting services with the platform.

user

Users authenticating to the platform.

Those entities are named, and the names are scoped to the entity types.

Within an instance of an entity, we can manipulate subentities that we will refer to as objects. Depending on the entity, there will be different object types.

Like entities, object instances will also be named, and names will be scoped to their entity as well as their object type.

The platform entity has only one instance, and calls to access it may not include its name. At this point in time, platform instances have no object types associated.

Likewise, the user entity has no object types in this API version.

tenants admit the following object types:

account

Axebow tenant IaaS information management.

service

Deployed service management and updates.

domain

Kumori Resource domain management

port

Kumori resource port management

certificate

Kumori resource port management

ca

Kumori resource ca (certificate authority) management

secret

Kumori resource secret management

volume

Kumori resource volume management

Accounts also admit the following object type:

environment

Axebow tenant deployment environment management within an account

2.1. API Format

2.1.1. Request

The notation below uses angle brackets to specify elements of a URI that MUST be present. Square brackets are used for optional elements.

The HTTP API paths general format is as follows:

<OPERATION> /api/<version>/<entity>/[entity name]/[<object_type>/[object_name]/[section...]]?[params]

The <OPERATION>, version and <entity> sections are mandatory.

The <OPERATION> must be one of the following:

GET

to read information.

POST

to register a new object in the system.

PUT

to modify a previously registered object.

DELETE

to delete a previously registered object.

PATCH

To partially modify a previously registered object

In this document we describe the API versioned as 1.0-beta, thus 1.0-beta MUST be included in the URL path. Further versions will be assigned different version numbers following a semantic versioning approach with only two components (and potentially, a prerelease qualifier).

The [section] part is used when the call refers to a specific portion of the object, for those objects for which such sections are defined. They will be discussed when describing each object type.

The [params] are query parameters defined per <entity-kind>/<object-type>/[section] and operation.

In addition, some requests may carry with them files and/or JSON objects in the body.

AxebowAPI offers a swagger endpoint (/docs).

Example:

GET /api/1.0-beta/tenant/mycompany/service/myservice/history

Reads section history within the myservice service of tenant mycompany

In this document, JSON body structure will be specified using the CUE language. The JSON Schma specification can be obtained from Axebow’s endpoint.

2.1.2. Response

Each call will receive an Http response code.

Content resulting from a return Http code of 2XX has the following format:

#APIResponse: {
  data?  : #PlatformResponse | #TenantResponse | #UserResponse   (1)
  events?: [...{  (2)
    message: _  (3)
    level  : "ERROR" | "WARNING" | "INFO" (4)
  }]
}
1 The response content itself, if any. Will follow a different schema for different calls.
2 Array of events related to this call (if any). Each event has the following format:
3 An object containing information about the event
4 Level of severity for the event ERROR, WARNING or INFO-

HTTP error codes to be expected are:

4xx error codes
400

client make an invalid request

401

invalid authentication credentials

403

authorization failure

404

cannot find the requested resource

409

request conflicts with the current state of the server

415

unsupported payload format

429

the user has sent too many requests in a given amount of time

5xx error codes
500

internal server error

501

functionality to fulfill the request is not supported

502

invalid response from the upstream server

503

server is not ready to handle the request

504

request timeout from the upstream server

Error responses will have a JSON body with the following structure

#ErrorBody: {
  code:    #AxebowErrorCodes, (1)
  content: _  (2)
}
1 A string among a reduced set of strings encoding additional info about the error
2 An object, with a structure dependent on the code

3. System Information

3.1. Get Instance Information

GET /platform

Gets information about the Kumori platform instance.

  • Parameters: none.

  • Request body: none.

  • Example response data (TBD):

    #PlatformInfo: {
      apiVersions    : [...#ProtocolVersion],   (1)
      instanceName   : string,                  (2)
      platformVersion: #Version,                (3)
      oidProviders: string[]                    (4)
      iaasProviders: [provider:string]: {...}   (5)
      freemiumAdvancedLimits: #Limits           (6)
      freemiumLimits: #Limits                   (7)
      portRange: number[]                       (8)
      referenceDomain: string                   (9)
    }
    1 The list of API versions supported
    2 The name of the platform instance
    3 The version of the platform tech stack
    4 The set of oid providers accepted by Axebow
    5 a dictionary with the IaaS providers supported, and their configurable characteristics
    6 Resource consumption limits for freemium accounts
    7 Resource consumption limits for basic freemium accounts
    8 Range of ports available
    9 Reference domain of the platform

4. Users

Users in Axebow are agents that operate on behalf of tenants and must authenticated by means of some openid provider (alternatively, Certificates can also be used for mTLS interactions).

Axebow will establish a trust relationship with a set of openid providers. Only users that can authenticate against one of those providers will be able to use Axebow’s API.

All interactions with the API described here must come from an authenticated user: the agent of the API request.

When a user is registered to Axebow it is issued a platform-generated UID, that is associated to the authenticated user.

A user can add openid provider profiles to its Axebow registration.

In this section we provide the APIs Axebow provides to handle users on the platform.

The agent of a user request can only be the user itself or an operator.

4.1. User registration

A user registers by simply posting a profile and providing an Authentication token containing the user’s information, as well as a few more parameters in the body for providing more information.

POST /api/1.0-beta/user

Registers the authenticated user.

If the user has already been registered, the call fails.

  • Parameters: none

  • Request body:

    • JSON structure as

      {
        name: string,
        surname: string,
        discoveryMethod?: string,
        companyName?: string,
        companyRole?: string
      }
  • Response: standard response with the data field containing the UID of the created user.

    • internal UID

{
  success: true,
  errors: [],
  data: {
    userid: urecord.id.name
  }
}

4.2. Add profile

POST /api/1.0-beta/user/provider

Creates a user’s profile for one of the platform’s known oid providers.

The call fails if

  • the user already has a profile for <oidp>

  • Parameters: none

  • Request body:

    • JSON structure as

{
  jwt: string
}
  • Response: Generic, with no data

Note that the jwt must be signed by the provider, and must not have expired.

UNIMPLEMENTED

4.3. Remove profile

DELETE /api/1.0-beta/user/provider/<oidp>

Will only succeed if oid is not the only profile for the user

  • Parameters: none

  • Request body: none

  • Response: Generic

4.4. Remove user

DELETE /api/1.0-beta/user

Removes the user making the request.

The user can’t be removed when: * The user is the last "owner" member in a tenant

  • Parameters: none

  • Request body: none

  • Response: Generic

4.5. Get info

GET /api/1.0-beta/user/info

Gets the information of the user making the request.

  • Parameters: none

  • Request body: none

  • Response:

    • JSON with user detailed data

      #UserInfo: {
        tenants: {
          [string]: #TenanUserRole
        }
        profiles: {
          [oidp=string]: #OIdPProfile[oidp]
        }
      }

4.6. List

GET /api/1.0-beta/user

Gets the list of users. Can only be used by the operator tenant.

  • Parameters: none

  • Request body: none

  • Response:

    • JSON with the list of users ID.

      [...{
        name: string,  // user given name
        uid:  string,  // internal user ID.
      }]

5. Tenants

A tenant is an organization that has established a contract of usage with Axebow. Tenants are created by registered users that act on their behalf.

When a registered user creates a tenant, it becomes its owner, and can request any action on behalf of the tenant, including adding other users to it.

Users in a tenant can have one of three roles: owner, admin, and plain, in descending order of privileges.

Detailed authorization to perform specific actions on behalf of a tenant by any of its users MUST be established by the tenant itself, with its own authorization model and policies that can only be established by admins of the tenant.

Axebow authorizes calls in two phases: the first phase it implements directly and simply checks that the user has been added to the tenant it wants to request an action for.

If the first phase check passes, a second phase authorization is performed by executing a series of selectors to determine if an action, specially a deployment action, can be carried out.

Tenant API calls, as a general rule, must be carried out by users of a tenant, or by operators. Operators are not subject to tenant’s authorization policies.

An operator is a user of the operator tenant.

5.1. Create Tenant

POST /api/1.0-beta/tenant/<name>

Creates a new tenant whose owner is the user making the request. If the name is taken the request fails

  • Parameters: none

  • Request body:

    • JSON

      #TenantSpec: {
          rules: {
              // Selecting an environment to deploy a service
              selectEnvironmentService      : [...{reason: string, sel: #Selector}]
      
              // Selecting an environment with explicit acceptance
              selectAcceptEnvironmentService: [...{reason: string, sel: #Selector}]
      
              // Validates an environment to place a resource within
              validateEnvironmentResource   : [...{reason: string, sel: #Selector}]
      
              // Validates an environment for a User to deploy there
              validateEnvironmentUser       : [...{reason: string, sel: #Selector}]
          },
          registry: {
            endpoint     : string,      (1)
            credentials? : string,      (2)
            domain       : string,      (3)
            public       : *true | bool (4)
          }
      }

      When registering a tenant a NMP registry account can be configured in which can be published kumori modules.

      1 endpoint: endpoint of your npm registry
      2 credentials: credentials for your npm registry
      3 domain: domain under which the modules will be published in the registry
      4 public: selector for choosing wheter to make published modules public or private.
  • Response: common response

5.2. Update Tenant

PATCH /api/1.0-beta/tenant/<name>

Updates an existing tenant information. If the tenant does not exist the request fails.

  • Parameters: none

  • Request body:

    • JSON

      #TenantSpec: {
          rules: {
              // Selecting an environment to deploy a service
              selectEnvironmentService      : [...{reason: string, sel: #Selector}]
      
              // Selecting an environment with explicit acceptance
              selectAcceptEnvironmentService: [...{reason: string, sel: #Selector}]
      
              // Validates an environment to place a resource within
              validateEnvironmentResource   : [...{reason: string, sel: #Selector}]
      
              // Validates an environment for a User to deploy there
              validateEnvironmentUser       : [...{reason: string, sel: #Selector}]
          },
          registry: {
            endpoint     : string,      (1)
            credentials? : string,      (2)
            domain       : string,      (3)
            public       : *true | bool (4)
          }
      }
  • Response: common response

5.3. Remove

DELETE /api/1.0-beta/tenant/<tenant>

Removes the tenant <tenant>.

The request will fail when:

  • The user making the call is not the only owner of the tenant

  • There are services running for the tenant.

When a tenant is removed, all its resource registrations are also removed, as well as all its environments and accounts. Axebow may keep whatever information it needs for proper reporting the usage of the platform, but such information will no longer be available to the tenant through this API.

When a tenant is removed, its name can be re-used for a new tenant after the removal has been completed.

  • Parameters: none

  • Request body: none

  • Response: common response

5.4. Accounts

Tenants can establish accounts. An account identifies a IaaS provider and fills in information needed to access its API (credentials)

In addition, when adding an account, a tenant establishes which IaaS resource flavors (VMs, storage classes,…​) it wants to consider when allocating them on the IaaS.

5.4.1. Add Account

POST /api/1.0-beta/tenant/<tenant>/account/<acname>
  • Parameters: none

  • Request body:

    • JSON

      #TenantAccount: this={
          spec : {
            iaas          : #IaaSProviderKey
            iaasInfo      : #IaaSProviderInfo[this.iaas]
            marks         : #Marks
          }
          meta: {
            labels: [string]: string
          }
      }
  • Result: none

5.4.2. Update Account

PATCH /api/1.0-beta/tenant/<tenant>/account/<acname>
  • Parameters: none

  • Request body:

    • JSON

      #TenantAccount: this={
          spec : {
            iaas          : #IaaSProviderKey
            iaasInfo      : #IaaSProviderInfo[this.iaas]
            marks         : #Marks
          }
          meta: {
            labels: [string]: string
          }
      }
  • Result: none

5.4.3. Get Account

PATCH /api/1.0-beta/tenant/<tenant>/account/<acname>
  • Parameters: none

  • Result:

    • JSON

      #TenantAccount: this={
          spec : {
            iaas          : #IaaSProviderKey
            iaasInfo      : #IaaSProviderInfo[this.iaas]
            marks         : #Marks
          }
          meta: {
            labels: [string]: string
          }
      }

5.4.4. List Accounts in Tenant

PATCH /api/1.0-beta/tenant/<tenant>/account

Return the list of names of the accounts in the tenant

  • Parameters: none

  • Result:

    • JSON

      [...string]

5.4.5. Remove Account / Purge Account

DELETE /api/1.0-beta/tenant/<tenant>/account/<acname>
  • Parameters:

    • delete: boolean

If delete is true removes a given account only if there is no environment for the account. Removal of the account, eventually results in the release of all IaaS resources previously reserved under it.

If delete is false purges an account of all unused IaaS resources.

5.5. Deployment Environments

A deployment environment is a mechanism primarily for:

  1. Determining the IaaS account to use for the resources to employ by the services deployed by the tenant.

  2. Establishing a set of variables and values for them so that quotas can be established and decisions can be made on where to deploy a service, or wether to allow a user to deploy in it or a Kumori resource to actually be established in it (see selectors).

An IaaS account, as mentioned above, establishes an isolated environment even for billing purposes for the IaaS provider itself. Depending on the IaaS, spending limits can be set up (not on Axebow) and specific flavors of the resources provided by the IaaS can be specified (on Axebow) to be considered for allocation.

An environment is created within an account, and it must specify if needs to be further isolated.

Isolated environments will give rise to their own clusters, so that interference with other services deployed in other environments can be avoided.
Environments declaring different accounts will be isolated from each other.

It is important to understand that environment isolation may (likely) incur extra IaaS costs, as control planes must be reserved to achieve this isolation.

Isolation is convenient when the tenant needs to guarantee absence of contention in network usage, for instance separating pre-production from testing, from production loads.

In addition, a deployment environment can also be used to

  1. Establish limits in axebow resource usage (vcpu, ram, storage)

  2. Select the environment where to deploy a service

  3. Determine which users can deploy which loads on an environment

  4. Determine which kumori resources can be propagated to an environment to be used by the services that can be deployed there

To provide the above extra features, Axebow lets a tenant associate metadata with an environment. The metadata structure is an arbitrary Json object. Such objects will be interpreted by selectors

5.5.1. Create Environment

POST /api/1.0-beta/tenant/<tenant>/account/<acname>/environment/<name>

Creates a new deployment environment within the given account.

  • Parameters: none

  • Request body:

    • JSON describing the environment, #EnvironmentSpec:

      #EnvironmentSpec: this={
          // Marks are used to define limits in resource usage.
          marks: #Marks
          // Arbitrary metadata, including any kind of quota info.
          labels?: {...}      
      }
  • Response: common response

5.5.2. Update Environment

Only the metadata can be changed on an environment

PATCH /api/1.0-beta/tenant/<tenant>/account/<acname>/environment/<name>

Modifies an existing deployment-environment.

  • Parameters: none

  • Request body: JSON describing the environment **

    {
      marks: #Marks
    }
  • Response: common response

changing the metadata will only affect future selector runs. Decisions made in the past will not be reconsidered.

5.5.3. Remove Environemnt

DELETE /api/1.0-beta/tenant/<tenant>/account/<acname>/environment/<name>

Removes a deployment environment.
The request will fail if there are services deployed in the environment

  • Parameters: none

  • Request body: none

  • Response: none

5.5.4. Get Environment Info

GET /api/1.0-beta/tenant/<tenant>/account/<acname>/environment/<name>

Gets the information of a deployment-environment.

  • Parameters: none

  • Request body: none

  • Response: JSON describing the environment. **

    // The status of an environment shows dynamic data like the number of vsrious
    // resources in used, and for vcpus, their accumulated usage.
    #MarksStatus: {
      vcpu:      {current: number, unit: "m"}
      memory:    {current: number, unit: "MB"}
      vstorage:  {current: number, unit: "MB"}
      nrstorage: {current: number, unit: "MB"}
      rstorage:  {current: number, unit: "MB"}
      storage:   {current: number, unit: "MB"}
      cost:      {current: number, unit: "EUR"}
    }
    
    #EnvironmentInfo: {
        spec  : #EnvironmentSpec
        status: {
          marks: #MarksStatus
        }
    }

5.5.5. List Environments in Tenant

GET /api/1.0-beta/tenant/<tenant>/account/<acname>/environment

Gets the list of deployment-environments for the given tenant+

  • Parameters:none

  • Request body: none

  • Response: JSON array with the list of dep-envs names **

    [...string]

5.6. Get Tenant Info

GET /api/1.0-beta/tenant/<name>

Gets detailed information for a tenant. The user making the request must be a confirmed user of the tenant or of the "operator" tenant.

  • Parameters: none

  • Request body: none

  • Response:

    • JSON with all the tenant data:

      #TenantInfo: this={
          accounts: [account=string]: {
              account     : #TenantAccount
              environments: [string]: #EnvironmentSpec & {_account: account, account: this.account}
          }
          users: [string]: {
              role     : #TenantUserRole
              confirmed: bool
          }
          resources: [kind=#ResourceKind]: [string]: #ResourceSpec[kind]
          rules: #TenantSpec.rules
      }

5.7. List Tenants

GET /api/1.0-beta/tenant?[params]

Gets the list of tenants satisfying the role parameter. If no parameters are supplied, the user making the request must be part of the operator tenant

  • Parameters:

    • strict?: bool. By default true, returns the list of tenants the user making the request has access to. If false, the request can only be done by and opeator user, which will return a list of all the tenants in the platform.

  • Request body: none

  • Response:

    • JSON with the list of tenant IDs.

      {
        [string]: #TenantRole | "none"  // the key is the tenant name.
                                        // The value, the role of the user in the tenant
      }

5.8. Tenant users

Users are added to tenants with specific roles.

5.8.1. Invite a user to a tenant with a role

POST /api/1.0-beta/tenant/<tenant>/user/<user>?role=`owner | admin | plain`

Adds a user to a tenant with the proposed role: owner, admin, plain.

If the user already belongs to the tenant, the call fails.

The request adds the user to the tenant in the pending state. In this state, the user cannot still act on behalf of the tenant except to confirm its acceptance (see ahead)

The request fails if

  • The user making the request is not at least admin.

  • role is owner, and the user making the request is not an owner of the tenant.

  • Parameters:

    • role: One of owner | admin | plain. Default: plain

  • Response: common response

5.8.2. Confirm an invitation to a tenant

PUT /api/1.0-beta/tenant/<tenant>/user?role=`owner | admin | plain`

Confirms the user making the request to a tenant.

The call will fail if:

  • <user> is not unconfirmed in the tenant.

  • role in this call is different from the role the user was added with.

  • Parameters:

    • role: One of owner | admin | plain. No default. The parameter MUST be provided.

  • Request body: none:

  • Response: common response

5.8.3. Reject an invitation to a tenant

DELETE /api/1.0-beta/tenant/<tenant>/user

The user making the requet rejects the invitation to a tenant.

The call will fail if:

  • <user> is not confirmed in the tenant.

  • <user> has no invitation in the tenant.

  • Parameters:

    • role: One of owner | admin | plain. No default. The parameter MUST be provided.

  • Request body: none:

  • Response: common response

5.8.4. Modify a user’s role

PUT /api/1.0-beta/tenant/<tenant>/user/<user>?role=`owner | admin | plain`

Modifies the role of <user> within <tenant>. The call will take immediate action if it does not fail (no confirmation needed)

The call will fail if:

  • The user making the request is not at least admin in the tenant.

  • <user> is not confirmed in the tenant.

  • role in this call is above the role of the user making the call.

  • <user> is the last owner of the tenant and role is not owner.

  • Parameters:

    • role: One of owner | admin | plain. No default. The parameter MUST be provided.

  • Request body: none:

  • Response: common response

5.8.5. Exclude a user from a tenant member list

DELETE /api/1.0-beta/tenant/<tenant>/user/<user>

Removes a user from the tenant member list.

If the requesting user has a privilege (role) less than admin the request fails. If <user> is the last owner of the tenant, the request fails.

  • Parameters: none

  • Request body: none

  • Response: none

5.9. Tenant Services

Tenants can deploy Kumori applications to create services.

Running services on Axebow imply indicating somehow on which deployment environment a service should be deployed into. Thus, such information must be part of a request to create a service.

Services on Axebow proceed through a series of revisions, where each revision implements changes in configuration of the service, or implementation of the service, or topology, or all of them. All revisions are deployed within the deployment environment specified for the service when created.

Every time a request for setting up a revision for a service is received by Axebow, the costs that the revision would incur are computed. Afterwards, the revision must go through a process of acceptance. Until a revision is not accepted, it cannot be actually deployed.

When a service is created, a first revision for the service is also created. If this first revision is not accepted, the revision and the service are removed.

5.9.1. List Services in a tenant

GET /api/1.0-beta/tenant/<tenant>/service

Gets the list of running services for a given tenant.

  • Parameters: none

  • Request body: none

  • Response data:

    [...string]   // a simple array of service names

5.9.2. Get Service

GET /api/1.0-beta/tenant/<tenant>/service/<name>?summary=bool

Gets information about a running service

  • Parameters:

    • summary: If true returns a summarized version of the service information, indicating basic information about the state of the service, as well as, a summarized view of the resources this service depends on. If set to false, it returns an extended version which include information abount the instances the services has, its resource ( CPU, memory…​) usage, and much more useful information related to the service.

  • Request body: none

  • Response data: contains general information about the service (creation and last modification timestamps, name, tenant), the service configuration in JSON format, the service topology (in JSON format) and the existing links with other services:

    • if summary = true

      {
        id:        number
        deleted:   number
        current:   number
        deployed:  number
        resources: {...}
      }
    • if summary = false

      {
        "comment": "Blah...",
        "revision": 12345678,
        "configuration": {
          "parameters": {...},
          "resources": {...},
          "scale": {
            "frontend": 1
          },
          "resilience": 0
        },
        "creationTimestamp": "2023-06-15T14:50:25Z",
        "events": [{
          "counter": 1,
          "firstTimestamp": "...",
          "lastTimestamp": "...",
          "message": "...",
          "source": {
            "id": "...",
            "kind": "...",
            "name": "..."
          },
          "reason": "..."
        }],
        "instances": {
          "frontend": {
            "instance-hfkhdskfs": {}
          }
        },
        "lastModification": "2023-06-19T11:45:35Z",
        "links": [{
          "source": {
            "tenant": "democomp",
            "deployment": "helloinb",
            "channel": "inbound"
          },
          "target": {
            "tenant": "democomp",
            "deployment": "helloworld",
            "channel": "service"
          }
        }],
        "ref": {
          "name":     "hellodemo",
          "tenant":   "democomp",
          "domain":   "kumori.examples",
          "module":   "helloworld",
          "artifact": "helloworldsvc",
          "version": [1,0,7]
        }
      }
  • Request cost: none

5.9.3. Get Service Scale

GET /api/1.0-beta/tenant/<tenant>/service/<name>/scale

Gets the number of replicas per role for a running service.

  • Parameters: none

  • Request body: none

  • Response data: the number of replicas per service role.

    #Scale: {
      [string]: uint
    }

    Where each entry in the json object represents the name of one of the deployed roles.

For example:

{
  "frontend":  1,
  "worker":  3
}
  • Request cost: none

5.9.4. Get Service channels

GET /api/1.0-beta/tenant/<tenant>/service/<name>/channels
  • Parameters: none

  • Request body: none

  • Response data:

    {
      client: {
        [string]: any // metadata TBD
      }
      server: {
        [string]: any // metadata TBD
      }
    }

5.9.5. Get Service History

GET /api/1.0-beta/tenant/<tenant>/service/<name>/history

Gets the history of versions (updates) registered in the system, including the running one.

  • Parameters: none

  • Request body: none

  • Response data:

    {
        reinstates?: number, // Only if the revision is a Rollback
        revision:    number,
        previous:    number,
        original:    number,
        comment:     string,
        type:        "PUT" | "PATCH" | "SCALE" | "ROLLBACK",
    }

In the response, field original will be filled if a previous update was selected to run the service (see ahead), in which case, no patch against previous has been performed.

5.9.6. Get Service Roles

GET /api/1.0-beta/tenant/<tenant>/service/<name>/role/<name>

Gets information about a given role in a given service.

The result follows this structure:

{
  artifactref: #ArtifactRef,
  config: #Config,
  instances: {
    [string]: {
      containers: [...#Container],
      creationTimestamp: string,
      events: [
        ...{
          counter: number
          firstTimestamp: string
          lastTimestamp: string
          message: string
          reason: string
          type: string
        }
      ]
      id: string,
      metrics: {
        usage: {
          cpu: number,
          memory: number
        }
      },
      node: string
      ready: bool,
      status: string
    }
  }
}

5.9.7. Restart Service Role

DELETE /api/1.0-beta/tenant/<tenant>/service/<name>/role/<name>

Restarts all the role <role> instances

  • Parameters: none

  • Request body: none

  • Response data: Generic

5.9.8. Get Service Role Instances

GET /api/1.0-beta/service/<tenant>/<name>/role/<name>/instance/<iid>

Gets information about a given role instance in a given service. If the role <name> is a sub-service, an extra /role/<name> section should be added until a leaf role is reached.

  • Parameters: none

  • Request body: none

  • Response data:

    {
      containers: {
        [string]: {
          metrics: {
            usage: {
              cpu: number // In vCPUs
              memory: number // In bytes
            }
          }
          ready: bool
          restarts: number
          states: {
            running: {
              startedAt: string
            }
          }
        }
      }
      creationTimestamp: string
      events: [
        ...{
          counter: number
          firstTimestamp: string
          lastTimestamp: string
          message: string
          reason: string
          type: string
        }
      ]
      id: string
      metrics: {
        usage: {
          cpu: number // In vCPUs
          memory: number // In bytes
        }
      }
      node: string
      ready: bool
      status: string
    }
  • Request cost: none

Instance name should be known by the request issuer after having gotten a description of the role or the complete service

5.9.9. Restart Service Role Instance

DELETE /api/1.0-beta/tenant/<tenant>/service/<name>/role/<name>/instance/<iid>

Restarts the specified instance of the given role.

  • Parameters: none

  • Request body: none

  • Response data: Generic

5.9.10. Get Service Role Instance Container Logs

GET /api/1.0-beta/tenant/<tenant>/logs/service/<name>/role/<name>/instance/<iid>/[container/<name>][?parameters]

Returns the standard output and error of the given instance. If an instance has more than one container, one of them must be specified.

  • Parameters:

    • tail=N: to show the last N log lines of the container involved:

    • delta=N: to show the last N seconds of logs of the container involved:

      GET /api/1.0-beta/tenant/<tenant>/logs/service/<name>/role/<name>/instance/<iid>/[container/<name>]?tail=1000

5.9.11. Create a service

POST /api/1.0-beta/tenant/<tenant>/service/<name>

Registers a new service for a tenant. Requires the kumori deployment specification as a module:

  • The service artifact describing the service being deployed, with all its dependencies, either as references to published artifacts, or included inline within the deployment bundle (see below)

  • Autoscaling parameters if any.

  • Deployment environment selection parameters

The payload will consist of a Kumori Bundle and a JSON structure (multipart).

A Kumori Bundle is a zip archive containing a set of top-level directories each one representing a Kumori module. There must be a directory with the name deployment, and at the top level of its module it MUST define a deployment package that resolves to a #Deployment structure as defined in Kumori’s service model.

A deployment creation creates implicitly a revision deployment request. The deployment request will not be carried out until the costs are accepted (see [section-api-accept-deployment]).
  • Parameters:

    • dryrun: if true, the manifest is processed and the costs calculated but the new service is never deployed..

    • wait: if set, the request ends once the new service is up and running or the specified timeout is reached. In the last case, a 201 code is returned, and the data field contains the request ID that can be used. to retrieve information about the request. If 0, the timeout is infinite. Otherwise, the request ends once the deployment operation is validated and registered.

    • accept: if set, the request is automatically accepted if resource consumption falls within the declared bounds, and the accept step (see [section-api-accept-deployment]) is not required.

  • Request body: a multipart body containing:

    • A Kumori bundle (see above)

    • A JSON document containing a metadata JSON object used to select the deployment environment.

      #ServiceSpec: {
          bundle: ZipFile
          // Arbitrary JSON used for environment selection as well as 
          // later on, for scaling decisions.
          // Note that his metadata is not available within the service being
          // deployed.
          meta   : {...}
      
          // Not available for decisions
          comment: string
      }
    • A bundle with the deployment manifest and, optionally, some other modules required to deploy the service.

  • Response data: a structure with the following fields

#ServiceStatus: {
    // ID of the first revision
    firstRevision   : number
    currentRevision : number
    history         : [...number]
    environment    ?: string 
}

#SerficeInfo: {
    spec  : #ServiceSpec
    status: #ServiceStatus
}

Where the revision field is the revision ID assigned by the platform to the created revision request created as a consequence.

5.9.12. Create a service (simple)

POST /api/1.0-beta/tenant/<tenant>/service/<name>/simple

It is the same as the previous method but this one does not require a bundle, instead just an artifact reference is provided to deploy a service or component whose manifests are already published in a registry.

  • Parameters:

    • dryrun: if true, the manifest is processed and the costs calculated but the new service is never deployed..

    • wait: if set, the request ends once the new service is up and running or the specified timeout is reached. In the last case, a 201 code is returned, and the data field contains the request ID that can be used. to retrieve information about the request. If 0, the timeout is infinite. Otherwise, the request ends once the deployment operation is validated and registered.

    • accept: if set, the request is automatically accepted if resource consumption falls within the declared bounds, and the accept step (see [section-api-accept-deployment]) is not required.

  • Request body:

    {
      deployment: {
        name: string
        up: null,
        meta: {...},
        config: {
          parameter: [string]: {...},
          resource: {...},
          resilience: number,
          scale: #Scale
        },
        artifact: {
          ref: #ArtifactRef
        }
      }
      comment: string
      meta: {...}
    }

5.9.13. Accept Service deployment request

Revision requests are accepted/rejected by explicitly "updating" its acceptance status

PUT /api/1.0-beta/tenant/<tenant>/service/<name>/revision/<revision>?accept=true/false

Accepting a service revision means that the configuration of that revision will be deployed for the service. A revision can only be accepted if it has been authorized and validated but it has not been accepted or rejected yet.

Rejecting the revision will remove it from the system, not deploying it. Moreover, if it was the first revision of a service the service itself will be removed.

<revision> is the revision number to be accepted to be deployed for an existing service. This revision id has been returned from the POST deployment calls above. If only the first revision of a deployment exists,<revision> can be omitted.

  • Parameters:

    • accept: boolean that indicates to accept (true) or reject the revision deployment request.

  • Request body: none

  • Response data: none *

5.9.14. Partial Update Service

PATCH /api/1.0-beta/tenant/<tenant>/service/<name>/revision/<previous>

Sends a request for an update of an existing deployment. When an update request is received, it must be accepted again. An update request will be immediately rejected if there is a previous pending update request. An update request MUST provide the revision it is updating (see below). If that revision is not the current one for the deployment, the update request is immediately rejected.

  • Parameters:

    • dryrun: if true, the manifest is processed and the costs calculated but the update is not performed.

    • wait: same as for initial deployment.

    • accept: if set, the request is automatically accepted and the accept step (see [section-api-accept-deployment]) is not required.

    • previous: Non-optional parameter that MUST indicate the revision this one patches.

  • Request body

    • A deployment bundle as for initial deployment, but the bundle itself may be partial: some of the modules may not be included, in which case they should have been part of a previous revision. Also, the deployment module can be partial, in which case, configuration values not included in the deployment manifest are taken from the revision this one updates. So, an update bundle is in reality a patch of the bundle of the previous revision.

  • Response data:

    • Info about the revision as JSON

      #RevisionStatus: {
          accepted: bool 
          resources: : [#ResourceKind]: [...string]
          usage: {
              max: {
                  vcpu: uint
                  ram:  uint  // in MB
              }
              min: {
                  vcpu: uint
                  ram:  uint  // in MB
              }
          }
      }
      
      #RevisionInfo: {
          spec  : #RevisionSpec
          status: #RevisionStatus
      }

5.9.15. Update Service

POST /api/1.0-beta/tenant/<tenant>/service/<name>/revision/<previous>

Sends a request for an update of an existing deployment. When an update request is received, it must be accepted again. An update request will be immediately rejected if there is a previous pending update request. An update request MUST provide the revision it is updating (see below). If that revision is not the current one for the deployment, the update request is immediately rejected.

  • Parameters:

    • dryrun: if true, the manifest is processed and the costs calculated but the update is not performed.

    • wait: same as for initial deployment.

    • accept: if set, the request is automatically accepted and the accept step (see [section-api-accept-deployment]) is not required.

    • remove_links: if true, if the update removes a service channel that was being used the link gets removed, if false, it will prevent updating the service so the links are not broken.

  • Request body

    • A complete deployment bundle as for initial deployment. This is not PATCHED.

  • Response data:

    • Info about the revision as JSON

      #RevisionStatus: {
          accepted: bool 
          resources: : [#ResourceKind]: [...string]
          usage: {
              max: {
                  vcpu: uint
                  ram:  uint  // in MB
              }
              min: {
                  vcpu: uint
                  ram:  uint  // in MB
              }
          }
      }
      
      #RevisionInfo: {
          spec  : #RevisionSpec
          status: #RevisionStatus
      }

5.9.16. Update Service (simple)

POST /api/1.0-beta/tenant/<tenant>/service/<name>/revision/<previous>/simple

The same as the previous method but this one does not require a bundle, instead just an artifact reference is provided to deploy a service or component whose manifests are already published in a registry.

  • Parameters:

    • dryrun: if true, the manifest is processed and the costs calculated but the update is not performed.

    • wait: same as for initial deployment.

    • accept: if set, the request is automatically accepted and the accept step (see [section-api-accept-deployment]) is not required.

    • remove_links: if true, if the update removes a service channel that was being used the link gets removed, if false, it will prevent updating the service so the links are not broken.

  • Request body:

    {
      deployment: {
        name: string
        up: null,
        meta: {...},
        config: {
          parameter: [string]: {...},
          resource: {...},
          resilience: number,
          scale: #Scale
        },
        artifact: {
          ref: #ArtifactRef
        }
      }
      comment: string
      meta: {...}
    }
  • Response data:

    • Info about the revision as JSON

5.9.17. Rollback Service

PUT /api/1.0-beta/tenant/<tenant>/service/<name>/revision/<previous>/rollback/<target>

Rollback a running service to a previous revision (target).

A service cannot be rolled back if there is a pending revision for the deployment. If when the rollback request is received the current revision of the service is nor the one denoted by previous the request fails.

Note that rolling back takes the whole configuration of the revision we are rolling back to. The only possible changes are those derived of changes in the resources.

  • Parameters:

    • dryrun: if true, the manifest is processed and the costs calculated byt the update is not performed.

    • wait: if set, the request ends once the new service is up and running or the specified timeout is reached. In the last case, an 408 error code is returned. If 0, the timeout is infinite. Otherwise, the request ends once the deployment operation is validated and registered.

    • accept: if set, the request is automatically accepted and the accept step (see [section-api-accept-deployment]) is not required.

    • remove_links: if true, if the update removes a service channel that was being used the link gets removed, if false, it will prevent updating the service so the links are not broken.

  • Response data:

    • Info about the revision as JSON

      #RevisionStatus: {
          accepted: bool 
          resources: : [#ResourceKind]: [...string]
          usage: {
              max: {
                  vcpu: uint
                  ram:  uint  // in MB
              }
              min: {
                  vcpu: uint
                  ram:  uint  // in MB
              }
          }
      }
      
      #RevisionInfo: {
          spec  : #RevisionSpec
          status: #RevisionStatus
      }
The previous revision is the version being updated by the user. If the previous revision is not the currently deployed revision for the service, the request will be rejected.

5.9.18. Change Service Scale

PATCH /api/1.0-beta/tenant/<tenant>/service/<name>/revision/:previous/scale

Shorthand update of a service, where the only "patch" is the scale configuration, provided in a JSON body. Changes the number of role replicas in an existing service. A service cannot be scaled if a previous update (or the initial registration) has not been accepted or rejected yet.

As a streamlined update, it follows all the rules of an update.

  • Parameters:

    • dryrun: if true, the manifest is processed and the costs calculated byt the update is not performed.

    • wait: if set, the request ends once the service is up and running or the specified timeout is reached. In the last case, an 408 error code is returned. If 0, the timeout is infinite. Otherwise, the request ends once it has been validated and registered.

    • accept: if set, the request is automatically accepted and the accept step (see [section-api-accept-deployment]) is not required.

    • remove_links: if true, if the update removes a service channel that was being used the link gets removed, if false, it will prevent updating the service so the links are not broken.

  • Request body:

    • a JSON document indicating which roles are going to be scaled and to which number. Roles not included are not modified.

      {
        // an entry per role whose scale must change.
        scale: [string]: uint
      }
  • Response data:

    • Info about the revision as JSON

      #RevisionStatus: {
          accepted: bool 
          resources: : [#ResourceKind]: [...string]
          usage: {
              max: {
                  vcpu: uint
                  ram:  uint  // in MB
              }
              min: {
                  vcpu: uint
                  ram:  uint  // in MB
              }
          }
      }
      
      #RevisionInfo: {
          spec  : #RevisionSpec
          status: #RevisionStatus
      }

5.9.19. Remove Service

DELETE /api/1.0-beta/tenant/<tenant>/service/<name>

Removes a deployed service, releasing its resources, and removing all its revision history.

  • Parameters:

    • wait: if set, the request ends once the service has been completely removed or the specified timeout is reached. In the last case, an 408 error code is returned. If 0, the timeout is infinite. Otherwise, the request ends once it has been validated and registered.

  • Request body: none

  • Response data: none

  • Request cost: none

POST /api/1.0-beta/tenant/<client_tenant>/service/<client_service>/client/<client_channel>/tenant/<server_tenant>/service/<server_service>/server/<server_channel>

Creates a link between a service client channel and a service server channel.

A link establishes a path between two different services through a client channel from the client service to a server channel of the server service.

  • Parameters: none

  • Request body: none

  • Response data: none

at this point in time, for two services to be linked, both must be deployed on the same deployment environment.
DELETE /api/1.0-beta/tenant/<client_tenant>/service/<client_service>/client/<client_channel>/tenant/<server_tenant>/service/<server_service>/server/<server_channel>

Removes an existing link between two services.

  • Parameters: none

  • Request body: none

  • Response data: none

  • Request cost: none

GET /api/1.0-beta/tenant/<tenant>/service/<service>/links

Lists the links a service is part of.

  • Parameters: none

  • Request body: none

  • Response data:

    [
      ...{
        id: #EntityId,
        spec: {
          client_tenant:  string
          client_service: string
          client_channel: string
          server_tenant:  string
          server_service: string
          server_channel: string
        },
        meta: #Meta,
        status: {
          linked: bool
        }
      }
    ]
  • Request cost: none

5.10. Kumori Resources

Kumori resources are pieces on information that are protected by the platform and can be used by deployed services.

Kumori resources can be registered at the platform level. Later on, when a service needs to use them they can be made available within the environment where the service finally gets deployed.

A Kumori resource can be provided with metadata that can be used by generic tenant policies to determine what environments can use them.

Additionally, a given resource can be provided with a selector that further restricts the set of environments it can be deployed to

APIs for kumori resources all look the same. What varies are the structures of the request body and part of the response data.

A couple of special cases are port and domain resources, whose values CANNOT be shared by different services, and thus, different tenants.

We provide the generic request shape for all resources, and then, for each one of them, specify the request body spec.

GET /api/1.0-beta/tenant/<tenant>/[kind]

Gets the list of registered resources of kind <kind> in a given tenant. Where <kind> is one of

#ResourceKind: "domain"       | // Kumori Resource `domain`
               "port"         | // Kumori resource `port`
               "certificate"  | // Kumori resource `port`
               "ca"           | // Kumori resource `ca` (certificate authority)
               "secret"       | // Kumori resource `secret`
               "volume"         // Kumori resource `volume`

If no kind provided it will return information about all the resources registered in the tenant.

When requesting information only for ports, the following extra fields will be included: * usedports: List of ports owned by the current tenant. * additionalshared: When using a freemium tenant, this is the list of ports owned by other freemium tenants.

  • Parameters: none

  • Request body: none

  • Response data:

    [...{
      id: #ResourceId
      accounts: [string]: string (1)
    }] (2)
    1 list of accounts and environemnts in which the resource is being used.
    2 array of resources

if no <kind> is specified then all resources for the tenant are listed like so:

{
  [#ResourceKind]: [...string] (1)
}

5.10.1. Get information about a particular resource

GET /api/1.0-beta/tenant/<tenant>/<kind>/<name>

Returns information of a the resource of kind <kind> and name <name>

  • Parameters: none

  • Request body: none

  • Response data:

5.10.2. Register Resource

POST /api/1.0-beta/tenant/<tenant>/<kind>/<name>

Registers a new resource of kind <kind> and name <name> for the <tenant>

  • Parameters:

  • Request body:

  • Response data: none

5.10.3. Update Resource

Similar to resource creation.

PUT /api/1.0-beta/tenant/<tenant>/<kind>/<name>

Updates the resource information of a previously registered resource.

  • Parameters: none

  • Request body: Same as for the creation request. The new spec substitutes the original one.

5.10.4. Unregister resource

DELETE /api/1.0-beta/tenant/<tenant>/<kind>/<name>

Removes an previously registered resource. A resource cannot be removed if it is being used by a service.

  • Parameters: none.

  • Request body: none.

  • Response data: none.

  • Request cost: none.

5.10.5. Resource structures

Resource related requests use a JSON request body, producing a JSON response, as specified in the APIs

JSON request bodies fully depend on the resource being accessed, describing it.

Response JSON bodies have a common part, and data part, where the data part is the same JSON structure used to create it/modify it.

Thus a response JSON body has the following structure:

package axebow

#ResourceKind: "ca" | "certificate" | "domain" | "port" | "secret" | "volume"

#ResourceId: [id_kind=#ResourceKind]: {
  name: string
  kind: id_kind
  parent: {
    name: string
    kind: "tenant"
  }
}

#Resource: [kind=#ResourceKind]: {
  id               : #ResourceId[kind]   // The id of the resource
  spec             : #ResourceSpec[kind] // The actual spec of the resource
  meta?            : [string]: string    // Optional dictionary of values
  selector?        : #SelectorResource   // Optional selector of the environment
  status           : {                   // list of cluster/accounts/environments where the resources registered/used
    clusters: [string]: bool
    requested: [string]: number
    environment: [string]: number
  }
}

#ResourceSpec: [kind=#ResourceKind]: {
    data     : #ResourceData[kind] // Actual data spec to be provided when creating
}

// Dictionary of resource data structures
#ResourceData: {
    ca         : #Data_CA
    certificate: #Data_Certificate
    domain     : #Data_Domain
    port       : #Data_Port
    secret     : #Data_Secret
    volume     : #Data_Volume
}


#Data_CA: string

#Data_Certificate: {
  cert: string,           // String representation of a cert
  key:  string,           // String representation of the private key
  domain: #DomainString   // A string representing a domain name
}

#Data_Domain: #DomainString

#Data_Port: uint16

#Data_Secret: string

#Data_Volume: {
  items: uint                    // How many subvolumes
  size: #Magnitude               // a magnitude string, e.g. 10M, 5G
  type: "replicated" | "single"  // kind of volumes
  provider: string               // CSI provider, as named by the platform
}

5.11. Selectors

We can declare a set of rules in a tenant that specify selectors to be run at specific points of request processing.

A tenant spec has a section with rules. Those rules contain selectors.

A selector is a stack program that when run, returns a boolean value on top of the stack.

The spec for selectors is here:

package axebow


// Selection of environments for resources and deployments
// and validation of environments for users



#Ops: "::getor" | // 2 => 1:  gets the reference on top, if it exists. 
                  // Else returns the next element
  "::exists"    | // 1 => 1:  returns true is the reference exists, false otherwise
  "::dup"       | // 1 => 2:  duplicate top of the stack
  "::pop"       | // 1 => 0:  pops top value
  "::swap"      | // 2 => 2:  Swap top two values on the stack
  "::num"       | // 1 => 1:  Convert to decimal number or leave a 0
  "::bool"      | // 1 => 1:  Convert to boolean (anything not null or false is true)
  "::eq"        | // 2 => 1:  Is equal
  "::neq"       | // 2 => 1:  Is not equal
  "::gt"        | // 2 => 1:  Is greater than
  "::gte"       | // 2 => 1:  Is greater than or equal
  "::lt"        | // 2 => 1:  Is less than
  "::lte"       | // 2 => 1:  Is less than or equal
  "::not"       | // 1 => 1:  Logical not
  "::and"       | // 2 => 1:  Logical and
  "::nand"      | // 2 => 1:  Logical nand
  "::or"        | // 2 => 1:  Logical or
  "::nor"       | // 2 => 1:  Logical nor
  "::xor"         // 2 => 1:  Logical xor


#Ref   : =~ "^\\$\\.(this|user|service|resource|environment)(\\.[^.]+)+$"
#NotRef: !~ "^\\$\\."
#NotOps: !~ "^::"

#string: #Ref | #Ops | (#NotOps & #NotRef)

#SelectorItem: #string | number | bool | null 

#Selector_Item_Resource: #SelectorItem & !~ "^\\$\\.(user|service|resource)"
#Selector_Item_User    : #SelectorItem & !~ "^\\$\\.(user|resource)"
#Selector_Item_Service : #SelectorItem & !~ "^\\$\\.(user|resource|service)" 

#Selector: [...#SelectorItem]
 
/**
  A selector is a stack program evaluating to a boolean

  A selector item can be data, a reference (special kind of data) or an operation

  Operations act on the top of the stack and consume the value therein, potentially 
  producing a new value that gets pushed.

  When evaluated, the value on top of the stack is the result of the evaluation.
  If evaluation produces an error (e.g., conversion errors to num or bool)

  Evaluation of a selector occurs in a context from which some objects
  can be references for values out of a JSON structure for the object

  Selectors are represented as CUE arrays constrained as shown below

  References in a selector MUST be to only 
   $this
   $user
   $environment
   $deployment
   $resource

   objects, and must consist of paths into them.
   Those paths can reach into any of the structures of those objects as defined
   in each objects INFO section (info: structure returned with a get info op)

   The $this object will always exist and will represent the object on which
   the selector has been defined.

   The rest of the objects may, or may not exist, depending the kind of object
   $this is. For each case where a selector can be specified, the context objects available
   will be defined.
*/



#Selector_Resource: [...#Selector_Item_Resource]
#Selector_User    : [...#Selector_Item_User    ]
#Selector_Service : [...#Selector_Item_Service ]

a: #Selector & [1, 2, "$.this.that.there.where", "::dup", "::getor"]

From the spec we see that formally, a selector is a JSON array, whose items are just data, references, or operations.

5.12. Kumori Modules Marketplace

When registering a tenant we have seen that an npm registry can be configured to publish there the kumori modules that you will build in the platform. In this section, the endpoints related to module publishing and consumption will be described.

5.12.1. Publish Module

PUT /api/1.0-beta/tenant/<tenant>/marketplace/module

Publishes a module to the registry configured in the tenant.

  • Parameters: none

  • Request Body:

    • It expects a form data containing the following fields:

      • bundle: zip file containing a kumori module like the one discussed in previous sections.

      • bundle-target-kind: component | service, you must indicate whether the module to be publish contains a component or a service.

      • bundle-target-dir: the relative path in the bundle where the main artifact is located.

      • bundle-tags: a JSON array containing a list of strings.

  • Response body: Generic

5.12.2. List Modules

GET /api/1.0-beta/tenant/<tenant>/marketplace/module

Returs the list of all the modules the tenant has access to. It can also filter the result based on a few parameters.

  • Parameters:

    • name: string. Optional. Find closest match by artifact name

    • tags: JSON array. Optional. Array of tags the modules should contain.

    • domain: string. Optional. Filter modules under the given domain

    • limit: number. Optional. Pagination page size.

    • offset: number. Optional. Pagination offset.

  • Request Body: none

  • Response body:

    {
      pagination: {
        total:  number
        offset: number
      },
      items: [
        ...{
          name:          string
          domain:        string
          version:       string
          tags:          [...string]
          artifactTypes: "component" | "service"
        }
      ]
    }

5.12.3. Get Module Info

GET /api/1.0-beta/tenant/<tenant>/marketplace/module/schema

Gets detailed information about a publish module. It fails if no module is found with the parameters provided.

This endpoint also returns a JSON Schema of the artificat configuration.

  • Parameters:

    • domain: string. Domain of the module.

    • name: string. Name of the module.

    • version: string. Version of the module.

  • Request Body: none

  • Response body:

    {
      [artifact_name: string]: {
        kind: "component" | "service"
        schemas: [...#JSONSchema]
        roles: [...string]
      }
    }

5.12.4. Selector operations

Selector operations are explained in the comments. Each operation takes its arguments from the top of the stack, and pushes its results to the top of the stack.

For each operation we show its arity (args in, result out).

The array must be interpreted as this:

  1. The array is processed from left to right

  2. A non-operation item is pushed on the stack

  3. an operation item is executed on the stack state, modifying it.

5.12.5. References in selectors and the context

A selector execution is carried out within a context providing some top level objects, accessed with a string like $.<object>. Where <object>, in general, can vary depending where the selector is declared.

Selectors declared on the tenant selectEnvironmentService set of rules, have available to them, when preparing a deployment the tenant info (through the this object) the service info and the revision info (including the usage info), through the service object.

Selector declared on the tenant validateEnvironmentResource set of rules have available to them the environment info the tenant info (this) and the resource info.

Selector declared on the tenant validateEnvironmentUser set of rules have available to them the environment info, the tenant info (this) and the tenant user info.

Armed with such a context, complex rules (non-recursive) can be specified and they are run as follows:

When a new revision of a service is requested:

  1. If the environment for the service is not set, the set of rules in selectEnvironmentService are evaluated for each environment. When on an environment, the context environment object is set to that environment info. The set of environments for which a true is obtained is labeled as accepted, becoming candidates for the next phase

  2. If the environment has already been set, the set of rules in selectEnvironmentService is run on the environment selected. If all of them pass, we proceed labeling the environment as accepted.

  3. We repeat the above with the selectAcceptEnvironmentService list on the set of environments that did not pass. The set of environments passing this phase is labeled as requiring.

  4. For each environment that passed the above selections (as either accepted or requiring), we run the set of selectors in validateEnvironmentResource for each resource the revision needs. If a resource passes, we run the selector of the resource, if any. If all resources pass the environment stays as candidate with the same label it had, if any resource fails, the environment is removed from the candidate list.

  5. Finally, for all surviving candidate environments we run the validateEnvironmentUser list of selectors on the tenant user info of the user making the request. If no environment passes, we fail the request. If more than one environment is still candidate, we select the environment with the most vcpus extant, priorizing accepted environments.

  6. If the selected environment is labeled as accepted, it is setup as the environment of the deployment, and we proceed to deploy the revision. If, on the contrary, it is labeled as requiring, we assign the environment, but leave the revision as not accepted, and wait for an explicit acceptance call.

The above process can be used to implement access control for users.

Execution of selectors, in most cases, will be fast and low complexity