From bfa0c5acfe1437007a4f3b52adbe55cef6d28eb8 Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Fri, 31 Mar 2023 13:20:54 -0500 Subject: [PATCH] Add metadata block to the agent (#112) --- docs/resources/agent.md | 15 +++++++++++++ provider/agent.go | 43 ++++++++++++++++++++++++++++++++++++ provider/agent_test.go | 48 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/docs/resources/agent.md b/docs/resources/agent.md index 1333d5bb..9ee5c1d0 100644 --- a/docs/resources/agent.md +++ b/docs/resources/agent.md @@ -51,6 +51,7 @@ resource "kubernetes_pod" "dev" { - `dir` (String) The starting directory when a user creates a shell session. Defaults to $HOME. - `env` (Map of String) A mapping of environment variables to set inside the workspace. - `login_before_ready` (Boolean) This option defines whether or not the user can (by default) login to the workspace before it is ready. Ready means that e.g. the startup_script is done and has exited. When enabled, users may see an incomplete workspace when logging in. +- `metadata` (Block List) Each "metadata" block defines a single item consisting of a key/value pair. This feature is in alpha and may break in future releases. (see [below for nested schema](#nestedblock--metadata)) - `motd_file` (String) The path to a file within the workspace containing a message to display to users when they login via SSH. A typical value would be /etc/motd. - `shutdown_script` (String) A script to run before the agent is stopped. The script should exit when it is done to signal that the workspace can be stopped. - `shutdown_script_timeout` (Number) Time in seconds until the agent lifecycle status is marked as timed out during shutdown, this happens when the shutdown script has not completed (exited) in the given time. @@ -64,4 +65,18 @@ resource "kubernetes_pod" "dev" { - `init_script` (String) Run this script on startup of an instance to initialize the agent. - `token` (String, Sensitive) Set the environment variable "CODER_AGENT_TOKEN" with this token to authenticate an agent. + +### Nested Schema for `metadata` + +Required: + +- `interval` (Number) The interval in seconds at which to refresh this metadata item. +- `key` (String) The key of this metadata item. +- `script` (String) The script that retrieves the value of this metadata item. + +Optional: + +- `display_name` (String) The user-facing name of this value. +- `timeout` (Number) The maximum time the command is allowed to run in seconds. + diff --git a/provider/agent.go b/provider/agent.go index 4d628927..c5797081 100644 --- a/provider/agent.go +++ b/provider/agent.go @@ -137,6 +137,49 @@ func agentResource() *schema.Resource { Optional: true, Description: "This option defines whether or not the user can (by default) login to the workspace before it is ready. Ready means that e.g. the startup_script is done and has exited. When enabled, users may see an incomplete workspace when logging in.", }, + "metadata": { + Type: schema.TypeList, + Description: "Each \"metadata\" block defines a single item consisting of a key/value pair. This feature is in alpha and may break in future releases.", + ForceNew: true, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Description: "The key of this metadata item.", + ForceNew: true, + Required: true, + }, + "display_name": { + Type: schema.TypeString, + Description: "The user-facing name of this value.", + ForceNew: true, + Optional: true, + }, + "script": { + Type: schema.TypeString, + Description: "The script that retrieves the value of this metadata item.", + ForceNew: true, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "timeout": { + Type: schema.TypeInt, + Description: "The maximum time the command is allowed to run in seconds.", + ForceNew: true, + Optional: true, + }, + "interval": { + Type: schema.TypeInt, + Description: "The interval in seconds at which to refresh this metadata item. ", + ForceNew: true, + Required: true, + }, + }, + }, + }, }, } } diff --git a/provider/agent_test.go b/provider/agent_test.go index 445ed75b..2069247b 100644 --- a/provider/agent_test.go +++ b/provider/agent_test.go @@ -71,7 +71,7 @@ func TestAgent(t *testing.T) { }) } -func TestAgentInstance(t *testing.T) { +func TestAgent_Instance(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ Providers: map[string]*schema.Provider{ @@ -111,3 +111,49 @@ func TestAgentInstance(t *testing.T) { }}, }) } + +func TestAgent_Metadata(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + Providers: map[string]*schema.Provider{ + "coder": provider.New(), + }, + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" { + url = "https://example.com" + } + resource "coder_agent" "dev" { + os = "linux" + arch = "amd64" + metadata { + key = "process_count" + display_name = "Process Count" + script = "ps aux | wc -l" + interval = 5 + timeout = 1 + } + } + `, + Check: func(state *terraform.State) error { + require.Len(t, state.Modules, 1) + require.Len(t, state.Modules[0].Resources, 1) + + resource := state.Modules[0].Resources["coder_agent.dev"] + require.NotNil(t, resource) + + t.Logf("resource: %v", resource.Primary.Attributes) + + attr := resource.Primary.Attributes + require.Equal(t, "1", attr["metadata.#"]) + require.Equal(t, "process_count", attr["metadata.0.key"]) + require.Equal(t, "Process Count", attr["metadata.0.display_name"]) + require.Equal(t, "ps aux | wc -l", attr["metadata.0.script"]) + require.Equal(t, "5", attr["metadata.0.interval"]) + require.Equal(t, "1", attr["metadata.0.timeout"]) + return nil + }, + }}, + }) +}