From 695e20da54d5963c18f1343eeae89747f98bda41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= Date: Mon, 12 Feb 2024 11:18:00 +0100 Subject: [PATCH] Add Combustion resource to use instead of the ignition one --- libvirt/coreos_ignition_def.go | 9 +- libvirt/provider.go | 1 + libvirt/resource_libvirt_combustion.go | 91 +++++++++++++++++++++ libvirt/resource_libvirt_combustion_test.go | 73 +++++++++++++++++ 4 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 libvirt/resource_libvirt_combustion.go create mode 100644 libvirt/resource_libvirt_combustion_test.go diff --git a/libvirt/coreos_ignition_def.go b/libvirt/coreos_ignition_def.go index 74012c4e0..c48ded5a3 100644 --- a/libvirt/coreos_ignition_def.go +++ b/libvirt/coreos_ignition_def.go @@ -14,9 +14,10 @@ import ( ) type defIgnition struct { - Name string - PoolName string - Content string + Name string + PoolName string + Content string + Combution bool } // Creates a new cloudinit with the defaults @@ -133,7 +134,7 @@ func (ign *defIgnition) createFile() (string, error) { file = true if _, err := os.Stat(ign.Content); err != nil { var js map[string]interface{} - if errConf := json.Unmarshal([]byte(ign.Content), &js); errConf != nil { + if errConf := json.Unmarshal([]byte(ign.Content), &js); !ign.Combution && errConf != nil { return "", fmt.Errorf("coreos_ignition 'content' is neither a file "+ "nor a valid json object %s", ign.Content) } diff --git a/libvirt/provider.go b/libvirt/provider.go index f7720138a..8cb43a8ed 100644 --- a/libvirt/provider.go +++ b/libvirt/provider.go @@ -25,6 +25,7 @@ func Provider() *schema.Provider { "libvirt_pool": resourceLibvirtPool(), "libvirt_cloudinit_disk": resourceCloudInitDisk(), "libvirt_ignition": resourceIgnition(), + "libvirt_combustion": resourceCombustion(), }, DataSourcesMap: map[string]*schema.Resource{ diff --git a/libvirt/resource_libvirt_combustion.go b/libvirt/resource_libvirt_combustion.go new file mode 100644 index 000000000..a2ad23d98 --- /dev/null +++ b/libvirt/resource_libvirt_combustion.go @@ -0,0 +1,91 @@ +package libvirt + +import ( + "context" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCombustion() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceCombustionCreate, + ReadContext: resourceCombustionRead, + DeleteContext: resourceCombustionDelete, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "pool": { + Type: schema.TypeString, + Optional: true, + Default: "default", + ForceNew: true, + }, + "content": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceCombustionCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + log.Printf("[DEBUG] creating combustion file") + client := meta.(*Client) + if client.libvirt == nil { + return diag.Errorf(LibVirtConIsNil) + } + + combustion := newIgnitionDef() + + combustion.Name = d.Get("name").(string) + combustion.PoolName = d.Get("pool").(string) + combustion.Content = d.Get("content").(string) + combustion.Combution = true + + log.Printf("[INFO] combustion: %+v", combustion) + + key, err := combustion.CreateAndUpload(client) + if err != nil { + return diag.FromErr(err) + } + d.SetId(key) + + return resourceIgnitionRead(ctx, d, meta) +} + +func resourceCombustionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + virConn := meta.(*Client).libvirt + if virConn == nil { + return diag.Errorf(LibVirtConIsNil) + } + + combustion, err := newIgnitionDefFromRemoteVol(virConn, d.Id()) + d.Set("pool", combustion.PoolName) + d.Set("name", combustion.Name) + + if err != nil { + return diag.Errorf("error while retrieving remote volume: %s", err) + } + + return nil +} + +func resourceCombustionDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*Client) + if client.libvirt == nil { + return diag.Errorf(LibVirtConIsNil) + } + + key, err := getIgnitionVolumeKeyFromTerraformID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + return diag.FromErr(volumeDelete(ctx, client, key)) +} diff --git a/libvirt/resource_libvirt_combustion_test.go b/libvirt/resource_libvirt_combustion_test.go new file mode 100644 index 000000000..a3fd701f4 --- /dev/null +++ b/libvirt/resource_libvirt_combustion_test.go @@ -0,0 +1,73 @@ +package libvirt + +import ( + "fmt" + "testing" + + libvirt "github.com/digitalocean/go-libvirt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccLibvirtCombustion_Basic(t *testing.T) { + var volume libvirt.StorageVol + randomCombustionName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) + randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) + randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName + var config = fmt.Sprintf(` + resource "libvirt_pool" "%s" { + name = "%s" + type = "dir" + path = "%s" + } + + resource "libvirt_combustion" "combustion" { + name = "%s" + content = "#!/bin/bash +# combustion: network +echo 'root:$6$3aQC9rrDLHiTf1yR$NoKe9tko0kFIpu0rQ2y/FOO' | chpasswd -e +" + pool = "${libvirt_pool.%s.name}" + } + `, randomPoolName, randomPoolName, randomPoolPath, randomCombustionName, randomPoolName) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLibvirtIgnitionDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testAccCheckIgnitionVolumeExists("libvirt_combustion.combustion", &volume), + resource.TestCheckResourceAttr( + "libvirt_combustion.combustion", "name", randomCombustionName), + resource.TestCheckResourceAttr( + "libvirt_combustion.combustion", "pool", randomPoolName), + ), + }, + }, + }) +} + +func testAccCheckLibvirtCombustionDestroy(s *terraform.State) error { + virtConn := testAccProvider.Meta().(*Client).libvirt + for _, rs := range s.RootModule().Resources { + if rs.Type != "libvirt_combustion" { + continue + } + // Try to find the Ignition Volume + ignKey, errKey := getIgnitionVolumeKeyFromTerraformID(rs.Primary.ID) + if errKey != nil { + return errKey + } + _, err := virtConn.StorageVolLookupByKey(ignKey) + if err == nil { + return fmt.Errorf( + "Error waiting for CombustionVolume (%s) to be destroyed: %w", + ignKey, err) + } + } + return nil +}