diff options
author | Alvaro Saurin <alvaro.saurin@gmail.com> | 2017-03-15 12:53:28 +0100 |
---|---|---|
committer | Alvaro Saurin <alvaro.saurin@gmail.com> | 2017-03-29 18:17:23 +0200 |
commit | 81f7527f3597740b67d0430534e12ee0a1da1713 (patch) | |
tree | 63dabe1c1157ff71c7af5d0c333790bc67ed81a3 /libvirt/utils_volume.go | |
parent | a286dc5494691c2b04c48ef6695ed0c902912c0f (diff) | |
download | terraform-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.go | 120 |
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) + } +} |