From e3936ddf3f7a4a9dd3ac97529b0b1721f0539897 Mon Sep 17 00:00:00 2001 From: Stamatis Katsaounis Date: Wed, 4 Oct 2023 00:40:15 +0300 Subject: [PATCH] Fix parsing of power parameters --- docs/resources/machine.md | 6 +- examples/1-machines.tf | 16 ++--- examples/resources/maas_machine/resource.tf | 4 +- go.mod | 2 +- go.sum | 4 +- maas/resource_maas_machine.go | 69 ++++++++++++++----- maas/resource_maas_machine_migrate.go | 74 +++++++++++++++++++++ maas/resource_maas_machine_migrate_test.go | 37 +++++++++++ maas/resource_maas_vm_host_machine.go | 2 +- 9 files changed, 182 insertions(+), 32 deletions(-) create mode 100644 maas/resource_maas_machine_migrate.go create mode 100644 maas/resource_maas_machine_migrate_test.go diff --git a/docs/resources/machine.md b/docs/resources/machine.md index 2308a1c7..92bd185d 100644 --- a/docs/resources/machine.md +++ b/docs/resources/machine.md @@ -15,10 +15,10 @@ Provides a resource to manage MAAS machines. ```terraform resource "maas_machine" "virsh_vm1" { power_type = "virsh" - power_parameters = { + power_parameters = jsonencode({ power_address = "qemu+ssh://ubuntu@10.113.1.26/system" power_id = "test-vm1" - } + }) pxe_mac_address = "52:54:00:89:f5:3e" } ``` @@ -28,7 +28,7 @@ resource "maas_machine" "virsh_vm1" { ### Required -- `power_parameters` (Map of String, Sensitive) A map with the parameters specific to the `power_type`. See [Power types](https://maas.io/docs/api#power-types) section for a list of the available power parameters for each power type. +- `power_parameters` (String, Sensitive) Serialized JSON string containing the parameters specific to the `power_type`. See [Power types](https://maas.io/docs/api#power-types) section for a list of the available power parameters for each power type. - `power_type` (String) A power management type (e.g. `ipmi`). - `pxe_mac_address` (String) The MAC address of the machine's PXE boot NIC. diff --git a/examples/1-machines.tf b/examples/1-machines.tf index 3e2a2f48..028a502f 100644 --- a/examples/1-machines.tf +++ b/examples/1-machines.tf @@ -3,10 +3,10 @@ # resource "maas_machine" "virsh_vm1" { power_type = "virsh" - power_parameters = { + power_parameters = jsonencode({ power_address = "qemu+ssh://ubuntu@10.113.1.26/system" power_id = "test-vm1" - } + }) pxe_mac_address = "52:54:00:89:f5:3e" } @@ -74,10 +74,10 @@ resource "maas_network_interface_link" "virsh_vm1_nic3" { # resource "maas_machine" "virsh_vm2" { power_type = "virsh" - power_parameters = { + power_parameters = jsonencode({ power_address = "qemu+ssh://ubuntu@10.113.1.26/system" power_id = "test-vm2" - } + }) pxe_mac_address = "52:54:00:7c:f7:77" } @@ -186,10 +186,10 @@ resource "maas_block_device" "vdc" { # resource "maas_machine" "virsh_vm3" { power_type = "virsh" - power_parameters = { + power_parameters = jsonencode({ power_address = "qemu+ssh://ubuntu@10.113.1.21/system" power_id = "machine-01" - } + }) pxe_mac_address = "52:54:00:16:78:ec" } @@ -198,9 +198,9 @@ resource "maas_machine" "virsh_vm3" { # resource "maas_machine" "virsh_vm4" { power_type = "virsh" - power_parameters = { + power_parameters = jsonencode({ power_address = "qemu+ssh://ubuntu@10.113.1.22/system" power_id = "machine-05" - } + }) pxe_mac_address = "52:54:00:c4:74:96" } diff --git a/examples/resources/maas_machine/resource.tf b/examples/resources/maas_machine/resource.tf index a781c233..47da21a8 100644 --- a/examples/resources/maas_machine/resource.tf +++ b/examples/resources/maas_machine/resource.tf @@ -1,8 +1,8 @@ resource "maas_machine" "virsh_vm1" { power_type = "virsh" - power_parameters = { + power_parameters = jsonencode({ power_address = "qemu+ssh://ubuntu@10.113.1.26/system" power_id = "test-vm1" - } + }) pxe_mac_address = "52:54:00:89:f5:3e" } diff --git a/go.mod b/go.mod index fa777fde..8595120e 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/terraform-plugin-docs v0.16.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0 - github.com/maas/gomaasclient v0.0.0-20230927145110-b2775d1ca870 + github.com/maas/gomaasclient v0.0.0-20231005172544-633cecfc0171 github.com/stretchr/testify v1.8.4 ) diff --git a/go.sum b/go.sum index b860097d..1f361743 100644 --- a/go.sum +++ b/go.sum @@ -333,8 +333,8 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LE github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/maas/gomaasclient v0.0.0-20230927145110-b2775d1ca870 h1:CZ2i4fEX8xXOd5JBG+RhDILCQG5Cu0ZTFOL3qNg8Mns= -github.com/maas/gomaasclient v0.0.0-20230927145110-b2775d1ca870/go.mod h1:6Rf68yTVxSHE35pGymgAXdZQPja2lvX3mRRHHuqdr2M= +github.com/maas/gomaasclient v0.0.0-20231005172544-633cecfc0171 h1:um7H4xdQxGMHOZ2WhDhOtCJ3brybBely2zxp8XaFnGs= +github.com/maas/gomaasclient v0.0.0-20231005172544-633cecfc0171/go.mod h1:6Rf68yTVxSHE35pGymgAXdZQPja2lvX3mRRHHuqdr2M= github.com/masterzen/azure-sdk-for-go v3.2.0-beta.0.20161014135628-ee4f0065d00c+incompatible/go.mod h1:mf8fjOu33zCqxUjuiU3I8S1lJMyEAlH+0F2+M5xl3hE= github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc= github.com/masterzen/winrm v0.0.0-20161014151040-7a535cd943fc/go.mod h1:CfZSN7zwz5gJiFhZJz49Uzk7mEBHIceWmbFmYx7Hf7E= diff --git a/maas/resource_maas_machine.go b/maas/resource_maas_machine.go index 4b2f6595..9439f9c8 100644 --- a/maas/resource_maas_machine.go +++ b/maas/resource_maas_machine.go @@ -4,11 +4,13 @@ import ( "context" "fmt" "log" + "reflect" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/maas/gomaasclient/client" "github.com/maas/gomaasclient/entity" @@ -21,6 +23,14 @@ func resourceMaasMachine() *schema.Resource { ReadContext: resourceMachineRead, UpdateContext: resourceMachineUpdate, DeleteContext: resourceMachineDelete, + SchemaVersion: 1, + StateUpgraders: []schema.StateUpgrader{ + { + Type: resourceMaasMachineResourceV0().CoreConfigSchema().ImpliedType(), + Upgrade: resourceMaasMachineStateUpgradeV0, + Version: 0, + }, + }, Importer: &schema.ResourceImporter{ StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { client := m.(*client.Client) @@ -32,10 +42,14 @@ func resourceMaasMachine() *schema.Resource { if err != nil { return nil, err } + powerParamsString, err := structure.FlattenJsonToString(powerParams) + if err != nil { + return nil, err + } tfState := map[string]interface{}{ "id": machine.SystemID, "power_type": machine.PowerType, - "power_parameters": powerParams, + "power_parameters": powerParamsString, "pxe_mac_address": machine.BootInterface.MACAddress, "architecture": machine.Architecture, } @@ -60,13 +74,26 @@ func resourceMaasMachine() *schema.Resource { false)), }, "power_parameters": { - Type: schema.TypeMap, - Required: true, - Sensitive: true, - Description: "A map with the parameters specific to the `power_type`. See [Power types](https://maas.io/docs/api#power-types) section for a list of the available power parameters for each power type.", - Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + Required: true, + Sensitive: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: func(k, oldValue, newValue string, d *schema.ResourceData) bool { + oldMap, err := structure.ExpandJsonFromString(oldValue) + if err != nil { + return false + } + newMap, err := structure.ExpandJsonFromString(newValue) + if err != nil { + return false + } + return reflect.DeepEqual(oldMap, newMap) }, + StateFunc: func(v interface{}) string { + json, _ := structure.NormalizeJsonString(v) + return json + }, + Description: "Serialized JSON string containing the parameters specific to the `power_type`. See [Power types](https://maas.io/docs/api#power-types) section for a list of the available power parameters for each power type.", }, "pxe_mac_address": { Type: schema.TypeString, @@ -120,7 +147,11 @@ func resourceMachineCreate(ctx context.Context, d *schema.ResourceData, m interf client := m.(*client.Client) // Create MAAS machine - machine, err := client.Machines.Create(getMachineParams(d), getMachinePowerParams(d)) + powerParams, err := getMachinePowerParams(d) + if err != nil { + return diag.FromErr(err) + } + machine, err := client.Machines.Create(getMachineParams(d), powerParams) if err != nil { return diag.FromErr(err) } @@ -171,7 +202,11 @@ func resourceMachineUpdate(ctx context.Context, d *schema.ResourceData, m interf if err != nil { return diag.FromErr(err) } - if _, err := client.Machine.Update(machine.SystemID, getMachineParams(d), getMachinePowerParams(d)); err != nil { + powerParams, err := getMachinePowerParams(d) + if err != nil { + return diag.FromErr(err) + } + if _, err := client.Machine.Update(machine.SystemID, getMachineParams(d), powerParams); err != nil { return diag.FromErr(err) } @@ -189,13 +224,17 @@ func resourceMachineDelete(ctx context.Context, d *schema.ResourceData, m interf return nil } -func getMachinePowerParams(d *schema.ResourceData) map[string]string { - powerParams := d.Get("power_parameters").(map[string]interface{}) - params := make(map[string]string, len(powerParams)) - for k, v := range powerParams { - params[fmt.Sprintf("power_parameters_%s", k)] = v.(string) +func getMachinePowerParams(d *schema.ResourceData) (powerParams map[string]interface{}, err error) { + powerParams = make(map[string]interface{}) + powerParamsString := d.Get("power_parameters").(string) + params, err := structure.ExpandJsonFromString(powerParamsString) + if err != nil { + return powerParams, err + } + for k, v := range params { + powerParams[fmt.Sprintf("power_parameters_%s", k)] = v } - return params + return powerParams, nil } func getMachineParams(d *schema.ResourceData) *entity.MachineParams { diff --git a/maas/resource_maas_machine_migrate.go b/maas/resource_maas_machine_migrate.go new file mode 100644 index 00000000..1eb42c2d --- /dev/null +++ b/maas/resource_maas_machine_migrate.go @@ -0,0 +1,74 @@ +package maas + +import ( + "context" + "encoding/json" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceMaasMachineResourceV0() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "power_type": { + Type: schema.TypeString, + Required: true, + }, + "power_parameters": { + Type: schema.TypeMap, + Required: true, + Sensitive: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "pxe_mac_address": { + Type: schema.TypeString, + Required: true, + }, + "architecture": { + Type: schema.TypeString, + Optional: true, + Default: "amd64/generic", + }, + "min_hwe_kernel": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "hostname": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "domain": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "zone": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "pool": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + } +} + +func resourceMaasMachineStateUpgradeV0(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + // Convert power_parameters from map[string]string to a serialized JSON string. + oldPowerParametersRaw := rawState["power_parameters"].(map[string]string) + flattenedOldPowerParameters, err := json.Marshal(oldPowerParametersRaw) + if err != nil { + return nil, err + } + + rawState["power_parameters"] = string(flattenedOldPowerParameters) + + return rawState, nil +} diff --git a/maas/resource_maas_machine_migrate_test.go b/maas/resource_maas_machine_migrate_test.go new file mode 100644 index 00000000..b92dc196 --- /dev/null +++ b/maas/resource_maas_machine_migrate_test.go @@ -0,0 +1,37 @@ +package maas + +import ( + "context" + "reflect" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" +) + +func testResourceMaasMachineInstanceStateDataV0() map[string]interface{} { + return map[string]interface{}{ + "power_parameters": map[string]string{ + "power_user": "ubuntu", + }, + } +} + +func testResourceMaasMachineInstanceStateDataV1() map[string]interface{} { + flattenedV0, _ := structure.FlattenJsonToString(map[string]interface{}{ + "power_user": "ubuntu", + }) + return map[string]interface{}{"power_parameters": flattenedV0} +} + +func TestResourceMaasMachineInstanceStateUpgradeV0(t *testing.T) { + ctx := context.Background() + expected := testResourceMaasMachineInstanceStateDataV1() + actual, err := resourceMaasMachineStateUpgradeV0(ctx, testResourceMaasMachineInstanceStateDataV0(), nil) + if err != nil { + t.Fatalf("error migrating state: %s", err) + } + + if !reflect.DeepEqual(expected, actual) { + t.Fatalf("\n\nexpected:\n\n%#v\n\ngot:\n\n%#v\n\n", expected, actual) + } +} diff --git a/maas/resource_maas_vm_host_machine.go b/maas/resource_maas_vm_host_machine.go index 013f4778..696de466 100644 --- a/maas/resource_maas_vm_host_machine.go +++ b/maas/resource_maas_vm_host_machine.go @@ -208,7 +208,7 @@ func resourceVMHostMachineUpdate(ctx context.Context, d *schema.ResourceData, m client := m.(*client.Client) // Update VM host machine - if _, err := client.Machine.Update(d.Id(), getVMHostMachineUpdateParams(d), map[string]string{}); err != nil { + if _, err := client.Machine.Update(d.Id(), getVMHostMachineUpdateParams(d), map[string]interface{}{}); err != nil { return diag.FromErr(err) }