Skip to content

Commit

Permalink
Fixes #408 - implemented clone flag on ovirt_vm resource (#415)
Browse files Browse the repository at this point in the history
  • Loading branch information
engelmi authored May 31, 2022
1 parent c9f0b00 commit 15fddfb
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 10 deletions.
3 changes: 3 additions & 0 deletions docs/resources/vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ resource "ovirt_vm" "test" {

### Optional

- `clone` (Boolean) If true, the VM is cloned from the template instead of linked. As a result, the template can be removed and the VM still exists.
- `comment` (String) User-provided comment for the VM.
- `cpu_cores` (Number) Number of CPU cores to allocate to the VM. If set, cpu_threads and cpu_sockets must also be specified.
- `cpu_mode` (String) Sets the CPU mode for the VM. Can be one of: custom, host_model, host_passthrough
Expand All @@ -54,6 +55,8 @@ resource "ovirt_vm" "test" {

### Read-Only

- `effective_template_id` (String) Effective template ID used to create this VM.
This field yields the same value as "template_id" unless the "clone" field is set to true. In this case the blank template id is returned.
- `id` (String) oVirt ID of this VM.
- `status` (String) Status of the virtual machine. One of: `down`, `image_locked`, `migrating`, `not_responding`, `paused`, `powering_down`, `powering_up`, `reboot_in_progress`, `restoring_state`, `saving_state`, `suspended`, `unassigned`, `unknown`, `up`, `wait_for_launch`.

Expand Down
52 changes: 42 additions & 10 deletions internal/ovirt/resource_ovirt_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ var vmSchema = map[string]*schema.Schema{
Description: "Base template for this VM.",
ValidateDiagFunc: validateUUID,
},
"effective_template_id": {
Type: schema.TypeString,
Computed: true,
Description: `Effective template ID used to create this VM.
This field yields the same value as "template_id" unless the "clone" field is set to true. In this case the blank template id is returned.`,
},
"status": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -171,6 +177,20 @@ var vmSchema = map[string]*schema.Schema{
Optional: true,
Description: "Enable or disable the serial console.",
},
"clone": {
Type: schema.TypeBool,
Optional: true,
Description: "If true, the VM is cloned from the template instead of linked. As a result, the template can be removed and the VM still exists.",
},
}

func cpuModeValues() []string {
values := ovirtclient.CPUModeValues()
result := make([]string, len(values))
for i, v := range values {
result[i] = string(v)
}
return result
}

func vmAffinityValues() []string {
Expand Down Expand Up @@ -233,6 +253,7 @@ func (p *provider) vmCreate(
handleVMMemory,
handleVMMemoryPolicy,
handleVMSerialConsole,
handleVMClone,
} {
diags = f(client, data, params, diags)
}
Expand Down Expand Up @@ -273,6 +294,23 @@ func handleVMSerialConsole(
return diags
}

func handleVMClone(
_ ovirtclient.Client,
data *schema.ResourceData,
params ovirtclient.BuildableVMParameters,
diags diag.Diagnostics,
) diag.Diagnostics {
shouldClone, ok := data.GetOk("clone")
if !ok {
return diags
}
_, err := params.WithClone(shouldClone.(bool))
if err != nil {
diags = append(diags, errorToDiag("set clone flag to VM", err))
}
return diags
}

func handleTemplateDiskAttachmentOverride(
_ ovirtclient.Client,
data *schema.ResourceData,
Expand Down Expand Up @@ -582,7 +620,10 @@ func vmResourceUpdate(vm ovirtclient.VMData, data *schema.ResourceData) diag.Dia
diags := diag.Diagnostics{}
data.SetId(string(vm.ID()))
diags = setResourceField(data, "cluster_id", vm.ClusterID(), diags)
diags = setResourceField(data, "template_id", vm.TemplateID(), diags)
if isCloned, ok := data.GetOk("clone"); !ok && !isCloned.(bool) {
diags = setResourceField(data, "template_id", vm.TemplateID(), diags)
}
diags = setResourceField(data, "effective_template_id", vm.TemplateID(), diags)
diags = setResourceField(data, "name", vm.Name(), diags)
diags = setResourceField(data, "comment", vm.Comment(), diags)
diags = setResourceField(data, "status", vm.Status(), diags)
Expand Down Expand Up @@ -688,12 +729,3 @@ func (p *provider) vmImport(ctx context.Context, data *schema.ResourceData, _ in
data,
}, nil
}

func cpuModeValues() []string {
values := ovirtclient.CPUModeValues()
result := make([]string, len(values))
for i, v := range values {
result[i] = string(v)
}
return result
}
107 changes: 107 additions & 0 deletions internal/ovirt/resource_ovirt_vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -869,3 +869,110 @@ resource "ovirt_vm" "test" {
)
}
}

func TestClone(t *testing.T) {
t.Parallel()
no := false
yes := true
testCases := []struct {
set *bool
expectBlankTemplateID bool
}{
{
nil,
false,
},
{
&no,
false,
},
{
&yes,
true,
},
}

for _, tc := range testCases {
set := "nil"
if tc.set != nil {
set = fmt.Sprintf("%t", *tc.set)
}
expectBlank := fmt.Sprintf("%t", tc.expectBlankTemplateID)
t.Run(
fmt.Sprintf("clone=%s,expect blank template ID=%s", set, expectBlank), func(t *testing.T) {
p := newProvider(newTestLogger(t))
testHelper := p.getTestHelper()
clusterID := testHelper.GetClusterID()
cloneLine := ""
if tc.set != nil {
cloneLine = fmt.Sprintf("clone = %t", *tc.set)
}
config := fmt.Sprintf(
`
provider "ovirt" {
mock = true
}
data "ovirt_blank_template" "blank" {
}
resource "ovirt_vm" "test" {
template_id = data.ovirt_blank_template.blank.id
cluster_id = "%s"
name = "%s"
}
resource "ovirt_template" "blueprint" {
vm_id = ovirt_vm.test.id
name = "blueprint1"
}
resource "ovirt_vm" "second_vm" {
template_id = ovirt_template.blueprint.id
cluster_id = "%s"
name = "%s"
%s
}
`,
clusterID,
p.getTestHelper().GenerateTestResourceName(t),
clusterID,
p.getTestHelper().GenerateTestResourceName(t),
cloneLine,
)

resource.UnitTest(
t, resource.TestCase{
ProviderFactories: p.getProviderFactories(),
Steps: []resource.TestStep{
{
Config: config,
Check: func(state *terraform.State) error {
secondVMID := state.RootModule().Resources["ovirt_vm.second_vm"].Primary.ID
templateID := state.RootModule().Resources["ovirt_template.blueprint"].Primary.ID

client := testHelper.GetClient()
secondVM, err := client.GetVM(ovirtclient.VMID(secondVMID))
if err != nil {
return err
}
secondVMTemplateID := string(secondVM.TemplateID())
if tc.expectBlankTemplateID && (secondVMTemplateID != string(ovirtclient.DefaultBlankTemplateID)) {
return fmt.Errorf(
"Expected template of VM to be blank '%s', but got '%s",
string(ovirtclient.DefaultBlankTemplateID), secondVMTemplateID)
}
if !tc.expectBlankTemplateID && (secondVMTemplateID != templateID) {
return fmt.Errorf("Expected template of VM to be '%s', but got '%s", templateID, secondVMTemplateID)
}

return nil
},
},
{
Config: config,
Destroy: true,
},
},
},
)
},
)
}
}

0 comments on commit 15fddfb

Please sign in to comment.