From 19b61acad397d2b16f5be02189cdae501a5d1c52 Mon Sep 17 00:00:00 2001 From: Florian Blampey Date: Fri, 7 Jun 2024 10:37:40 +0200 Subject: [PATCH] add preheat instance (issue #445) (#446) Signed-off-by: flbla Co-authored-by: github-actions[bot] --- client/preheat_instance.go | 34 ++++ docs/resources/preheat_instance.md | 67 ++++++++ .../authentification.tf | 8 + .../harbor_preheat_instance/basic.tf | 5 + models/preheat_instance.go | 24 +++ provider/provider.go | 1 + provider/resource_preheat__instance.go | 161 ++++++++++++++++++ provider/resource_preheat_instance_test.go | 101 +++++++++++ templates/resources/preheat_instance.md.tmpl | 56 ++++++ 9 files changed, 457 insertions(+) create mode 100644 client/preheat_instance.go create mode 100644 docs/resources/preheat_instance.md create mode 100644 examples/resources/harbor_preheat_instance/authentification.tf create mode 100644 examples/resources/harbor_preheat_instance/basic.tf create mode 100644 models/preheat_instance.go create mode 100644 provider/resource_preheat__instance.go create mode 100644 provider/resource_preheat_instance_test.go create mode 100644 templates/resources/preheat_instance.md.tmpl diff --git a/client/preheat_instance.go b/client/preheat_instance.go new file mode 100644 index 0000000..e2d1899 --- /dev/null +++ b/client/preheat_instance.go @@ -0,0 +1,34 @@ +package client + +import ( + "github.com/goharbor/terraform-provider-harbor/models" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func PreheatInstanceBody(d *schema.ResourceData) models.PreheatInstance { + authInfo := models.PreheatInstanceAuthInfo{} + authMode := d.Get("auth_mode").(string) + + switch authMode { + case "NONE": + // No token, username, or password + case "BASIC": + authInfo.Username = d.Get("username").(string) + authInfo.Password = d.Get("password").(string) + case "OAUTH": + authInfo.Token = d.Get("token").(string) + } + + body := models.PreheatInstance{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + Vendor: d.Get("vendor").(string), + Endpoint: d.Get("endpoint").(string), + AuthMode: authMode, + AuthInfo: authInfo, + Enabled: d.Get("enabled").(bool), + Default: d.Get("default").(bool), + Insecure: d.Get("insecure").(bool), + } + return body +} diff --git a/docs/resources/preheat_instance.md b/docs/resources/preheat_instance.md new file mode 100644 index 0000000..7a82017 --- /dev/null +++ b/docs/resources/preheat_instance.md @@ -0,0 +1,67 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "harbor_preheat_instance Resource - terraform-provider-harbor" +subcategory: "" +description: |- + +--- + +# harbor_preheat_instance (Resource) + + + +## Example Usage + +### Basic Usage + +```terraform +resource "harbor_preheat_instance" "example" { + name = "example-preheat-instance" + vendor = "dragonfly" + endpoint = "http://example.com" +} +``` + +### Usage with Authentication + +```terraform +resource "harbor_preheat_instance" "example" { + name = "example-preheat-instance" + vendor = "dragonfly" + endpoint = "http://example.com" + auth_mode = "BASIC" + username = "example-user" + password = "example-password" +} +``` + +## Schema + +### Required + +- `name` (String) The name of the preheat instance. +- `vendor` (String) The vendor of the preheat instance. Must be either "dragonfly" or "kraken". +- `endpoint` (String) The endpoint of the preheat instance. + +### Optional + +- `description` (String) The description of the preheat instance. Defaults to an empty string. +- `auth_mode` (String) The authentication mode for the preheat instance. Must be either "NONE", "BASIC", or "OAUTH". Defaults to "NONE". +- `username` (String) The username for the preheat instance. Required if `auth_mode` is "BASIC". Defaults to an empty string. +- `password` (String, Sensitive) The password for the preheat instance. Required if `auth_mode` is "BASIC". Defaults to an empty string. +- `token` (String, Sensitive) The token for the preheat instance. Required if `auth_mode` is "OAUTH". Defaults to an empty string. +- `default` (Boolean) Whether the preheat instance is the default instance. Defaults to false. +- `enabled` (Boolean) Whether the preheat instance is enabled. Defaults to true. +- `insecure` (Boolean) Whether to allow insecure connections to the preheat instance. Defaults to false. + +### Read-Only + +- `id` (String) The ID of the preheat instance. + +## Import + +The `harbor_preheat_instance` resource can be imported using the preheat instance ID. + +```sh +terraform import harbor_preheat_instance.example /p2p/preheat/instances/example-preheat-instance +``` \ No newline at end of file diff --git a/examples/resources/harbor_preheat_instance/authentification.tf b/examples/resources/harbor_preheat_instance/authentification.tf new file mode 100644 index 0000000..d526db2 --- /dev/null +++ b/examples/resources/harbor_preheat_instance/authentification.tf @@ -0,0 +1,8 @@ +resource "harbor_preheat_instance" "example" { + name = "example-preheat-instance" + vendor = "dragonfly" + endpoint = "http://example.com" + auth_mode = "BASIC" + username = "example-user" + password = "example-password" +} diff --git a/examples/resources/harbor_preheat_instance/basic.tf b/examples/resources/harbor_preheat_instance/basic.tf new file mode 100644 index 0000000..d60c6c4 --- /dev/null +++ b/examples/resources/harbor_preheat_instance/basic.tf @@ -0,0 +1,5 @@ +resource "harbor_preheat_instance" "example" { + name = "example-preheat-instance" + vendor = "dragonfly" + endpoint = "http://example.com" +} diff --git a/models/preheat_instance.go b/models/preheat_instance.go new file mode 100644 index 0000000..dd6bf0b --- /dev/null +++ b/models/preheat_instance.go @@ -0,0 +1,24 @@ +package models + +var PathPreheatInstance = "/p2p/preheat/instances" + +type PreheatInstance struct { + ID int `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Vendor string `json:"vendor"` + Endpoint string `json:"endpoint"` + AuthMode string `json:"auth_mode"` + AuthInfo PreheatInstanceAuthInfo `json:"auth_info"` + Status string `json:"status"` + Enabled bool `json:"enabled"` + Default bool `json:"default"` + Insecure bool `json:"insecure"` + SetupTimestamp int64 `json:"setup_timestamp"` +} + +type PreheatInstanceAuthInfo struct { + Token string `json:"token,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` +} diff --git a/provider/provider.go b/provider/provider.go index 062e90e..41f2c7d 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -66,6 +66,7 @@ func Provider() *schema.Provider { "harbor_garbage_collection": resourceGC(), "harbor_purge_audit_log": resourcePurgeAudit(), "harbor_label": resourceLabel(), + "harbor_preheat_instance": resourcePreheatInstance(), "harbor_immutable_tag_rule": resourceImmutableTagRule(), }, DataSourcesMap: map[string]*schema.Resource{ diff --git a/provider/resource_preheat__instance.go b/provider/resource_preheat__instance.go new file mode 100644 index 0000000..05a2e91 --- /dev/null +++ b/provider/resource_preheat__instance.go @@ -0,0 +1,161 @@ +package provider + +import ( + "encoding/json" + "fmt" + + "github.com/goharbor/terraform-provider-harbor/client" + "github.com/goharbor/terraform-provider-harbor/models" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourcePreheatInstance() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "vendor": { + Type: schema.TypeString, + Required: true, + ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { + v := val.(string) + if v != "dragonfly" && v != "kraken" { + errs = append(errs, fmt.Errorf("%q must be either 'dragonfly' or 'kraken', got: %s", key, v)) + } + return + }, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Default: "", + }, + "endpoint": { + Type: schema.TypeString, + Required: true, + }, + "auth_mode": { + Type: schema.TypeString, + Optional: true, + Default: "NONE", + ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { + v := val.(string) + if v != "NONE" && v != "BASIC" && v != "OAUTH" { + errs = append(errs, fmt.Errorf("%q must be either 'NONE' or 'BASIC' or 'OAUTH', got: %s", key, v)) + } + return + }, + }, + "username": { + Type: schema.TypeString, + Optional: true, + Default: "", + }, + "password": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + Default: "", + }, + "token": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + Default: "", + }, + "default": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "insecure": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + Create: resourcePreheatInstanceCreate, + Read: resourcePreheatInstanceRead, + Update: resourcePreheatInstanceUpdate, + Delete: resourcePreheatInstanceDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + } +} + +func resourcePreheatInstanceCreate(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Client) + body := client.PreheatInstanceBody(d) + + _, headers, _, err := apiClient.SendRequest("POST", models.PathPreheatInstance, body, 201) + if err != nil { + return err + } + + id, err := client.GetID(headers) + d.SetId(id) + return resourcePreheatInstanceRead(d, m) +} + +func resourcePreheatInstanceRead(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Client) + + resp, _, respCode, err := apiClient.SendRequest("GET", d.Id(), nil, 200) + if respCode == 404 && err != nil { + d.SetId("") + return nil + } else if err != nil { + return fmt.Errorf("resource not found %s", d.Id()) + } + + var jsonData models.PreheatInstance + err = json.Unmarshal([]byte(resp), &jsonData) + if err != nil { + return fmt.Errorf("Resource not found %s", d.Id()) + } + + d.Set("name", jsonData.Name) + d.Set("description", jsonData.Description) + d.Set("vendor", jsonData.Vendor) + d.Set("endpoint", jsonData.Endpoint) + d.Set("auth_mode", jsonData.AuthMode) + d.Set("enabled", jsonData.Enabled) + d.Set("default", jsonData.Default) + d.Set("insecure", jsonData.Insecure) + d.Set("username", jsonData.AuthInfo.Username) + d.Set("password", jsonData.AuthInfo.Password) + d.Set("token", jsonData.AuthInfo.Token) + + return nil +} + +func resourcePreheatInstanceUpdate(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Client) + body := client.PreheatInstanceBody(d) + + _, _, _, err := apiClient.SendRequest("PUT", d.Id(), body, 200) + if err != nil { + return err + } + + return resourcePreheatInstanceRead(d, m) +} + +func resourcePreheatInstanceDelete(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Client) + + _, _, respCode, err := apiClient.SendRequest("DELETE", d.Id(), nil, 200) + if respCode != 404 && err != nil { // We can't delete something that doesn't exist. Hence the 404-check + return err + } + return nil +} diff --git a/provider/resource_preheat_instance_test.go b/provider/resource_preheat_instance_test.go new file mode 100644 index 0000000..d6bb95d --- /dev/null +++ b/provider/resource_preheat_instance_test.go @@ -0,0 +1,101 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/goharbor/terraform-provider-harbor/client" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +const harborPreheatInstanceMain = "harbor_preheat_instance.main" + +func testAccCheckPreheatInstanceDestroy(s *terraform.State) error { + apiClient := testAccProvider.Meta().(*client.Client) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "harbor_preheat_instance" { + continue + } + + resp, _, _, err := apiClient.SendRequest("GET", rs.Primary.ID, nil, 404) + if err != nil { + return fmt.Errorf("Resource was not deleted \n %s", resp) + } + } + + return nil +} + +func TestAccPreheatInstanceUpdate(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPreheatInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPreheatInstanceBasic(), + Check: resource.ComposeTestCheckFunc( + testAccCheckResourceExists(harborPreheatInstanceMain), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "name", "test"), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "vendor", "dragonfly"), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "endpoint", "http://example.com"), + ), + }, + { + Config: testAccCheckPreheatInstanceUpdate(), + Check: resource.ComposeTestCheckFunc( + testAccCheckResourceExists(harborPreheatInstanceMain), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "name", "test-updated"), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "vendor", "kraken"), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "endpoint", "http://example-updated.com"), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "auth_mode", "BASIC"), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "username", "test-user"), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "password", "test-password"), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "default", "true"), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "enabled", "false"), + resource.TestCheckResourceAttr( + harborPreheatInstanceMain, "insecure", "true"), + ), + }, + }, + }) +} + +func testAccCheckPreheatInstanceBasic() string { + return fmt.Sprintf(` + resource "harbor_preheat_instance" "main" { + name = "test" + vendor = "dragonfly" + endpoint = "http://example.com" + } + `) +} + +func testAccCheckPreheatInstanceUpdate() string { + return fmt.Sprintf(` + resource "harbor_preheat_instance" "main" { + name = "test-updated" + vendor = "kraken" + endpoint = "http://example-updated.com" + auth_mode = "BASIC" + username = "test-user" + password = "test-password" + default = true + enabled = false + insecure = true + } + `) +} diff --git a/templates/resources/preheat_instance.md.tmpl b/templates/resources/preheat_instance.md.tmpl new file mode 100644 index 0000000..c02d86e --- /dev/null +++ b/templates/resources/preheat_instance.md.tmpl @@ -0,0 +1,56 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "harbor_preheat_instance Resource - terraform-provider-harbor" +subcategory: "" +description: |- + +--- + +{{/* This template serves as a starting point for documentation generation, and can be customized with hardcoded values and/or doc gen templates. + +For example, the {{ .SchemaMarkdown }} template can be used to replace manual schema documentation if descriptions of schema attributes are added in the provider source code. */ -}} + +# harbor_preheat_instance (Resource) + + + +## Example Usage + +### Basic Usage + +{{tffile "examples/resources/harbor_preheat_instance/basic.tf"}} + +### Usage with Authentication + +{{tffile "examples/resources/harbor_preheat_instance/authentification.tf"}} + +## Schema + +### Required + +- `name` (String) The name of the preheat instance. +- `vendor` (String) The vendor of the preheat instance. Must be either "dragonfly" or "kraken". +- `endpoint` (String) The endpoint of the preheat instance. + +### Optional + +- `description` (String) The description of the preheat instance. Defaults to an empty string. +- `auth_mode` (String) The authentication mode for the preheat instance. Must be either "NONE", "BASIC", or "OAUTH". Defaults to "NONE". +- `username` (String) The username for the preheat instance. Required if `auth_mode` is "BASIC". Defaults to an empty string. +- `password` (String, Sensitive) The password for the preheat instance. Required if `auth_mode` is "BASIC". Defaults to an empty string. +- `token` (String, Sensitive) The token for the preheat instance. Required if `auth_mode` is "OAUTH". Defaults to an empty string. +- `default` (Boolean) Whether the preheat instance is the default instance. Defaults to false. +- `enabled` (Boolean) Whether the preheat instance is enabled. Defaults to true. +- `insecure` (Boolean) Whether to allow insecure connections to the preheat instance. Defaults to false. + +### Read-Only + +- `id` (String) The ID of the preheat instance. + +## Import + +The `harbor_preheat_instance` resource can be imported using the preheat instance ID. + +```sh +terraform import harbor_preheat_instance.example /p2p/preheat/instances/example-preheat-instance +``` \ No newline at end of file