Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Able to specifiy size when using backing volume (and able to resize partitions with cloud-init) #416

Merged
merged 7 commits into from
Sep 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/resize_base/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.img
*.qcow2
*.tfstate*
.terraform
11 changes: 11 additions & 0 deletions examples/resize_base/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

This example takes a base image of 2G and uses it as the backing store of a bigger volume. _cloud-init_ is then used to resize the original partition to the new available space.

See https://github.com/dmacvicar/terraform-provider-libvirt/issues/369

# Running

```console
$ terraform apply
$ ssh -i id_rsa "root@$(terraform output ip)"
```
27 changes: 27 additions & 0 deletions examples/resize_base/id_rsa
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAzKsKBhrbzq5Ur80tDE2t5fsAkJ5qHnm5w0v9cEVKkkPgeUTi
+VswoBAFMjf1nTKbGZAEsXS8nphD4XURdztV+p1m7XopzS1uC0DDyPm5TxWptMSd
ZAS2DA0l0eeyvKmNGveKKcrgFAjwMENr3syjwfNKao5waYSkLBvvgp6oWkPJG7RK
SER6z/n1JBhJoGwAu8plNsLWRhhoYrGMaVTsOcYj2ohFNM3c59UarwLPsKlV2TRJ
PFpLkGm69BYMR2fxHyFLn1iEMvy21X0wcs4bh2SLB8qTu1uDko6MneAAlFQgPgvJ
cIYWhgdyIi0VGhatvPFH4E0C2wfADqV3us5qzwIDAQABAoIBAQCJ0LplNfzBBX6d
ConE+SGZ9RSCTUmjz8+YhDjaOq5mIzKqNgqoYhEyFteI40mOWp857VJbtAG2wU0k
KdJi+R+CLC88xcAUGv04spmjYRS4/htST/qzeMClCM1otJ4UkA8mE32Desq8cvBZ
b2zZj+7NEOgRLGzhgKGT2hPDXtZ6QGn9+K6xUrjGp9gOhKgFWz7jNqlxQQh/bvLt
BHj/YHcCT32TFf7AciZK/gDT+8D9a3rTzBKFhmCoHnCyJlqF/EPlA29VEL2rOFR8
638MIXSWCnK2LXCD6V7x+l9KKyJndh5TFlcdUIZ7YOpDcnWrRNjzuCkzb2KK2cdD
URekeL5RAoGBAPMTEGHCwBkq2tB93tWl3M6rMqs2pLoWv+r74dIBhSdvzFhq7vrL
TGwR59JhXPlcde97ANyZpulxEIKzVJE0mRHFebnNxz+MmRVcj4cNeE4b1GKwmx00
hcy2RSjM+9YnFFLUWyZIPKY0NiW3aBC98aPn0biiG6ZGIXJVmAlladz1AoGBANeN
J8YTLpVb7p5+B9nbSM3mvx+ZtAifAeDR792nTSN7DjQSYOfNrzTqdfqveSPtrpnZ
wgMa9nQyFFtMp0eDB835dy/ZA/w918H5YwFgabgTQ+eBJjZNI2iSyptITCbieUHV
MOin5nlhonx1jirhZEHDS8gGoIV3TQQlzu/E2g4zAoGAIr7e4JqOCwrtLFBRwghr
f79JBuBQu6j01gobRYGiHvkEJL9kWcUlr2z/zjrMp3hoA0t53A66pTPcQFKSDA+Q
sdGgjMa1bIgUedE5UvzB7ahcu56zDYGsfo6vZB2pAfukFBL21IoO4VMlSk7lOT9t
gxhoChRiD2qG7Wj+ypkMgOECgYB7LSvcchu9uHJM2gKMiVY6a7EuUrxh7NO68N1c
0f0v2GNOeG4uKQkFeTKAVgQo9us++gR3l9Hcpr2hStWQ9RzhpLxqeF5hp8mDDIt6
PulLCp9UTSZUA5LHcJMdV5xE4EigyT6QxVncZWHgM6FRecm8FulYXgkfHATD6QMv
W1OspwKBgQDviiVBtlUvRWo9wUs1Y1tYCwBjFVztaJBGQ+Qx5uhYAhSobwUTW/MI
1lrxpGWaBfe63Iy+3V8v7YLU/bjjUMrzNFTrvoERwoRndL5EDqL5clljHO5kW+2g
wXfNa8BPj2EiqmmMcM3rcxd7Kw7qvEFLeJk9WE6EvKjvYiirr20mhQ==
-----END RSA PRIVATE KEY-----
1 change: 1 addition & 0 deletions examples/resize_base/id_rsa.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMqwoGGtvOrlSvzS0MTa3l+wCQnmoeebnDS/1wRUqSQ+B5ROL5WzCgEAUyN/WdMpsZkASxdLyemEPhdRF3O1X6nWbteinNLW4LQMPI+blPFam0xJ1kBLYMDSXR57K8qY0a94opyuAUCPAwQ2vezKPB80pqjnBphKQsG++CnqhaQ8kbtEpIRHrP+fUkGEmgbAC7ymU2wtZGGGhisYxpVOw5xiPaiEU0zdzn1RqvAs+wqVXZNEk8WkuQabr0FgxHZ/EfIUufWIQy/LbVfTByzhuHZIsHypO7W4OSjoyd4ACUVCA+C8lwhhaGB3IiLRUaFq288UfgTQLbB8AOpXe6zmrP [email protected]
76 changes: 76 additions & 0 deletions examples/resize_base/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
provider "libvirt" {
uri = "qemu:///system"
}

resource "libvirt_volume" "os_image_ubuntu" {
name = "os_image_ubuntu"
pool = "default"
source = "https://cloud-images.ubuntu.com/releases/xenial/release/ubuntu-16.04-server-cloudimg-amd64-disk1.img"
}

resource "libvirt_volume" "disk_ubuntu_resized" {
name = "disk"
base_volume_id = "${libvirt_volume.os_image_ubuntu.id}"
pool = "default"
size = 5361393152
}

# Use CloudInit to add our ssh-key to the instance
resource "libvirt_cloudinit_disk" "cloudinit_ubuntu_resized" {
name = "cloudinit_ubuntu_resized.iso"
pool = "default"
user_data = <<EOF
#cloud-config
disable_root: 0
ssh_pwauth: 1
users:
- name: root
ssh-authorized-keys:
- ${file("id_rsa.pub")}
growpart:
mode: auto
devices: ['/']
EOF
}

resource "libvirt_domain" "domain_ubuntu_resized" {
name = "doman_ubuntu_resized"
memory = "512"
vcpu = 1

cloudinit = "${libvirt_cloudinit_disk.cloudinit_ubuntu_resized.id}"

network_interface {
network_name = "default"
wait_for_lease = true
}

# IMPORTANT
# Ubuntu can hang if an isa-serial is not present at boot time.
# If you find your CPU 100% and never is available this is why
console {
type = "pty"
target_port = "0"
target_type = "serial"
}

console {
type = "pty"
target_type = "virtio"
target_port = "1"
}

disk {
volume_id = "${libvirt_volume.disk_ubuntu_resized.id}"
}

graphics {
type = "spice"
listen_type = "address"
autoport = true
}
}

output "ip" {
value = "${libvirt_domain.domain_ubuntu_resized.network_interface.0.addresses.0}"
}
114 changes: 55 additions & 59 deletions libvirt/resource_libvirt_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,7 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error
volumeDef.Name = d.Get("name").(string)

var (
img image
volume *libvirt.StorageVol
img image
)

givenFormat, isFormatGiven := d.GetOk("format")
Expand Down Expand Up @@ -151,76 +150,73 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error
volumeDef.Capacity.Unit = "B"
volumeDef.Capacity.Value = size
} else {
_, noSize := d.GetOk("size")
_, noBaseVol := d.GetOk("base_volume_id")

if noSize && noBaseVol {
return fmt.Errorf("'size' needs to be specified if no 'source' or 'base_volume_id' is given")
}
volumeDef.Capacity.Value = uint64(d.Get("size").(int))
}

if baseVolumeID, ok := d.GetOk("base_volume_id"); ok {
if _, ok := d.GetOk("size"); ok {
return fmt.Errorf("'size' can't be specified when also 'base_volume_id' is given (the size will be set to the size of the backing image")
}
// the volume does not have a source image to upload, first handle
// whether it has a backing image
//
// backing images can be specified by either (id), or by (name, pool)
var baseVolume *libvirt.StorageVol

if _, ok := d.GetOk("base_volume_name"); ok {
return fmt.Errorf("'base_volume_name' can't be specified when also 'base_volume_id' is given")
}

volume = nil
baseVolume, err := client.libvirt.LookupStorageVolByKey(baseVolumeID.(string))
if err != nil {
return fmt.Errorf("Can't retrieve volume %s: %v", baseVolumeID.(string), err)
}
backingStoreDef, err := newDefBackingStoreFromLibvirt(baseVolume)
if err != nil {
return fmt.Errorf("Could not retrieve backing store %s", baseVolumeID.(string))
if baseVolumeID, ok := d.GetOk("base_volume_id"); ok {
if _, ok := d.GetOk("base_volume_name"); ok {
return fmt.Errorf("'base_volume_name' can't be specified when also 'base_volume_id' is given")
}
baseVolume, err = client.libvirt.LookupStorageVolByKey(baseVolumeID.(string))
if err != nil {
return fmt.Errorf("Can't retrieve volume %s: %v", baseVolumeID.(string), err)
}
}
volumeDef.BackingStore = &backingStoreDef
}

if baseVolumeName, ok := d.GetOk("base_volume_name"); ok {
if _, ok := d.GetOk("size"); ok {
return fmt.Errorf("'size' can't be specified when also 'base_volume_name' is given (the size will be set to the size of the backing image")
if baseVolumeName, ok := d.GetOk("base_volume_name"); ok {
baseVolumePool := pool
if _, ok := d.GetOk("base_volume_pool"); ok {
baseVolumePoolName := d.Get("base_volume_pool").(string)
baseVolumePool, err = client.libvirt.LookupStoragePoolByName(baseVolumePoolName)
if err != nil {
return fmt.Errorf("can't find storage pool '%s'", baseVolumePoolName)
}
defer baseVolumePool.Free()
}
baseVolume, err = baseVolumePool.LookupStorageVolByName(baseVolumeName.(string))
if err != nil {
return fmt.Errorf("Can't retrieve volume %s: %v", baseVolumeName.(string), err)
}
}

volume = nil
baseVolumePool := pool
if _, ok := d.GetOk("base_volume_pool"); ok {
baseVolumePoolName := d.Get("base_volume_pool").(string)
baseVolumePool, err = client.libvirt.LookupStoragePoolByName(baseVolumePoolName)
if baseVolume != nil {
backingStoreDef, err := newDefBackingStoreFromLibvirt(baseVolume)
if err != nil {
return fmt.Errorf("can't find storage pool '%s'", baseVolumePoolName)
return fmt.Errorf("Could not retrieve backing store definition: %s", err.Error())
}
defer baseVolumePool.Free()
}
baseVolume, err := baseVolumePool.LookupStorageVolByName(baseVolumeName.(string))
if err != nil {
return fmt.Errorf("Can't retrieve volume %s: %v", baseVolumeName.(string), err)
}
backingStoreDef, err := newDefBackingStoreFromLibvirt(baseVolume)
if err != nil {
return fmt.Errorf("Could not retrieve backing store %s", baseVolumeName.(string))

// does the backing store have some size information?, check at least that it is not smaller than the backing store
volumeDef.Capacity.Value = uint64(d.Get("size").(int))
if _, ok := d.GetOk("size"); ok {
backingStoreVolumeDef, err := newDefVolumeFromLibvirt(baseVolume)
if err != nil {
return err
}

if backingStoreVolumeDef.Capacity != nil && volumeDef.Capacity.Value < backingStoreVolumeDef.Capacity.Value {
return fmt.Errorf("When 'size' is specified, it shouldn't be smaller than the backing store specified with 'base_volume_id' or 'base_volume_name/base_volume_pool'")
}
}
volumeDef.BackingStore = &backingStoreDef
}
volumeDef.BackingStore = &backingStoreDef
}

if volume == nil {
volumeDefXML, err := xml.Marshal(volumeDef)
if err != nil {
return fmt.Errorf("Error serializing libvirt volume: %s", err)
}
volumeDef.Capacity.Value = uint64(d.Get("size").(int))
volumeDefXML, err := xml.Marshal(volumeDef)
if err != nil {
return fmt.Errorf("Error serializing libvirt volume: %s", err)
}

// create the volume
v, err := pool.StorageVolCreateXML(string(volumeDefXML), 0)
if err != nil {
return fmt.Errorf("Error creating libvirt volume: %s", err)
}
volume = v
defer volume.Free()
// create the volume
volume, err := pool.StorageVolCreateXML(string(volumeDefXML), 0)
if err != nil {
return fmt.Errorf("Error creating libvirt volume: %s", err)
}
defer volume.Free()

// we use the key as the id
key, err := volume.GetKey()
Expand Down
3 changes: 3 additions & 0 deletions website/docs/r/volume.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ The following arguments are supported:
* `size` - (Optional) The size of the volume in bytes (if you don't like this,
help fix [this issue](https://github.com/hashicorp/terraform/issues/3287).
If `source` is specified, `size` will be set to the source image file size.
`size` can be omitted if `source` is specified. `size` will then be set to the source image file size.
`size` can be omitted if `base_volume_id` or `base_volume_name` is specified. `size` will then be set to the base volume size.
If `size` is specified to be bigger than `base_volume_id` or `base_volume_name` size, you can use [cloudinit](https://cloudinit.readthedocs.io) if your OS supports it, with `libvirt_cloudinit_disk` and the [growpart](https://cloudinit.readthedocs.io/en/latest/topics/modules.html#growpart) module to resize the partition.
* `base_volume_id` - (Optional) The backing volume (CoW) to use for this volume.
* `base_volume_name` - (Optional) The name of the backing volume (CoW) to use
for this volume. Note well: when `base_volume_pool` is not specified the
Expand Down