Resource Definitions
Overview
A Resource Definition defines how and when a Resource should be provisioned. It is made up of the Resource Type, Resource Drivers and its inputs, along with a set of Matching Criteria to define when to select the Resource Definition. Resource Definitions are generally created and managed by the Platform Team.
Several pre-defined default Resource Definitions are available by default in all Organizations. These definitions are managed by Humanitec but can be enabled or disabled as needed.
A Resource Definition holds the following:
Parameter | Description |
---|---|
Resource Type | The type of resource that the Resource Definition provisions |
Resource Driver | The ID of the Resource Driver to use when provisioning the resource |
Driver Inputs | Driver specific inputs that are taken by the Driver alongside the Resource inputs |
Matching Criteria | The criteria used to select which Resource Definition of a specific Resource Type |
Example
This example shows the core elements of a Resource Definition:
apiVersion: core.api.humanitec.io/v1
kind: Definition
metadata:
id: stg-redis
entity:
name: stg-redis
type: redis
driver_type: humanitec/terraform
driver_account: aws-stg-infra
driver_inputs:
values:
source:
url: https://my-git-host.com/my-project/redis-elasticache-example.git
rev: refs/tags/v.1.3.5
variables:
# Redacted for brevity
criteria:
- env_type: staging
- The
type
specifies the Resource Type asredis
- The
driver_type
specifies the Driver to use. Here, it is the Terraform Driver - The
driver_account
references a Cloud Account for providing access to the target infrastructure for the Driver - The
driver_inputs
specify the inputs the specific Driver needs to operate. In this case, the Resource Definition provides data on finding the Terraform code to be executed, and potentially more inputs which are redacted for brevity - The
criteria
specify the matching criteria , i.e. in which context to use this exact Resource Definition. Here, it is for Deployments into Environments of typestaging
Working with inputs and outputs
A Resource Definition may receive inputs to parameterize the Resource to be provisioned. It configures and calls a Driver internally to perform the actual provisioning, and may produce outputs when done. More technical details follow in the sections below. These general principles apply:
-
Within Score, only inputs and outputs defined by the schema of the respective Resource Type can be used.
-
All
params
passed in to aresource
in Score become available as Resource inputs in the Resource Definition used to provision that Resource. The restriction for the Resource Type input schema applies, see 1.
Score file snippet using resource inputs and outputs
...
containers:
demo:
variables:
# Use the output "host" which is part of the "dns" Resource Type's output schema
MY_HOSTNAME: ${resources.my-dns.host}
...
resources:
my-dns:
type: dns
users-route:
type: route
# Provide resource inputs via "params" according to the "route" Resource Type's input schema
params:
# Use the output "host" which is part of the "dns" Resource Type's output schema
host: ${resources.api-dns.host}
path: /users
port: 80
-
A Resource Definition passes Driver inputs to the Driver it uses, following that Driver’s input schema.
-
A Resource Definition may produce any output regardless of its Resource Type. In the Resource Graph , i.e. between Resources, a Resource Definition has access to any output another referenced Resource may produce.
Resource Definition snippet showing the use of a custom output from a referenced Resource
...
driver_type: template
driver_inputs:
values:
templates:
init: |
# Reading the output "region" from a Resource of type "config"
region: ${resources.config.outputs.region}
...
Note: the
config
Resource Type
does not need to have region
in its output schema, and it does not.
-
However, only the outputs defined by the Resource Type’s output schema will be available in Score (see 1.).
-
A Resource Definition cannot push inputs to another referenced Resource in the Resource Graph. It can only pull data from other Resources through the Graph by querying their outputs.
Schematically, inputs and outputs can flow like this:
%%{ init: { 'flowchart': { 'curve': 'linear' } } }%%
flowchart LR
subgraph resourceGraph[Resource Graph]
direction LR
workload(Workload) --> rgResource1(Resource 1)
workload --> rgResource2(Resource 2) -->|references| rgResource3(Resource 3)
rgResource3 -.->|May use any output<br/>regardless of output schema| rgResource2
end
score -.->|Provide Resource inputs<br/>via Score "params:" following<br/>Resource Type input schemas<br/>of Resource 1 and 2| resourceGraph
subgraph score[Score file]
direction TB
subgraph scoreContainers["containers:" section]
scoreContainer1(container)
end
scoreContainers ~~~ scoreResources
subgraph scoreResources["resources:" section]
direction TB
scoreResource2 -.->|"May use outputs from<br/>Resource Type output schema<br/>of Resource 2<br/>(and vice versa)"| scoreResource1
scoreResource1(Resource 1) ~~~ scoreResource2(Resource 2)
end
end
scoreResources -.->|May use outputs from<br/>Resource Type output schemas<br/>of Resource 1 and 2<br/>as container variables| scoreContainer1
resourceGraph -.->|Provide outputs following<br/>Resource Type output schemas<br/>of Resource 1 and 2| score
classDef invisible fill:#00000000,stroke:#00000000
class scoreContainers,scoreResources nested
Resource inputs
Resource inputs are provided via Score file through the params
property of a Score resource
. Allowable resource inputs are defined through the input schema of the Resource Type, e.g. for the
route
Resource Type
:
...
resources:
users-route:
type: route
params:
host: ${resources.api-dns.host}
path: /users
port: 80
The mechanism for referencing Resource inputs within the Resource Definition depends on the Driver:
In the
Template Driver
, use the format .resource.<input>
:
driver_type: humanitec/template
driver_inputs:
values:
templates:
init: |
host: {{ .resource.host | quote }}
In the
Terraform Driver
, declare a Terraform variable
named like the Resource input and use in your code as required:
driver_type: humanitec/terraform
driver_inputs:
values:
# Using an inline Terraform script for simplicity, same approach for external code in Git repo
script: |
variable "host" {}
# use as var.host in your code
In the
Container Driver
, the container receives the Resource Inputs as a JSON object stored in the file at the path specified by the Driver in the RESOURCE_INPUTS_FILE
environment variable:
{
"host": "my-host.my-domain.com"
}
Driver inputs
Driver inputs are the inputs a Resource Definition provides to the Driver that performs the provisioning of a Resource. Allowable Driver inputs are defined through the input schema of the respective Driver. Use the driver_inputs
property of the Resource Definition to set their values.
You can find the input schema on the Driver’s page within the
Drivers
section or, if no dedicated page is available, by querying the API and inspecting the inputs_schema
property for the Driver of choice:
# Obtain the input schema for the "dns-cloudflare" Driver
humctl get driver -o yaml \
| yq '.[] | select(.metadata.id == "dns-cloudflare") | .entity.inputs_schema'
Different Drivers used for the same Resource Type may require different inputs based on how they work, i.e. they may have different input schemas.
For example, provisioning a dns
resource with the
humanitec/dns-cloudflare
Driver
requires the Cloudflare Zone ID and the parent domain to be specified as Driver inputs:
...
entity:
type: dns
driver_type: humanitec/dns-cloudflare
driver_inputs:
values:
zone_id: some-zone-id
domain: my-domain.com
...
Whereas the
humanitec/dns-wildcard
Driver
only requires the parent domain as a Driver input:
...
entity:
type: dns
driver_type: humanitec/dns-wildcard
driver_inputs:
values:
domain: staging.example.com
...
The Driver inputs can make use of any
Placeholder
marked with driver_inputs
to insert parts of the deployment context at deploy time:
...
driver_inputs:
values:
domain: ${context.app.id}.example.com
...
Some Drivers have flexible capabilities for working with Driver inputs.
The Echo Driver will accept any top level Driver input and return is as an output.
Example
redis-secret-refs.yaml
(
view on GitHub
)
:
apiVersion: entity.humanitec.io/v1b1
kind: Definition
metadata:
id: redis-echo
entity:
name: redis-echo
type: redis
driver_type: humanitec/echo
driver_inputs:
values:
host: 0.0.0.0
port: 6379
secret_refs:
password:
store: my-gsm
ref: redis-password
username:
store: my-gsm
ref: redis-user
criteria:
- {}
The
Template Driver
lets you set any additional top level Driver input and then reference it in the templates as .driver.values.<input>
or .driver.secrets.<input>
.
Example
config.yaml
(
view on GitHub
)
:
# This Resource Definition pulls credentials for a container image registry from a secret store
# and creates a Kubernetes Secret of kubernetes.io/dockerconfigjson type
apiVersion: entity.humanitec.io/v1b1
kind: Definition
metadata:
id: regcred-config
entity:
driver_type: humanitec/template
name: regcred-config
type: config
criteria:
- class: default
# This res_id must be used from a referencing Resource Definition to request this config Resource
res_id: regcred
driver_inputs:
# These secret references read the credentials from a secret store
secret_refs:
password:
ref: regcred-password
# Replace this value with the secret store id that's supplying the password
store: FIXME
username:
ref: regcred-username
# Replace this value with the secret store id that's supplying the username
store: FIXME
values:
secret_name: regcred
# Replace this value with the servername of your registry
server: FIXME
templates:
# The init template is used to prepare the "dockerConfigJson" content
init: |
dockerConfigJson:
auths:
{{ .driver.values.server | quote }}:
username: {{ .driver.secrets.username | toRawJson }}
password: {{ .driver.secrets.password | toRawJson }}
manifests:
# The manifests template creates the Kubernetes Secret
# which can then be used in the workload "imagePullSecrets"
regcred-secret.yaml:
data: |
apiVersion: v1
kind: Secret
metadata:
name: {{ .driver.values.secret_name }}
data:
.dockerconfigjson: {{ .init.dockerConfigJson | toRawJson | b64enc }}
type: kubernetes.io/dockerconfigjson
location: namespace
outputs: |
secret_name: {{ .driver.values.secret_name }}
Outputs
Every Resource Type has an output schema. A Resource Definition for that type should at least produce the outputs defined by that schema. It may produce any additional outputs.
All outputs may be used within the Resource Graph, i.e. between one Resource and another. However, only the outputs defined by the Resource Type output schema can be used in Score.
Drivers do not have an output schema.
Resource output used in Score
score.yaml
(
view on GitHub
)
:
# Example Score file for a Workload that has three routes from one DNS name
apiVersion: score.dev/v1b1
metadata:
name: routes-example
service:
ports:
www:
port: 80
targetPort: 8080
containers:
webserver:
image: my-webservice:latest
resources:
api-dns:
type: dns
users-route:
type: route
params:
host: ${resources.api-dns.host}
path: /users
port: 80
products-route:
type: route
params:
host: ${resources.api-dns.host}
path: /products
port: 80
checkout-route:
type: route
params:
host: ${resources.api-dns.host}
path: /checkout
port: 80
Within the Resource Graph, any outputs can be used. For example, this Resource Definition of type config
produces an output that is being used in another Resource Definition via a
Resource Reference
.
Resource Definitions producing and consuming an output
Resource Definition producing an output cost_center_id
:
config-labels.yaml
(
view on GitHub
)
:
# This "config" type Resource Definition provides the value for the sample label
apiVersion: entity.humanitec.io/v1b1
kind: Definition
metadata:
id: app-config
entity:
name: app-config
type: config
driver_type: humanitec/template
driver_inputs:
values:
templates:
# Returns a sample output named "cost_center_id" to be used as a label
outputs: |
cost_center_id: my-example-id
# Match the resource ID "app-config" so that it can be requested via that ID
criteria:
- res_id: app-config
Resource Definition consuming the output:
custom-namespace-with-dynamic-labels.yaml
(
view on GitHub
)
:
# This Resource Definition references the "config" resource to use its output as a label
# and adds another label taken from the Deployment context
apiVersion: entity.humanitec.io/v1b1
kind: Definition
metadata:
id: custom-namespace-with-label
entity:
name: custom-namespace-with-label
type: k8s-namespace
driver_type: humanitec/template
driver_inputs:
values:
templates:
init: |
name: ${context.app.id}-${context.env.id}
manifests: |
namespace.yaml:
location: cluster
data:
apiVersion: v1
kind: Namespace
metadata:
labels:
env_id: ${context.env.id}
cost_center_id: ${resources['config.default#app-config'].outputs.cost_center_id}
name: {{ .init.name }}
outputs: |
namespace: {{ .init.name }}
# Set matching criteria as required
criteria:
- {}
A Resource output is either secret or non-secret. A secret output of a Resource can only be used as a secret input to another Resource.
All non-secret outputs of an Active Resource can be observed in the Humanitec Portal as the Resource “Values”, or queried programmatically. Visit
Active Resources
for details. For the shell commands shown on that page, check the resource
property in the generated response to see the outputs.
The mechanism for producing outputs within the Resource Definition depends on the Driver.
For the Echo Driver , all Driver inputs automatically become outputs.
This Resource Definition produces the non-secret outputs host
and port
, and the secret output password
.
...
entity:
driver_type: humanitec/echo
driver_inputs:
# Non-secret values
values:
host: my-hostname.example.com
port: 6379
# Secret value using a secret reference
secret_refs:
password:
store: my-store
ref: my-password
...
For the
Template Driver
, use the values.templates.outputs
and values.templates.secrets
properties to generate outputs.
This Resource Definition produces the non-secret output referencedVal
and the secret output password
.
...
entity:
driver_type: humanitec/template
driver_inputs:
# Using a secret reference to read from a secret store
secret_refs:
password:
ref: my-password
store: my-store
values:
referencedVal: ${resources.config.outputs.someVal}
templates:
# Non-secret outputs
outputs: |
referencedVal: {{ .driver.values.referencedVal }}
# Secret outputs
secrets: |
password: {{ .driver.secrets.password }}
...
For the
Terraform Driver
, declare
output
values
in your Terraform code.
This Resource Definition produces the non-secret output some-output
and the secret output some-secret-output
.
...
entity:
driver_type: humanitec/terraform
driver_inputs:
values:
# Using an inline Terraform script for simplicity
# Showing a non-secret and a secret output
script: |
output "some-output" {
value = some_tf_resource.example.id
}
output "some-secret-output" {
value = some_tf_resource.example.password
sensitive = true
}
...
In the
Container Driver
, the container should store non-sensitive and sensitive outputs as a JSON object in two files whose path is specified by the Driver in the environment variable OUTPUTS_FILE
and SECRET_OUTPUTS_FILE
environment variables, respectively:
{
"host": "my-hostname.example.com",
"port": 6379
}
A Custom Driver may add any output to a Resource using whichever technology is used to implement the Driver, as long as the output data is compliant with the Driver API Specification .
Matching criteria
Matching Criteria provide a way for Humanitec to select a Resource Definition for provisioning a resource in a given Resource Context. Each Resource Definition can have 0 or more Matching Criteria associated with it. Each of the Matching Criteria defines 0, 1 or more parts of the context that must match in order for a Resource Definition to be selected. When selecting with Matching Criteria, the most specific one is selected. In general, this means if all the Matching Criteria fully matching the context, the Matching Criteria Rule with the most specific element filled is chosen. If there is a tie, the next most specific elements are compared and so on until one is chosen.
A Resource Definition with no Matching Criteria will not be considered.
Criteria specificity
In general, the parts of the matching criteria are in order from least specific to most specific as follows:
Environment Type < Application ID < Environment ID < Resource ID < Resource Class
This means that Matching Criteria containing a Resource ID will always be more specific than any Matching Criteria that does not contain a Resource ID.
Mathematically, the specificity of Matching Criteria can be calculated by summing together weights for each part of the Matching Criteria:
Part | Weight |
---|---|
Environment Type |
1 |
Application ID |
2 |
Environment ID |
4 |
Resource ID |
8 |
Resource Class |
16 |
An empty Matching Criteria would score 0, one containing just an Environment ID
would score 4 and one containing an Application ID
and Environment Type
would score 3.
The Matching Criteria with the highest total weight are the most specific.
Example
Consider an Application called awesome-app
with multiple Environments of type development
. There is a shared environment called dev
used by all developers and multiple “PR” environments which are created automatically when a PR is created in GitHub. The dev
environment should be accessible via a stable DNS name of dev-api.awesome.app
while the preview environments should be available on randomly generated subdomains such as fjs92.awesome.app
or 4ij76s.awesome.app
.
Two Resource Definitions of type dns
are created:
static-dev-dns
- always returns the same DNS name ofdev-api.awesome.app
random-dev-dns
- generates a random subdomain
They have the following Matching Criteria:
Resource Definition | Environment Type | Application ID | Environment ID | Resource ID | Resource Class |
---|---|---|---|---|---|
static-dev-dns |
awesome-app |
dev |
shared.api-dns |
default |
|
random-dev-dns |
development |
awesome-app |
shared.api-dns |
default |
When a deployment occurs in the dev
environment, Humanitec will attempt to provision a dns
resource with ID shared-api-dns
. Looking at the Matching Criteria for Resource Definitions of type dns
it will return static-dev-dns
and random-dev-dns
. In this case, the static-dev-dns
would be chosen because its Matching Criteria are more specific.
When a deployment occurs in a PR environment, only the random-dev-dns
Resource Definition would be returned.
Manage Resource Definitions
Resource Definitions can be managed via the UI, CLI, API and using the Humanitec Terraform provider.
All actions involving Resource Definitions require the user to have the Administrator role in the Organization.
-
Click the Resource Management menu item from the left-hand navigation to open the Resource Management screen.
-
Select + Add resource definition, on the top left of the screen.
-
Select the Resource Type for the Resource Definition you want to create in the dialog.
-
Select the appropriate Driver from the list.
-
Supply the Driver ID any additional inputs that are required by the Driver.
-
Select Add, in the bottom right of the dialog.
- Create a file defining the Resource definition you want to create:
cat << EOF > my-def.yaml
apiVersion: entity.humanitec.io/v1b1
kind: Definition
metadata:
id: example-ns-def
entity:
type: k8s-namespace
name: k8s-namespace
driver_type: humanitec/echo
driver_inputs:
values:
namespace: \${context.app.id}-\${context.env.id}
EOF
- Use the
humctl create
command to create the resource definition in the organization defined by your configured context:
humctl create -f my-def.yaml
curl "https://api.humanitec.io/orgs/${HUMANITEC_ORG}/resources/defs" \
-X POST \
-H "Authorization: Bearer ${HUMANITEC_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"id": "example-ns-def",
"type": "k8s-namespace",
"driver_type": "humanitec/echo",
"driver_inputs": {
"values": {
"namespace": "${context.app.id}-${context.env.id}"
}
}
}'
Where the following environment variables are set:
Variable | Example | Description |
---|---|---|
HUMANITEC_TOKEN |
lsakdjhcals |
A Humanitec token of a user with at least Developer permission on the Application. |
HUMANITEC_ORG |
my-org |
The Humanitec organization the Application is in. |
resource "humanitec_resource_definition" "example-ns-def" {
driver_type = "humanitec/echo"
id = "example-ns-def"
name = "example-ns-def"
type = "k8s-namespace"
driver_inputs = {
values = {
"namespace" = "$${context.app.id}-$${context.env.id}"
}
}
}
Manage Resource Definitions by selecting Resources from the main navigation menu.
Create definitions for Resources
- On the Resources Management screen, assuming the Resource Type you’re looking for is not already in the hot-list, click Show all resources.
- From the grid, select the Resource Type that you need to create a Definition for.
- In the modal dialog, fill out the
id
field and select the appropriate Driver from the list. - Supply any additional inputs that are required by the Driver.
- Select Create.
Delete definitions for Resources
- On the Resources Management screen, select the .. at the end of the row of the Resource Definition that you wish to delete.
- Select Delete.
- In the modal dialog, choose Delete to confirm.
Using secret references
You can use
secret references
to read secrets from secret stores, and pass them to Drivers as driver_inputs
. Go
here
to see examples.
Default Resource Definitions
The Humanitec Platform Orchestrator provides a collection of default Resource Definitions for commonly provisioned resources. These are available by default in all organizations and do not require explicit matching criteria as they will match any supported resources that don’t have a custom Resource Definition and matching criteria.
Default Resource Definitions are available for:
base-env
- No special behavior.workload
- No special behavior.k8s-namespace
- Generates a random namespace name.ingress
- Provisions a Kubernetesnetworking.k8s.io/v1
Ingress
using the Ingress driver.logging
- Defaults to Kubernetes logging.route
- See Routes for more information on how Route resources are handled.dns
- Provisions a new random DNS subdomain of thenewapp.io
domain using thenewapp-io-dns
Driver .tls-cert
- Provides a default TLS certificate secret for thenewapp.io
domain using thenewapp-io-tls
Driver .- (Deprecated)
k8s-cluster
- Provisions an ephemeral and temporary Kubernetes cluster credential. - (Deprecated)
postgres
- Provisions an ephemeral and temporary Postgres database.
Default Resource Definitions can be disabled through either the Web UI or CLI. Note that this will cause any existing active resources that use this definition to be re-provisioned on the next deployment.
-
Click the Resource Management menu item from the left-hand navigation to open the Resource Management screen.
-
Select the “Default Humanitec” resource definition that you wish to disable.
-
Select the Matching Criteria tab.
-
Toggle the Active toggle to Inactive. Or the opposite to enable the definition again.
- Use the
humctl api
command to disable the default definition by clearing its matching criteria:
humctl api PUT /orgs/${HUMANITEC_ORG}/resources/defs/default-humanitec-dns/criteria --data '[]'
- Or re-enable the default definition by adding a catch-all matching criteria.
humctl api PUT /orgs/${HUMANITEC_ORG}/resources/defs/default-humanitec-dns/criteria --data '[{"class": "default"}]'
Where the following environment variables are set:
Variable | Example | Description |
---|---|---|
HUMANITEC_ORG |
my-org |
The Humanitec organization to act on. |
Examples
- See our example collection of Resource Definitions show their usage for a wide range of use cases.
- See how to add common infrastructure Resources to your platform based on our Resource Packs .