Environment Manager Developer Guide - Design Guidelines - Rafay Product Documentation

Design Guidelines

Environment template

Resource template

output "public_subnets" {
    value = module.vpc.public_subnets
}

Drivers/Workflow Handlers

Agents

IaC code

Variables

variable "eks_devworkspace_cluster_routing_sufix" {
  type = string
  description = "*Required: Supports multi-tenancy will generate url with the suffix provided e.g. for suffix devworkspace.dev.rafay-edge.net and name provided tem1 for every workspace we will get name <workspaceid>.<name>-devworkspace.dev.rafay-edge.net"
  validation {
      condition = (length(var.eks_devworkspace_cluster_routing_sufix)>0)
      error_message = "Value is required and a hosted zone should be created."
  }
}
locals {
  name = "${replace(var.name, "_", "-")}-eks-cluster"
  namespace = "${local.name}-ns"
  aws_public_subnet = "${local.name}-public-subnet"
  tags = merge(var.tags,{  
      ManagedBy = "Rafay Eaas"
      Resource = "${local.name}"
  })
}
locals {
  rds_oracle_name = "${substr(local.name,1,4)}${random.name_randomizer.hex}"
  tags = merge(var.tags,{  
      OriginalName = "${local.name}"
  })
}
resource "random" "name_randomizer"{
  keepers = {
      # Generate a new id each time we switch to a new name
      name = local.name
  }
  byte_length = 4
}

if string variables

<resource_name>_<purpose>

if boolean variable

<resource_name>_<purpose>_enabled

if numeric

<resource_name>_<purpose>_<count|max|min>

Guidelines for changing variables

Guidelines for Naming Outputs

  1. Descriptive Naming:

The name of an output should clearly describe the property it represents and be more structured than free-form naming 02. Recommended Structure:

| | | | --- | --- | | <br>1<br> | <br> Use the format {name}\_{type}\_{attribute}, where:<br> |

  1. {name}: Represents the resource or data source name

  2. Example for data: aws_subnet "private" → private

  3. Example for resource: aws_vpc_endpoint_policy "test" → test

  4. {type}: Represents the resource or data source type without the provider prefix

  5. Example for data: aws_subnet "private" → subnet

  6. Example for resource: aws_vpc_endpoint_policy "test" → vpc_endpoint_policy

  7. {attribute}: Represents the specific attribute returned by the output

  8. Generic Naming for Complex Outputs: For outputs returning values derived from multiple resources or interpolation functions, {name} and {type} should be as generic as possible

  9. Avoid including unnecessary prefixes

  10. Plural Names for Lists: If the output is a list, use a plural form in the name

  11. Include Descriptions: Always provide a description for outputs, even if the purpose seems self-evident

  12. Handling Sensitive Outputs: Avoid marking arguments as sensitive unless you have complete control over their usage across all modules

  13. Formatting Recommendations: Use hyphens (-) in argument values and in contexts where the value will be human-readable, such as DNS names for RDS instances

Resource

resource "aws_route_table" "<resource_name>_public" {
}
resource "aws_route_table" "<resource_name>_public" {
}

Use

resource "aws\_route\_table" "public" {}

Do Not Use

resource "aws\_route\_table" "public\_route\_table" {}

resource "aws\_route\_table" "public\_aws\_route\_table" {}

Helm Charts driven environment templates

Helm Provider Compatibility

Values File Management

Dry-Run Upgrade

Chart Versioning

Helm Dependencies

Subcharts: If your Helm chart includes dependencies (subcharts), verify whether those dependencies are also being upgraded and check for any breaking changes they might introduce. Avoid using subcharts when possible, as they may not be accessible in self-hosted environments.

Drivers Inputs and Outputs

Inputs

Dynamic inputs (expressions) can be configured for all fields within the driver. Users can supply values for these inputs during environment deployment, define them as variables within the config context attached to the driver, or specify them inline. These expressions are evaluated in the execution context during workflow execution.

Expression Format:

The standard format for expressions is:

(current.input.<variable-name>)

Here, <variable-name> represents the name of the variable whose value is being referenced.

Example:

If a variable is named api_key, it can be referenced in the configuration as:

(current.input.api_key)

Sample Input File:

{
  "kind": "Driver",
  "metadata": {
    "name": "driver-test"
  },
  "spec": {
    "config": {
      "type": "container",
      "container": {
        "image": "jira:latest",
        "arguments": [
          "-ticket_id",
          "$(current.input.ticket_id)$"
        ],
        "env_vars": {
          "API_KEY": "$(current.input.api_key)$"
        }
      }
    },
    "inputs": [
      {
        "data": {
          "variables": [
            {
              "name": "api_key",
              "value": "********",
              "valueType": "text"
            },
            {
              "name": "ticket_id",
              "value": "1234",
              "valueType": "text"
            }
          ]
        }
      }
    ]
  }
}

Outputs

Driver outputs can be used as inputs for subsequent drivers within a workflow.

These outputs can be referenced using expressions tailored to specific hooks.

Example Expression:

(resource.test_resource.hook.onInit.create_ticket.output.ticket_id)

This expression retrieves the ticket_id value generated by the create_ticket hook during the onInit stage of the test_resource resource template. The ticket_id can then be used in subsequent workflow steps.

Detailed Example:

A resource template named test_resource includes two hooks:

  1. onInit Hook:
    • Creates a Jira ticket.
    • Uploads an output.json file containing: {"ticket_id": "1234"}.
  2. onCompletion Hook:
    • References the data from the onInit hook using the output expression:

(resource.test_resource.hook.onInit.create_ticket.ticket_id).

This allows the ticket_id created during the onInit stage to be reused during the onCompletion stage or in other steps of the workflow.

{
  "kind": "ResourceTemplate",
  "metadata": {
    "name": "test_resource"
  },
  "spec": {
    "hooks": {
      "onInit": [
        {
          "name": "create_ticket",
          "type": "driver",
          "driver": {
            "data": {
              "config": {
                "type": "container",
                "container": {
                  "image": "jira:custom",
                  "commands": ["create"]
                }
              }
            }
          }
        }
      ],
      "onCompletion": [
        {
          "name": "send_ticket",
          "type": "driver",
          "driver": {
            "data": {
              "config": {
                "type": "container",
                "container": {
                  "image": "jira:custom",
                  "arguments": [
                    "--ticket-id",
                    "$(resource.test_resource.hook.onInit.create_ticket.output.ticket_id)$"
                  ]
                }
              }
            }
          }
        }
      ]
    }
  }
}

Resource Template Lifecycle Hooks

(resource.resource_name.hook.onInit.hook_name.output)

(resource.resource_name.hook.onSuccess.hook_name.output)

(resource.resource_name.hook.onFailure.hook_name.output)

(resource.resource_name.hook.onCompletion.hook_name.output)

Terraform Lifecycle Hooks

Deploy Hooks

(resource.template_name.hook.deploy.init.before.hook_name.output)

(resource.template_name.hook.deploy.init.after.hook_name.output)

(resource.template_name.hook.deploy.plan.before.hook_name.output)

(resource.template_name.hook.deploy.plan.after.hook_name.output)

(resource.template_name.hook.deploy.apply.before.hook_name.output)

(resource.template_name.hook.deploy.apply.after.hook_name.output)

(resource.template_name.hook.deploy.output.before.hook_name.output)

(resource.template_name.hook.deploy.output.after.hook_name.output)

Destroy Hooks

(resource.template_name.hook.destroy.init.before.hook_name.output)

(resource.template_name.hook.destroy.init.after.hook_name.output)

(resource.template_name.hook.destroy.plan.before.hook_name.output)

(resource.template_name.hook.destroy.plan.after.hook_name.output)

(resource.template_name.hook.destroy.destroy.before.hook_name.output)

(resource.template_name.hook.destroy.destroy.after.hook_name.output)

Environment Template Lifecycle Hooks

(environment.hook.onInit.hook_name.output)

(environment.hook.onSuccess.hook_name.output)

(environment.hook.onFailure.hook_name.output)

(environment.hook.onCompletion.hook_name.output)

The expression (resource.resource_name.task.task_name.output) is used to access the output of a specific task within a resource template. Here's a breakdown of its components:

This expression enables subsequent tasks or components to utilize the output of a previous task, facilitating data flow and dependency management within the workflow.

Loading and Launching Templates

Environment Manager provides the following interfaces for loading the environment templates into Rafay Platform and launching them.

Best Practices

  1. Centralized Storage: Store all your templates and related configurations in a private GitHub repository to establish a single source of truth
  2. Automated Loading: Use a unified pipeline configuration to automate the process of loading changes from Git to your system, ensuring seamless updates to your project
  3. Leveraging Swagger APIs: If you are building a platform or marketplace for custom templates outside of Rafay and need to load them into your Rafay organization’s project, Swagger APIs provide an efficient and scalable solution.