Skip to content

Commit

Permalink
Fixes oVirt#367: Disk from local disk image
Browse files Browse the repository at this point in the history
  • Loading branch information
Janos Bonic committed May 16, 2022
1 parent 26c6773 commit dfaebf5
Show file tree
Hide file tree
Showing 14 changed files with 371 additions and 8 deletions.
46 changes: 46 additions & 0 deletions docs/resources/disk_from_image.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "ovirt_disk_from_image Resource - terraform-provider-ovirt"
subcategory: ""
description: |-
The ovirtdiskfrom_image resource creates disks in oVirt from a local image file.
---

# ovirt_disk_from_image (Resource)

The ovirt_disk_from_image resource creates disks in oVirt from a local image file.

## Example Usage

```terraform
resource "ovirt_disk_from_image" "test" {
storagedomain_id = var.storagedomain_id
format = "raw"
alias = "test"
sparse = true
source_file = "./testimage/testimage"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `format` (String) Format for the disk. One of: `cow`, `raw`
- `source_file` (String) Path to the local file to upload as the disk image.
- `storagedomain_id` (String) ID of the storage domain to use for disk creation.

### Optional

- `alias` (String) Human-readable alias for the disk.
- `sparse` (Boolean) Use sparse provisioning for disk.

### Read-Only

- `id` (String) The ID of this resource.
- `size` (Number) Disk size in bytes.
- `status` (String) Status of the disk. 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`.
- `total_size` (Number) Size of the actual image size on the disk in bytes.


20 changes: 20 additions & 0 deletions examples/resources/ovirt_disk_from_image/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
terraform {
required_providers {
ovirt = {
source = "ovirt/ovirt"
}
}

required_version = ">= 0.15"
}

provider "ovirt" {
url = var.url
username = var.username
password = var.password
tls_ca_bundle = var.tls_ca_bundle
tls_system = var.tls_system
tls_ca_dirs = var.tls_ca_dirs
tls_ca_files = var.tls_ca_files
tls_insecure = var.tls_insecure
}
7 changes: 7 additions & 0 deletions examples/resources/ovirt_disk_from_image/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
resource "ovirt_disk_from_image" "test" {
storagedomain_id = var.storagedomain_id
format = "raw"
alias = "test"
sparse = true
source_file = "./testimage/testimage"
}
1 change: 1 addition & 0 deletions examples/resources/ovirt_disk_from_image/testimage
39 changes: 39 additions & 0 deletions examples/resources/ovirt_disk_from_image/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
variable "storagedomain_id" {
type = string
description = "ID of the storage domain to create the disk on."
}

variable "username" {
type = string
}
variable "password" {
type = string
}
variable "url" {
type = string
}
variable "tls_ca_files" {
type = list(string)
default = []
}
variable "tls_ca_dirs" {
type = list(string)
default = []
}
variable "tls_insecure" {
type = bool
default = false
}
variable "tls_ca_bundle" {
type = string
default = ""
}
variable "tls_system" {
type = bool
default = true
description = "Take TLS CA certificates from system root. Does not work on Windows."
}
variable "mock" {
type = bool
default = true
}
1 change: 1 addition & 0 deletions ovirt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ func (p *provider) getProvider() *schema.Provider {
"ovirt_vm_tag": p.vmTagResource(),
"ovirt_vm_optimize_cpu_settings": p.vmOptimizeCPUSettingsResource(),
"ovirt_disk": p.diskResource(),
"ovirt_disk_from_image": p.diskFromImageResource(),
"ovirt_disk_attachment": p.diskAttachmentResource(),
"ovirt_disk_attachments": p.diskAttachmentsResource(),
"ovirt_nic": p.nicResource(),
Expand Down
21 changes: 13 additions & 8 deletions ovirt/resource_ovirt_disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
ovirtclient "github.com/ovirt/go-ovirt-client"
)

var diskSchema = map[string]*schema.Schema{
var diskBaseSchema = map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -32,13 +32,6 @@ var diskSchema = map[string]*schema.Schema{
ValidateDiagFunc: validateFormat,
ForceNew: true,
},
"size": {
Type: schema.TypeInt,
Required: true,
Description: "Disk size in bytes.",
ValidateDiagFunc: validateDiskSize,
ForceNew: true,
},
"alias": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -65,6 +58,18 @@ var diskSchema = map[string]*schema.Schema{
},
}

var diskSchema = schemaMerge(
diskBaseSchema, map[string]*schema.Schema{
"size": {
Type: schema.TypeInt,
Required: true,
Description: "Disk size in bytes.",
ValidateDiagFunc: validateDiskSize,
ForceNew: true,
},
},
)

func (p *provider) diskResource() *schema.Resource {
return &schema.Resource{
CreateContext: p.diskCreate,
Expand Down
116 changes: 116 additions & 0 deletions ovirt/resource_ovirt_disk_from_image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package ovirt

import (
"context"
"fmt"
"os"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
ovirtclient "github.com/ovirt/go-ovirt-client"
)

var diskFromImageSchema = schemaMerge(
diskBaseSchema, map[string]*schema.Schema{
"source_file": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Path to the local file to upload as the disk image.",
ValidateDiagFunc: validateLocalFile,
},
"size": {
Type: schema.TypeInt,
Computed: true,
Description: "Disk size in bytes.",
},
},
)

func (p *provider) diskFromImageResource() *schema.Resource {
return &schema.Resource{
CreateContext: p.diskFromImageCreate,
ReadContext: p.diskRead,
UpdateContext: p.diskUpdate,
DeleteContext: p.diskDelete,
Schema: diskFromImageSchema,
Description: "The ovirt_disk_from_image resource creates disks in oVirt from a local image file.",
}
}

func (p *provider) diskFromImageCreate(ctx context.Context, data *schema.ResourceData, i interface{}) diag.Diagnostics {
client := p.client.WithContext(ctx)
var err error

storageDomainID := data.Get("storagedomain_id").(string)
format := data.Get("format").(string)

params := ovirtclient.CreateDiskParams()
if alias, ok := data.GetOk("alias"); ok {
params, err = params.WithAlias(alias.(string))
if err != nil {
return diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Error,
Summary: "Invalid alias value.",
Detail: err.Error(),
},
}
}
}
if sparse, ok := data.GetOk("sparse"); ok {
params, err = params.WithSparse(sparse.(bool))
if err != nil {
return diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Error,
Summary: "Invalid sparse value.",
Detail: err.Error(),
},
}
}
}
sourceFile := data.Get("source_file").(string)
// We actually want to include the file here, so this is not gosec-relevant.
fh, err := os.Open(sourceFile) //nolint:gosec
if err != nil {
return errorToDiags(fmt.Sprintf("opening file %s", sourceFile), err)
}
stat, err := fh.Stat()
if err != nil {
return errorToDiags(fmt.Sprintf("opening file %s", sourceFile), err)
}
upload, err := client.UploadToNewDisk(
ovirtclient.StorageDomainID(storageDomainID),
ovirtclient.ImageFormat(format),
uint64(stat.Size()),
params,
fh,
)
var disk ovirtclient.Disk
if upload != nil {
disk = upload.Disk()
}
if err != nil {
diags := diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Error,
Summary: "Failed to create disk.",
Detail: err.Error(),
},
}
if disk != nil {
if err := disk.Remove(); err != nil && !ovirtclient.HasErrorCode(err, ovirtclient.ENotFound) {
diags = append(
diags, diag.Diagnostic{
Severity: diag.Error,
Summary: fmt.Sprintf("Failed to remove created disk %s", disk.ID()),
Detail: err.Error(),
},
)
}
}
return diags
}
return diskResourceUpdate(disk, data)
}
54 changes: 54 additions & 0 deletions ovirt/resource_ovirt_disk_from_image_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package ovirt

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestImageUpload(t *testing.T) {
t.Parallel()

p := newProvider(newTestLogger(t))
storageDomainID := p.getTestHelper().GetStorageDomainID()

resource.UnitTest(
t, resource.TestCase{
ProviderFactories: p.getProviderFactories(),
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
`
provider "ovirt" {
mock = true
}
resource "ovirt_disk_from_image" "foo" {
storagedomain_id = "%s"
format = "raw"
alias = "test"
sparse = true
source_file = "./testimage/image"
}
`,
storageDomainID,
),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr(
"ovirt_disk_from_image.foo",
"storagedomain_id",
regexp.MustCompile(fmt.Sprintf("^%s$", regexp.QuoteMeta(string(storageDomainID)))),
),
resource.TestMatchResourceAttr(
"ovirt_disk_from_image.foo",
"size",
regexp.MustCompile(fmt.Sprintf("^%d$", 1024*1024)),
),
),
},
},
},
)
}
1 change: 1 addition & 0 deletions ovirt/testimage
11 changes: 11 additions & 0 deletions ovirt/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ import (
ovirtclient "github.com/ovirt/go-ovirt-client"
)

func schemaMerge(schema1, schema2 map[string]*schema.Schema) map[string]*schema.Schema {
result := make(map[string]*schema.Schema, len(schema1)+len(schema2))
for k, v := range schema1 {
result[k] = v
}
for k, v := range schema2 {
result[k] = v
}
return result
}

func extractString(data *schema.ResourceData, option string, diags diag.Diagnostics) (string, diag.Diagnostics) {
var url string
urlInterface, ok := data.GetOk(option)
Expand Down
Loading

0 comments on commit dfaebf5

Please sign in to comment.