Resource Classes
Overview
Resource Classes provide a way of specializing Resource Types . Developers can set the class of a Resource alongside the type in their Score File . Platform teams can create and describe the class of a Resource and match it via Matching Criteria .
An Internal Developer Platform (IDP) often offers many “flavors” of a particular Resource Type. For example, there might be multiple flavors of S3 bucket available:
- An
external
S3 bucket might be open to the public internet, e.g. to allow for downloading of assets. - A
sensitive
S3 bucket might be configured to be encrypted and only accessible via a limited set of roles, e.g. for storing confidential data. - A
volatile
S3 bucket where retention time is less than 24 hours, e.g. for holding intermediate data from other processes.
In all cases, an S3 bucket will be provisioned but they’ll be configured differently. Each of these flavors is represented by a “class”.
Every Resource always has a class. If the developer does not choose a class, the class default
is used. Classes can also be
set explicitly
within the Platform Orchestrator, providing developers with more context about the available resource types.
Using classes in a Score file
A developer can select the class of a Resource by adding a class
property to the Resource dependency in their Score file.
...
resources:
confidential-bucket:
type: s3
class: sensitive
Matching a Resource Definition to classes
Resource Definitions can be matched to classes using Matching Criteria. See the Matching Criteria documentation for more details on how this works.
Matching Criteria allow for a single Resource Definition to be matched to multiple classes. This can be very useful to model some scenarios.
-
Use a single Resource Definition for all classes in development environments, and only specialize in higher environments.
For example, it might not make sense to actually make an
external
S3 bucket externally accessible in development. Instead the same S3 bucket Resource Definition could cover both theinternal
andexternal
classes.This could be modeled with three Resource Definitions:
# Dev version that matches both external and internal
apiVersion: entity.humanitec.io/v1b1
kind: Definition
metadata:
id: dev-s3-bucket
entity:
...
criteria:
- env_type: development
class: internal
- env_type: development
class: external
# Production version that matches just internal
apiVersion: entity.humanitec.io/v1b1
kind: Definition
metadata:
id: prod-internal-s3-bucket
entity:
...
criteria:
- env_type: production
class: internal
# Production version that matches just external
apiVersion: entity.humanitec.io/v1b1
kind: Definition
metadata:
id: prod-external-s3-bucket
entity:
...
criteria:
- env_type: production
class: external
-
Using the class placeholder to programmatically handle the class in a single Resource Definition.
For example, one of the inputs to a Resource Definition using the Terraform Driver could be
${context.res.class}
. This could then be used to specialize the Resource within the Terraform code.
Choosing Resource classes
Classes are a powerful construct. Care should be taken to carefully choose classes that allow for maximum flexibility as the platform and use cases develop.
We recommend following these best practice guidelines:
-
Classes should be descriptive, not prescriptive
A class should describe the purpose of the specialization rather than how the specialization is implemented.
For example, rather than defining the machine requirements for a postgres database with a class such as
4cpu-32Gb
, describe the usage such ashigh-volume
.This means the class can be satisfied differently in different contexts.
high-volume
in a development environment is much lower volume thanhigh-volume
in production. Whereas being prescriptive about the machine cannot be varied across environments. -
Classes should be general rather than specific
It might be tempting to choose classes for all possible combinations of configurations of a Resource type. However, remember that every class is an additional flavor of a Resource that needs to be maintained.
It’s always possible to further specialize a Resource Definition for a particular app later. This means that a small number of more general classes can often suffice for developers needing to get started. By the time the workload makes it to production, there may be deviations from the standard Resource Definitions.
-
Class names should follow a consistent format
Class names often have to perform double duty. Most commonly, this means covering both the intention of the Resource and access requirements. Examples for an S3 Resource Type could include
ro-sensitive
andrw-sensitive
.It’s important to be consistent across your organization so that class names are predictable and self-descriptive.
Class notation in Resource Descriptors
Resource Descriptors are used when working with the Resource Graph . They are used in Resource References , Co-provisioning , Resource Selectors , and in error messages.
When using Resource References, co-provisioning, or selectors, you can optionally specify the class alongside the type
and id
. This involves adding a .
after the type, followed by the class name.
As with the ID in Resource Descriptors, if the class is not specified, the class of the Resource that includes the descriptor is used. This allows for classes to be passed through the Resource Graph.
For example:
s3.sensitive
postgres.high-volume
dns.default
Creating a Resource Class
Resource classes don’t have to be created explicitly; you can start using them in Matching Criteria and it will work as well. However, to harness the full potential of the orchestrator, it is beneficial to create them. As the orchestrator resolves all classes during deployment, it’s impossible to calculate them earlier. Therefore, setting these explicitly allows for better validation and provides more context about the available resources for developers.
To ensure backwards compatibility, the connection between resource classes and matching criteria is kept minimal, allowing the use of classes in matching criteria without explicitly creating them. However, if you choose to create resource classes, tools like humctl can validate their presence. It is essential to create all classes, excluding default ones, to successfully validate the Score file.
humctl api post "/orgs/${HUMANITEC_ORG}/resources/types/${RESOURCE_TYPE}/classes" \
-d '{
"id": "sensitive",
"description": "Encrypted bucket for storing confidential data"
}'
Where the following environment variables are set:
Variable | Example | Description |
---|---|---|
HUMANITEC_ORG |
my-org |
The Humanitec organization the Application is in. |
RESOURCE_TYPE |
s3 |
The Humanitec resource type. |
curl "https://api.humanitec.io/orgs/${HUMANITEC_ORG}/resources/types/${RESOURCE_TYPE}/classes" \
-X POST \
-H "Authorization: Bearer ${HUMANITEC_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"id": "sensitive",
"description": "Encrypted bucket for storing confidential data"
}'
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_TYPE |
s3 |
The Humanitec resource type. |
resource "humanitec_resource_class" "resource_class" {
id = "sensitive"
resource_type = "s3"
description = "Encrypted bucket for storing confidential data"
}
Next steps
- Learn more about Matching Criteria .
- Learn more about the Resource Graph .