summaryrefslogtreecommitdiff
path: root/libvirt/utils_volume.go
diff options
context:
space:
mode:
authorAlvaro Saurin <alvaro.saurin@gmail.com>2017-03-15 12:53:28 +0100
committerAlvaro Saurin <alvaro.saurin@gmail.com>2017-03-29 18:17:23 +0200
commit81f7527f3597740b67d0430534e12ee0a1da1713 (patch)
tree63dabe1c1157ff71c7af5d0c333790bc67ed81a3 /libvirt/utils_volume.go
parenta286dc5494691c2b04c48ef6695ed0c902912c0f (diff)
downloadterraform-provider-libvirt-81f7527f3597740b67d0430534e12ee0a1da1713.tar
terraform-provider-libvirt-81f7527f3597740b67d0430534e12ee0a1da1713.tar.gz
Use If-Modified-Since for downloading images
Diffstat (limited to 'libvirt/utils_volume.go')
-rw-r--r--libvirt/utils_volume.go120
1 files changed, 120 insertions, 0 deletions
diff --git a/libvirt/utils_volume.go b/libvirt/utils_volume.go
new file mode 100644
index 00000000..6793124c
--- /dev/null
+++ b/libvirt/utils_volume.go
@@ -0,0 +1,120 @@
+package libvirt
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// network transparent image
+type image interface {
+ Size() (uint64, error)
+ Import(func(io.Reader) error, defVolume) error
+ String() string
+}
+
+type localImage struct {
+ path string
+}
+
+func (i *localImage) String() string {
+ return i.path
+}
+
+func (i *localImage) Size() (uint64, error) {
+ file, err := os.Open(i.path)
+ if err != nil {
+ return 0, err
+ }
+
+ fi, err := file.Stat()
+ if err != nil {
+ return 0, err
+ }
+ return uint64(fi.Size()), nil
+}
+
+func (i *localImage) Import(copier func(io.Reader) error, vol defVolume) error {
+
+ file, err := os.Open(i.path)
+ defer file.Close()
+ if err != nil {
+ return fmt.Errorf("Error while opening %s: %s", i.path, err)
+ }
+
+ if fi, err := file.Stat(); err != nil {
+ return err
+ } else {
+ // we can skip the upload if the modification times are the same
+ if vol.Target.Timestamps != nil && vol.Target.Timestamps.Modification != nil {
+ modTime := UnixTimestamp{fi.ModTime()}
+ if modTime == *vol.Target.Timestamps.Modification {
+ log.Printf("Modification time is the same: skipping image copy")
+ return nil
+ }
+ }
+ }
+
+ return copier(file)
+}
+
+type httpImage struct {
+ url *url.URL
+}
+
+func (i *httpImage) String() string {
+ return i.url.String()
+}
+
+func (i *httpImage) Size() (uint64, 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 uint64(length), nil
+}
+
+func (i *httpImage) Import(copier func(io.Reader) error, vol defVolume) error {
+ client := &http.Client{}
+ req, _ := http.NewRequest("GET", i.url.String(), nil)
+
+ if vol.Target.Timestamps != nil && vol.Target.Timestamps.Modification != nil {
+ t := vol.Target.Timestamps.Modification.UTC().Format(http.TimeFormat)
+ req.Header.Set("If-Modified-Since", t)
+ }
+ response, err := client.Do(req)
+ defer response.Body.Close()
+
+ if err != nil {
+ return fmt.Errorf("Error while downloading %s: %s", i.url.String(), err)
+ }
+ if response.StatusCode == http.StatusNotModified {
+ return nil
+ }
+
+ return copier(response.Body)
+}
+
+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)
+ }
+}