Custom Resource Types

Overview

The Platform Orchestrator provides a catalog of built-in Resource Types as a basis for creating Resource Definitions.

You may extend that catalog for your Humanitec Organization and create a Custom Resource Type to:

  • Provide a new Resource Type if the type you need is not available in the list of built-in Resource Types
  • Override a built-in Resource Type such as s3 to expand or modify its inputs or outputs

Managing Custom Resource Types requires the Administrator role in the Organization.

Define a Custom Resource Type

A Resource Type is made up of metadata as well as an inputs and outputs schema. A definition for a new type with no inputs and two outputs may look like this:

type: my-org/my-custom-type
use: direct
name: Demo Type
category: "Demo category"
inputs_schema:
  additionalProperties: false
  type: object
outputs_schema:
  properties:
    values:
      properties:
        host:
          description: The IP address or hostname
          title: Host
          type: string
        port:
          description: The port on the host
          maximum: 65535
          minimum: 0
          title: Port
          type: integer
      required:
      - host
      - port
      type: object
  type: object

Refer to the API documentation  for details on each property. More examples are shown at the bottom of this page.

To see existing Resource Type definitions, you can inspect the definitions of all built-in Resource Types, and Custom Types that may already have been added, using this CLI command:

humctl get resource-type -o yaml

Override an existing Resource Type

A Custom Resource Type may override one of the existing, built-in Resource Types, e.g. s3. To do so, create a definition with a type of my-org/<existing-type> like so:

type: my-org/s3
...

The override needs to completely define the new type. There is no merging or inheritance of the override and the built-in type definition. An override may therefore alter the structure of a built-in type in any way. In particular, it may define its own inputs and outputs. To keep existing inputs or outputs of the built-in type, the override needs to define them anew.

To obtain the definition of any built-in type to use as a starting point for an override, e.g. s3, use this command:

humctl get resource-type -o yaml \
  | yq -r '.[] | select (.metadata.type == "s3")'

Define inputs and outputs

The inputs_schema and outputs_schema properties define the Resource Inputs (those supplied as resource params in Score for direct Resource Types) and the Outputs of the Resource Type.

Both properties are based on JSON Schema , so you can use all of the JSON Schema vocabulary to construct your Resource Type, like required properties, allowable values etc. Some examples are shown further down in this section.

The Resource Inputs in inputs_schema are always non-secret values defined like this:

type: my-org/my-custom-type
use: direct
...
# A plain string property
inputs_schema:
  properties:
    myProperty:
      description: A demo string property
      title: My property
      type: string

The Resource Input declared this way can then be supplied a value via Score:

apiVersion: score.dev/v1b1
...
resources:
  demo:
    type: my-custom-type
    params:
      # Supplying a value for the Resource Input "myProperty"
      myProperty: some-value

The Resource outputs in outputs_schema distinguish between secret and non-secret outputs as secrets and values:

type: my-org/my-custom-type
use: direct
...
outputs_schema:
  additionalProperties: false
  type: object
  properties:
    # Secret outputs
    secrets:
      properties:
        key:
          description: A secret account key
          title: Account Key
          type: string
      type: object
    # Non-secret outputs
    values:
      properties:
        account:
          description: The account to use
          title: Account
          type: string
      type: object

These Resource outputs can be queried in Score (for direct Resource Types):

apiVersion: score.dev/v1b1
...
containers:
  demo:
    variables:
      KEY: ${resources.demo.key}
      ACCOUNT: ${resources.demo.account}
resources:
  demo:
    type: my-custom-type

Some useful JSON Schema  usage is shown in these examples. They apply to inputs_schema and outputs_schema properties alike.

Allow any additional input or output property
inputs_schema:
  additionalProperties: true
  type: object
outputs_schema:
  additionalProperties: true
  type: object
A plain string input property restricted to certain values
inputs_schema:
  properties:
    myEnumProperty:
      description: A demo string property limited to certain values
      title: My enum property
      type: string
      # Allow only the values defined here
      enum:
      - "allowed-value-1"
      - "allowed-value-2"
    myPatternProperty:
      description: A demo string property limited in length and by RegEx
      title: My pattern property
      type: string
      # Define length and pattern constraints
      minLength: 3
      maxLength: 44
      pattern": "^[a-z]{3,44}$"
Required inputs or outputs
outputs_schema:
  additionalProperties: false
  type: object
  properties:
    # Secret outputs
    secrets:
      properties:
        key:
          description: A secret account key
          title: Account Key
          type: string
      # Make "key" a required output
      required:
      - key
      type: object
Nested/complex properties
inputs_schema:
  additionalProperties: false
  type: object
  properties:
    myParentProperty:
      additionalProperties: false
      description: A parent property
      title: My parent property
      type: object
      properties:
        type: object
        mySubProperty:
          description: A sub property
          title: My sub property
          type: string

Portal UI grouping

When configuring a Resource Definition via the the Humanitec Portal, a Custom Resource Type will be shown in the list of all types and grouped according to its Resource category, e.g. category: datastore.

Portal UI configuration

The Humanitec Portal will display a form with input fields for all the outputs defined in the outputs_schema of the Resource Type being used, e.g. when using the Echo Driver to create a Resource Definition of that Resource Type. The Portal will use the properties of each output like this:

  • The title and description are used to label the field
  • A required output is displayed with a *
  • A secrets output is displayed with a lock icon

You can optionally customize the UI layout using uiHints and uiGroups.

  • uiHints.order defines the property order within the form, or within the uiGroup it is assigned to
  • uiHints.group assigns the property to a uiGroup
  • uiHints.width defines the relative width for the field within a uiGroup of type row. The default value is 1

Define uiGroups in the outputs_schema using these properties:

  • uiGroups.<group>.order defines the order of the group within the form
  • uiGroups.<group>.type defines the type of the group to be a section (a collection of rows) or a row
  • uiGroups.<group>.title defines the title of the a group of type: section
  • uiGroups.<group>.section assigns a group of type: row to a section
Example outputs schema using UI groups

This outputs schema uses UI groups to create two sections holding three output properties.

outputs_schema:
  properties:
    values:
      properties:
        name:
          description: The name of the topic that the workload should use.
          title: Topic Name
          type: string
          uiHints:
            group: topic
            order: 1
        host:
          description: The IP address or hostname the cluster is available on.
          title: Host
          type: string
          uiHints:
            group: hostport
            order: 1
            width: 2
        port:
          description: The port on the host that the cluster is available on.
          maximum: 65535
          minimum: 0
          title: Port
          type: integer
          uiHints:
            group: hostport
            order: 2
      required:
      - name
      - host
      - port
      type: object
  type: object
  uiGroups:
    topic:
      order: 1
      title: Topic
      type: section
    cluster:
      order: 2
      title: Cluster
      type: section
    hostport:
      order: 2
      section: cluster
      type: row

Register a Custom Resource Type

For the CLI or API commands in this and the following sections, set these environment variables to prepare the command execution:

# Set your Humanitec Organization ID
export HUMANITEC_ORG=my-org
# Set an API token (API only)
export HUMANITEC_TOKEN=token-value

Place the Custom Resource Type definition in YAML format in a file named custom-resource-type.yaml.

Prepare the command payload in JSON format:

export PAYLOAD=$(yq custom-resource-type.yaml -o json)

humctl api post "/orgs/${HUMANITEC_ORG}/resources/types" \
  -d "$PAYLOAD"

curl "https://api.humanitec.io/orgs/${HUMANITEC_ORG}/resources/types" \
  -X POST \
  -H "Authorization: Bearer $HUMANITEC_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$PAYLOAD"

Use a Custom Resource Type in Resource Definitions

Once registered, you can use a Custom Resource Type in Resource Definitions like a regular built-in type.

Create Resource Definitions based on a Custom Resource Type

You base a Resource Definition on a Custom Resource Type by using its fully qualified name (e.g. my-org/my-custom-type) as the type:

# Resource Definition using a newly defined type
apiVersion: entity.humanitec.io/v1b1
kind: Definition
entity:
  type: my-org/my-custom-type
  ...
# Resource Definition using an override type for "s3"
apiVersion: entity.humanitec.io/v1b1
kind: Definition
entity:
  type: my-org/s3
  ...

Using Custom Resource Types in references, selectors, co-provisioning

Resource Definitions for a built-in type (e.g. s3) and a corresponding override type (my-org/s3) can exist in parallel and even have the same matching criteria. Authors of Resource Definitions need to be specific when requesting a type in Resource References, Resource Selectors, or co-provisioning.

A mix of Resources of a built-in type and its override type in a Resource Graph is possible.

Given a Custom Resource Type my-org/my-custom-type and an override Custom Resource Type my-org/s3, these Resource References and selectors are valid:

# Request a "my-org/my-custom-type" Resource of the current Resource class and ID
${resources['my-org/my-custom-type'].outputs.region}

# Request a "my-org/s3" (an override type) Resource of the current Resource class and ID
${resources['my-org/s3'].outputs.region}

# Request a "s3" (the standard built-in type) Resource of the current Resource class and ID
${resources['s3'].outputs.region}

# Request a "my-org/s3" Resource of the Resource class "sensitive"
${resources['my-org/s3.sensitive'].outputs.region}

# Select a "my-org/s3" Resource that is depended on by a workload of the current Resource class and ID
${resources['workload>my-org/s3'].outputs.region}

# Co-provision a "my-org/my-custom-type" Resource of the current Resource class and ID
provision:
  my-org/my-custom-type:
    is_dependent: true

Introducing an override Custom Resource Type

Score matching for overridden types

Whenever at least one Resource Definition exists using an override of a built-in type, resource requests from Score to that type (e.g. s3) are always expanded to request the override (my-org/s3).

apiVersion: score.dev/v1b1
...
resources:
  # This resource request will be expanded to the override type "my-org/s3"
  # if a Resource Definition of that override type exists
  my-bucket:
    type: s3

Be aware that in this setup:

  • Only Resource Definitions based on the override type (my-org/s3) are considered for matching resource requests from Score for the corresponding built-in type (s3)
  • Even if there is a Resource Definition for the built-in type (s3) having the proper matching criteria, it is not considered for matching

When introducing Resource Definitions for override types, make sure to provide Definitions for all previously used matching contexts to avoid failing Deployments.

New Active Resource

If a Deployment has previously been using a Resource Definition based on a built-in type, e.g. s3, then with the introduction of a Resource Definition of the override type the Platform Orchestrator will create a new Active Resource of the override type my-org/s3 on the next Deployment. It will also keep the previous Active Resource of type s3 to support potential rollbacks.

Using the humctl resources active-resource-usage CLI command to observe Active Resources will show this setup:

$ humctl resources active-resource-usage
ResType         Class   ResID                                  Usage           Last referencing deployment     Last referencing 
s3              default modules.demo.externals.my-bucket       1 deploy ago    183dd45d31191a1a                4m56.986245652s
my-org/s3       default modules.demo.externals.my-bucket       current deploy  183dd49e29138a51                17.947954245s

Output of the ${context.res.type} placeholder

The Placeholder ${context.res.type} in a Resource Definition based on an override type will return the fully qualified custom type, e.g. my-org/s3.

If your Resource Definition code has been using the output of this Placeholder to name or access any stateful data for an Active Resource, make sure to use the part following the / only to continue using the same data in the follow-up Resource.

Use a Custom Resource Type in Score

Custom Resource Types are used like built-in types when requesting resources in Score. Always use the simple name for the type, i.e. without the Organization ID prefix, for both newly created types as well as overridden built-in types.

apiVersion: score.dev/v1b1
...
resources:
  # Requesting a resource of a newly defined Custom Resource Type
  demo:
    type: my-custom-type
  # Requesting a resource of a built-in Resource Type which may or may not be
  # overriden by a Custom Resource Type
  my-bucket:
    type: s3

Whether or not a built-in Resource Type such as s3 is overridden in the Organization is transparent to Score users.

For the general handling of Resource Inputs and outputs of Custom Resource Types Score, see Define inputs and outputs.

Any newly added or changed Resource Inputs or outputs introduced by an override Custom Resource Type are available in Score. E.g. if the type my-org/s3 defines an additional output object-lock-enabled, it can be queried by the requesting Workload like any other output:

apiVersion: score.dev/v1b1
...
containers:
  hello:
    image: .
    variables:
      LOCK: ${resources.my-bucket.object-lock-enabled}
resources:
  my-bucket:
    type: s3

Starting from humctl version 0.39.4, you can use these Score-related CLI commands with Custom Resource Types:

# Note: In the presence of a Resource Definition based on an override type,
# e.g. "my-org/s3" for "s3", this command will display a value of "s3"
# because that is the type to use in Score
humctl score available-resource-types

humctl score validate score.yaml

humctl score deploy -f score.yaml

View a Custom Resource Type

These commands view the Resource Type named my-custom-type.

YAML format:

humctl get resource-type -o yaml \
  | yq -r ".[] | select (.metadata.type == \"$HUMANITEC_ORG/my-custom-type\")"

JSON format:

humctl get resource-type -o json \
  | jq -r ".[] | select(.metadata.type == \"$HUMANITEC_ORG/my-custom-type\")"

YAML format:

curl -s "https://api.humanitec.io/orgs/${HUMANITEC_ORG}/resources/types" \
  -X GET \
  -H "Authorization: Bearer $HUMANITEC_TOKEN" \
  | jq -r ".[] | select(.type == \"$HUMANITEC_ORG/my-custom-type\")" \
  | yq -P

JSON format:

curl -s "https://api.humanitec.io/orgs/${HUMANITEC_ORG}/resources/types" \
  -X GET \
  -H "Authorization: Bearer $HUMANITEC_TOKEN" \
  | jq -r ".[] | select(.type == \"$HUMANITEC_ORG/my-custom-type\")"

Update a Custom Resource Type

You can update a Custom Resource Type at any time, including when Resource Definitions exist using that type, and when there are Active Resources of such Resource Definitions.

Custom Resource Types are not versioned. Updates are effective immediately, i.e. for all future Deployments referencing the type.

Note: you need to provide JSON format for the CLI and API calls shown below. We recommend to maintain sources in YAML for better readability and transform them on the fly as shown.

For a partial update, define the update JSON snippet like this:

# Example: change the Custom Resource Type `my-org/my-custom-type` to have a `use:` of `indirect`
export PAYLOAD='{"use": "indirect"}'

For a full update, read the entire Custom Resource Type definition from a file:

# Read the Custom Resource Type definition from a file and convert to JSON
export PAYLOAD=$(yq custom-resource-type.yaml -o json)

humctl api patch "/orgs/${HUMANITEC_ORG}/resources/types/${HUMANITEC_ORG}%2Fmy-custom-type" \
  -d "$PAYLOAD"

curl -s "https://api.humanitec.io/orgs/${HUMANITEC_ORG}/resources/types/${HUMANITEC_ORG}%2Fmy-custom-type" \
  -X PATCH \
  -H "Authorization: Bearer $HUMANITEC_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$PAYLOAD"

Delete a Custom Resource Type

These commands delete the Custom Resource Type my-org/my-custom-type. Deletion will be disallowed if there is a Resource Definition using that type.

humctl api delete "/orgs/${HUMANITEC_ORG}/resources/types/${HUMANITEC_ORG}%2Fmy-custom-type"

curl -s "https://api.humanitec.io/orgs/${HUMANITEC_ORG}/resources/types/${HUMANITEC_ORG}%2Fmy-custom-type" \
  -X DELETE \
  -H "Authorization: Bearer $HUMANITEC_TOKEN" \
  -H "Content-Type: application/json"

Examples

New Custom Resource Type example

This Custom Resource Type introduce the milvus and milvus-instance types for the Milvus database .

Custom Resource Type "milvus"
type: my-org/milvus
use: direct
category: datastore
inputs_schema:
  additionalProperties: false
  properties:
    extensions:
      additionalProperties:
        additionalProperties: false
        properties:
          schema:
            type: string
          version:
            type: string
        type: object
      type: object
  type: object
name: Milvus
outputs_schema:
  properties:
    secrets:
      properties:
        password:
          description: The password for the user or role.
          title: Password
          type: string
          uiHints:
            group: database
            order: 3
        username:
          description: The user or role that the workload should use to connect to
            the database.
          title: User / Role
          type: string
          uiHints:
            group: database
            order: 2
      required:
      - username
      - password
      type: object
    values:
      properties:
        host:
          description: The IP address or hostname the instance is available on.
          title: Host
          type: string
          uiHints:
            group: hostport
            order: 1
            width: 2
        name:
          description: The name of the database that the workload should connect to.
          title: Name
          type: string
          uiHints:
            group: database
            order: 1
        port:
          description: The port on the host that the instance is available on.
          maximum: 65535
          minimum: 0
          title: Port
          type: integer
          uiHints:
            group: hostport
            order: 2
      required:
      - name
      - host
      - port
      type: object
  uiGroups:
    database:
      order: 1
      title: Database
      type: section
    hostport:
      order: 2
      section: instance
      type: row
    instance:
      order: 2
      title: Instance
      type: section
  type: object
Custom Resource Type "milvus-instance"
category: datastore
type: my-org/milvus-instance
use: indirect
inputs_schema:
  properties:
    extensions:
      additionalProperties:
        additionalProperties: false
        properties:
          schema:
            type: string
          version:
            type: string
        type: object
      type: object
  type: object
name: Milvus Instance
outputs_schema:
  properties:
    secrets:
      properties:
        password:
          description: The password for the user or role.
          title: Password
          type: string
          uiHints:
            group: database
            order: 3
        username:
          description: The user or role that the workload should use to connect to
            the database.
          title: User / Role
          type: string
          uiHints:
            group: database
            order: 2
      type: object
    values:
      properties:
        host:
          description: The IP address or hostname the instance is available on.
          title: Host
          type: string
          uiHints:
            group: hostport
            order: 1
            width: 2
        name:
          description: The name of the database that the workload should connect to.
          title: Name
          type: string
          uiHints:
            group: database
            order: 1
        port:
          description: The port on the host that the instance is available on.
          maximum: 65535
          minimum: 0
          title: Port
          type: integer
          uiHints:
            group: hostport
            order: 2
      type: object
  uiGroups:
    database:
      order: 1
      title: Database
      type: section
    hostport:
      order: 2
      section: instance
      type: row
    instance:
      order: 2
      title: Instance
      type: section
  type: object

Override Custom Resource Type example

This Custom Resource Type overrides the built-in type s3 to provide an additional output object-lock-enabled.

Override of the "s3" type
category: datastore
type: my-org/s3
use: direct
name: S3 Bucket Override
inputs_schema:
  additionalProperties: false
  type: object
outputs_schema:
  properties:
    values:
      properties:
        arn:
          description: The Amazon Resource Name (ARN) of the S3 Bucket
          title: ARN
          type: string
          uiHints:
            group: bucket
            order: 3
        bucket:
          description: The globally unique name for the bucket.
          title: S3 Bucket Name
          type: string
          uiHints:
            group: bucket
            order: 1
        region:
          description: The AWS region the bucket is hosted in.
          title: AWS Region
          type: string
          uiHints:
            group: bucket
            order: 2
        # Additional output in this Custom Resource Type
        object-lock-enabled:
          description: Indicates whether this bucket has an Object Lock configuration enabled.
          title: Object Lock enabled true/false
          type: boolean
          uiHints:
            group: bucket
            order: 4
      required:
      - region
      - bucket
      type: object
  uiGroups:
    bucket:
      order: 1
      title: S3 Bucket
      type: section
  type: object
Top