From 7d71d148e4da271e83da26c90497c072c23372e2 Mon Sep 17 00:00:00 2001 From: Stamatis Katsaounis Date: Fri, 22 Dec 2023 23:37:55 +0200 Subject: [PATCH] Add resource pool resources --- docs/data-sources/resource_pool.md | 36 +++++ docs/resources/resource_pool.md | 44 ++++++ .../maas_resource_pool/data-source.tf | 8 ++ .../resources/maas_resource_pool/import.sh | 2 + .../resources/maas_resource_pool/resource.tf | 4 + maas/data_source_maas_resource_pool.go | 46 ++++++ maas/data_source_maas_resource_pool_test.go | 46 ++++++ maas/provider.go | 2 + maas/resource_maas_resource_pool.go | 135 ++++++++++++++++++ maas/resource_maas_resource_pool_test.go | 130 +++++++++++++++++ 10 files changed, 453 insertions(+) create mode 100644 docs/data-sources/resource_pool.md create mode 100644 docs/resources/resource_pool.md create mode 100644 examples/data-sources/maas_resource_pool/data-source.tf create mode 100644 examples/resources/maas_resource_pool/import.sh create mode 100644 examples/resources/maas_resource_pool/resource.tf create mode 100644 maas/data_source_maas_resource_pool.go create mode 100644 maas/data_source_maas_resource_pool_test.go create mode 100644 maas/resource_maas_resource_pool.go create mode 100644 maas/resource_maas_resource_pool_test.go diff --git a/docs/data-sources/resource_pool.md b/docs/data-sources/resource_pool.md new file mode 100644 index 0000000..2dc1542 --- /dev/null +++ b/docs/data-sources/resource_pool.md @@ -0,0 +1,36 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "maas_resource_pool Data Source - terraform-provider-maas" +subcategory: "" +description: |- + Provides details about an existing MAAS resource pool. +--- + +# maas_resource_pool (Data Source) + +Provides details about an existing MAAS resource pool. + +## Example Usage + +```terraform +resource "maas_resource_pool" "test_resource_pool" { + description = "Test description" + name = "test-resource-pool" +} + +data "maas_resource_pool" "test_resource_pool" { + name = maas_resource_pool.test_resource_pool.name +} +``` + + +## Schema + +### Required + +- `name` (String) The name of the resource pool. + +### Read-Only + +- `description` (String) The description of the resource pool. +- `id` (String) The ID of this resource. diff --git a/docs/resources/resource_pool.md b/docs/resources/resource_pool.md new file mode 100644 index 0000000..c428068 --- /dev/null +++ b/docs/resources/resource_pool.md @@ -0,0 +1,44 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "maas_resource_pool Resource - terraform-provider-maas" +subcategory: "" +description: |- + Provides a resource to manage MAAS resource pools. +--- + +# maas_resource_pool (Resource) + +Provides a resource to manage MAAS resource pools. + +## Example Usage + +```terraform +resource "maas_resource_pool" "test_resource_pool" { + description = "Test description" + name = "test-resource-pool" +} +``` + + +## Schema + +### Required + +- `name` (String) The name of the resource pool. + +### Optional + +- `description` (String) The description of the resource pool. + +### Read-Only + +- `id` (String) The ID of this resource. + +## Import + +Import is supported using the following syntax: + +```shell +# Resource pools can be imported using their ID or name. e.g. +$ terraform import maas_resource_pool.test_resource_pool test-resource-pool +``` diff --git a/examples/data-sources/maas_resource_pool/data-source.tf b/examples/data-sources/maas_resource_pool/data-source.tf new file mode 100644 index 0000000..1342bd6 --- /dev/null +++ b/examples/data-sources/maas_resource_pool/data-source.tf @@ -0,0 +1,8 @@ +resource "maas_resource_pool" "test_resource_pool" { + description = "Test description" + name = "test-resource-pool" +} + +data "maas_resource_pool" "test_resource_pool" { + name = maas_resource_pool.test_resource_pool.name +} diff --git a/examples/resources/maas_resource_pool/import.sh b/examples/resources/maas_resource_pool/import.sh new file mode 100644 index 0000000..476fcc9 --- /dev/null +++ b/examples/resources/maas_resource_pool/import.sh @@ -0,0 +1,2 @@ +# Resource pools can be imported using their ID or name. e.g. +$ terraform import maas_resource_pool.test_resource_pool test-resource-pool diff --git a/examples/resources/maas_resource_pool/resource.tf b/examples/resources/maas_resource_pool/resource.tf new file mode 100644 index 0000000..b286e69 --- /dev/null +++ b/examples/resources/maas_resource_pool/resource.tf @@ -0,0 +1,4 @@ +resource "maas_resource_pool" "test_resource_pool" { + description = "Test description" + name = "test-resource-pool" +} diff --git a/maas/data_source_maas_resource_pool.go b/maas/data_source_maas_resource_pool.go new file mode 100644 index 0000000..8f1d7cb --- /dev/null +++ b/maas/data_source_maas_resource_pool.go @@ -0,0 +1,46 @@ +package maas + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/maas/gomaasclient/client" +) + +func dataSourceMaasResourcePool() *schema.Resource { + return &schema.Resource{ + Description: "Provides details about an existing MAAS resource pool.", + ReadContext: dataSourceResourcePoolRead, + + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the resource pool.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the resource pool.", + }, + }, + } +} + +func dataSourceResourcePoolRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*client.Client) + + resourcePool, err := getResourcePool(client, d.Get("name").(string)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%v", resourcePool.ID)) + + d.Set("description", resourcePool.Description) + d.Set("name", resourcePool.Name) + + return nil +} diff --git a/maas/data_source_maas_resource_pool_test.go b/maas/data_source_maas_resource_pool_test.go new file mode 100644 index 0000000..c91b037 --- /dev/null +++ b/maas/data_source_maas_resource_pool_test.go @@ -0,0 +1,46 @@ +package maas_test + +import ( + "fmt" + "terraform-provider-maas/maas/testutils" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/maas/gomaasclient/entity" +) + +func TestAccDataSourceMaasResourcePool_basic(t *testing.T) { + + var resourcePool entity.ResourcePool + description := "Test description" + name := "test-name" + + checks := []resource.TestCheckFunc{ + testAccMaasResourcePoolCheckExists("data.maas_resource_pool.test", &resourcePool), + resource.TestCheckResourceAttr("data.maas_resource_pool.test", "description", description), + resource.TestCheckResourceAttr("data.maas_resource_pool.test", "name", name), + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testutils.PreCheck(t) }, + Providers: testutils.TestAccProviders, + CheckDestroy: testAccCheckMaasResourcePoolDestroy, + ErrorCheck: func(err error) error { return err }, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceMaasResourcePool(description, name), + Check: resource.ComposeTestCheckFunc(checks...), + }, + }, + }) +} + +func testAccDataSourceMaasResourcePool(description string, name string) string { + return fmt.Sprintf(` +%s + +data "maas_resource_pool" "test" { + name = maas_resource_pool.test.name +} +`, testAccMaasResourcePool(description, name)) +} diff --git a/maas/provider.go b/maas/provider.go index 04fe2e4..bdd4515 100644 --- a/maas/provider.go +++ b/maas/provider.go @@ -61,6 +61,7 @@ func Provider() *schema.Provider { "maas_block_device": resourceMaasBlockDevice(), "maas_tag": resourceMaasTag(), "maas_user": resourceMaasUser(), + "maas_resource_pool": resourceMaasResourcePool(), }, DataSourcesMap: map[string]*schema.Resource{ "maas_fabric": dataSourceMaasFabric(), @@ -69,6 +70,7 @@ func Provider() *schema.Provider { "maas_machine": dataSourceMaasMachine(), "maas_network_interface_physical": dataSourceMaasNetworkInterfacePhysical(), "maas_device": dataSourceMaasDevice(), + "maas_resource_pool": dataSourceMaasResourcePool(), }, ConfigureContextFunc: providerConfigure, } diff --git a/maas/resource_maas_resource_pool.go b/maas/resource_maas_resource_pool.go new file mode 100644 index 0000000..544223f --- /dev/null +++ b/maas/resource_maas_resource_pool.go @@ -0,0 +1,135 @@ +package maas + +import ( + "context" + "fmt" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/maas/gomaasclient/client" + "github.com/maas/gomaasclient/entity" +) + +func resourceMaasResourcePool() *schema.Resource { + return &schema.Resource{ + Description: "Provides a resource to manage MAAS resource pools.", + CreateContext: resourceResourcePoolCreate, + ReadContext: resourceResourcePoolRead, + UpdateContext: resourceResourcePoolUpdate, + DeleteContext: resourceResourcePoolDelete, + Importer: &schema.ResourceImporter{ + StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + client := meta.(*client.Client) + resourcePool, err := getResourcePool(client, d.Id()) + if err != nil { + return nil, err + } + d.SetId(fmt.Sprintf("%v", resourcePool.ID)) + return []*schema.ResourceData{d}, nil + }, + }, + + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of the resource pool.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the resource pool.", + }, + }, + } +} + +func resourceResourcePoolCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*client.Client) + + resourcePoolParams := entity.ResourcePoolParams{ + Description: d.Get("description").(string), + Name: d.Get("name").(string), + } + + resourcePool, err := client.ResourcePools.Create(&resourcePoolParams) + if err != nil { + return diag.FromErr(err) + } + d.SetId(fmt.Sprintf("%v", resourcePool.ID)) + + return resourceDeviceRead(ctx, d, meta) +} + +func resourceResourcePoolUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*client.Client) + + id, err := strconv.Atoi(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + resourcePoolParams := entity.ResourcePoolParams{ + Description: d.Get("description").(string), + Name: d.Get("name").(string), + } + + resourcePool, err := client.ResourcePool.Update(id, &resourcePoolParams) + if err != nil { + return diag.FromErr(err) + } + d.SetId(fmt.Sprintf("%v", resourcePool.ID)) + + return resourceResourcePoolRead(ctx, d, meta) +} + +func resourceResourcePoolDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*client.Client) + + id, err := strconv.Atoi(d.Id()) + if err != nil { + return diag.FromErr(err) + } + return diag.FromErr(client.ResourcePool.Delete(id)) +} + +func resourceResourcePoolRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*client.Client) + + resourcePool, err := getResourcePool(client, d.Id()) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%v", resourcePool.ID)) + + d.Set("description", resourcePool.Description) + d.Set("name", resourcePool.Name) + + return nil +} + +func getResourcePool(client *client.Client, identifier string) (*entity.ResourcePool, error) { + resourcePool, err := findResourcePool(client, identifier) + if err != nil { + return nil, err + } + if resourcePool == nil { + return nil, fmt.Errorf("resource pool (%s) was not found", identifier) + } + return resourcePool, nil +} + +func findResourcePool(client *client.Client, identifier string) (*entity.ResourcePool, error) { + resourcePools, err := client.ResourcePools.Get() + if err != nil { + return nil, err + } + for _, d := range resourcePools { + if fmt.Sprintf("%v", d.ID) == identifier || d.Name == identifier { + return &d, nil + } + } + return nil, nil +} diff --git a/maas/resource_maas_resource_pool_test.go b/maas/resource_maas_resource_pool_test.go new file mode 100644 index 0000000..b091c92 --- /dev/null +++ b/maas/resource_maas_resource_pool_test.go @@ -0,0 +1,130 @@ +package maas_test + +import ( + "fmt" + "strconv" + "strings" + "terraform-provider-maas/maas/testutils" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/maas/gomaasclient/client" + "github.com/maas/gomaasclient/entity" +) + +func TestAccResourceMaasResourcePool_basic(t *testing.T) { + + var resourcePool entity.ResourcePool + description := "Test description" + name := "test-name" + + checks := []resource.TestCheckFunc{ + testAccMaasResourcePoolCheckExists("maas_resource_pool.test", &resourcePool), + resource.TestCheckResourceAttr("maas_resource_pool.test", "description", description), + resource.TestCheckResourceAttr("maas_resource_pool.test", "name", name), + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testutils.PreCheck(t) }, + Providers: testutils.TestAccProviders, + CheckDestroy: testAccCheckMaasResourcePoolDestroy, + ErrorCheck: func(err error) error { return err }, + Steps: []resource.TestStep{ + { + Config: testAccMaasResourcePool(description, name), + Check: resource.ComposeTestCheckFunc(checks...), + }, + // Test import using ID + { + ResourceName: "maas_resource_pool.test", + ImportState: true, + ImportStateVerify: true, + }, + // Test import using hostname + { + ResourceName: "maas_resource_pool.test", + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources["maas_resource_pool.test"] + if !ok { + return "", fmt.Errorf("resource not found: %s", "maas_resource_pool.test") + } + + if rs.Primary.ID == "" { + return "", fmt.Errorf("resource id not set") + } + return rs.Primary.Attributes["hostname"], nil + }, + }, + }, + }) +} + +func testAccMaasResourcePoolCheckExists(rn string, resourcePool *entity.ResourcePool) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("resource not found: %s\n %#v", rn, s.RootModule().Resources) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("resource id not set") + } + + conn := testutils.TestAccProvider.Meta().(*client.Client) + id, err := strconv.Atoi(rs.Primary.ID) + if err != nil { + return err + } + gotResourcePool, err := conn.ResourcePool.Get(id) + if err != nil { + return fmt.Errorf("error getting resource pool: %s", err) + } + + *resourcePool = *gotResourcePool + + return nil + } +} + +func testAccMaasResourcePool(description string, name string) string { + return fmt.Sprintf(` +resource "maas_resource_pool" "test" { + name = "%s" + description = "%s" +} +`, name, description) +} + +func testAccCheckMaasResourcePoolDestroy(s *terraform.State) error { + // retrieve the connection established in Provider configuration + conn := testutils.TestAccProvider.Meta().(*client.Client) + + // loop through the resources in state, verifying each maas_resource_pool + // is destroyed + for _, rs := range s.RootModule().Resources { + if rs.Type != "maas_resource_pool" { + continue + } + + // Retrieve our maas_resource_pool by referencing it's state ID for API lookup + response, err := conn.Device.Get(rs.Primary.ID) + if err == nil { + if response != nil && response.SystemID == rs.Primary.ID { + return fmt.Errorf("MAAS Resource pool (%s) still exists.", rs.Primary.ID) + } + + return nil + } + + // If the error is equivalent to 404 not found, the maas_resource_pool is destroyed. + // Otherwise return the error + if !strings.Contains(err.Error(), "404 Not Found") { + return err + } + } + + return nil +}