diff options
author | Duncan Mac-Vicar P <dmacvicar@suse.de> | 2016-05-22 23:52:56 +0200 |
---|---|---|
committer | Duncan Mac-Vicar P <dmacvicar@suse.de> | 2016-05-22 23:52:56 +0200 |
commit | b0b5c0f1801c60d2d8a4ccccfefdbc562cab6502 (patch) | |
tree | 928f569f1d57fb67f6ca79df9ca142965ba99689 | |
parent | 9db44b5c0a6c21a7686ee7d41f01bf392bfe6a5d (diff) | |
download | terraform-provider-libvirt-b0b5c0f1801c60d2d8a4ccccfefdbc562cab6502.tar terraform-provider-libvirt-b0b5c0f1801c60d2d8a4ccccfefdbc562cab6502.tar.gz |
Add support for local files as source for base images. Closes #21.
-rw-r--r-- | libvirt/resource_libvirt_volume.go | 125 | ||||
-rw-r--r-- | libvirt/volume_def.go | 2 |
2 files changed, 115 insertions, 12 deletions
diff --git a/libvirt/resource_libvirt_volume.go b/libvirt/resource_libvirt_volume.go index fb20196e..b81e8af8 100644 --- a/libvirt/resource_libvirt_volume.go +++ b/libvirt/resource_libvirt_volume.go @@ -7,10 +7,106 @@ import ( "github.com/hashicorp/terraform/helper/schema" "io" "log" + "os" "net/http" + "net/url" "strconv" + "strings" ) +// network transparent image +type image interface { + Size() (int64, error) + WriteToStream(*libvirt.VirStream) error + String() string +} + +type localImage struct { + path string +} + +func (i *localImage) String() string { + return i.path +} + +func (i *localImage) Size() (int64, error) { + file, err := os.Open(i.path) + if err != nil { + return 0, err + } + + fi, err := file.Stat() + if err != nil { + return 0, err + } + return fi.Size(), nil +} + +func (i *localImage) WriteToStream(stream *libvirt.VirStream) error { + file, err := os.Open(i.path) + defer file.Close() + if err != nil { + return fmt.Errorf("Error while opening %s: %s", i.path, err) + } + + n, err := io.Copy(stream, file) + if err != nil { + return fmt.Errorf("Error while reading %s: %s", i.path, err) + } + log.Printf("%d bytes uploaded\n", n) + return nil +} + +type httpImage struct { + url *url.URL +} + +func (i *httpImage) String() string { + return i.url.String() +} + +func (i *httpImage) Size() (int64, error) { + response, err := http.Head(i.url.String()) + if err != nil { + return 0, err + } + length, err := strconv.Atoi(response.Header.Get("Content-Length")) + if err != nil { + return 0, err + } + return int64(length), nil +} + +func (i *httpImage) WriteToStream(stream *libvirt.VirStream) error { + response, err := http.Get(i.url.String()) + defer response.Body.Close() + if err != nil { + return fmt.Errorf("Error while downloading %s: %s", i.url.String(), err) + } + + n, err := io.Copy(stream, response.Body) + if err != nil { + return fmt.Errorf("Error while downloading %s: %s", i.url.String(), err) + } + log.Printf("%d bytes uploaded\n", n) + return nil +} + +func newImage(source string) (image, error) { + url, err := url.Parse(source) + if err != nil { + return nil, fmt.Errorf("Can't parse source '%s' as url: %s", source, err) + } + + if strings.HasPrefix(url.Scheme, "http") { + return &httpImage{url: url}, nil + } else if url.Scheme == "file" || url.Scheme == "" { + return &localImage{path: url.Path}, nil + } else { + return nil, fmt.Errorf("Don't know how to read from '%s': %s", url.String(), err) + } +} + func volumeCommonSchema() map[string]*schema.Schema { return map[string]*schema.Schema{ "name": &schema.Schema{ @@ -103,11 +199,17 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("'base_volume_id' can't be specified when also 'source' is given (the size will be set to the size of the base image.") } - size, err := remoteImageSize(url.(string)) + img, err := newImage(url.(string)) + if err != nil { + return err + } + + size, err := img.Size() if err != nil { return err } - log.Printf("Remote image is: %d bytes", size) + log.Printf("Image %s image is: %d bytes", img, size) + volumeDef.Capacity.Unit = "B" volumeDef.Capacity.Amount = size } else { @@ -117,7 +219,7 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error if noSize && noBaseVol { return fmt.Errorf("'size' needs to be specified if no 'source' or 'base_volume_id' is given.") } - volumeDef.Capacity.Amount = d.Get("size").(int) + volumeDef.Capacity.Amount = int64(d.Get("size").(int)) } if baseVolumeId, ok := d.GetOk("base_volume_id"); ok { @@ -159,22 +261,23 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error log.Printf("[INFO] Volume ID: %s", d.Id()) // upload source if present - if url, ok := d.GetOk("source"); ok { + if source, ok := d.GetOk("source"); ok { stream, err := libvirt.NewVirStream(virConn, 0) + if err != nil { + return err + } defer stream.Close() - volume.Upload(stream, 0, uint64(volumeDef.Capacity.Amount), 0) - response, err := http.Get(url.(string)) - defer response.Body.Close() + img, err := newImage(source.(string)) if err != nil { - return fmt.Errorf("Error while downloading %s: %s", url.(string), err) + return err } - n, err := io.Copy(stream, response.Body) + volume.Upload(stream, 0, uint64(volumeDef.Capacity.Amount), 0) + err = img.WriteToStream(stream) if err != nil { - return fmt.Errorf("Error while downloading %s: %s", url.(string), err) + return err } - log.Printf("%d bytes uploaded\n", n) } return resourceLibvirtVolumeRead(d, meta) diff --git a/libvirt/volume_def.go b/libvirt/volume_def.go index 3f4a9012..0e72123d 100644 --- a/libvirt/volume_def.go +++ b/libvirt/volume_def.go @@ -25,7 +25,7 @@ type defVolume struct { Allocation int `xml:"allocation"` Capacity struct { Unit string `xml:"unit,attr"` - Amount int `xml:"chardata"` + Amount int64 `xml:"chardata"` } `xml:"capacity"` BackingStore *defBackingStore `xml:"backingStore,omitempty"` } |