Skip to content

Commit 7fbe405

Browse files
Thomas Hippflavio
authored andcommitted
use libvirt-go-xml for volumes
Signed-off-by: Thomas Hipp <[email protected]>
1 parent b76cf35 commit 7fbe405

File tree

6 files changed

+85
-104
lines changed

6 files changed

+85
-104
lines changed

libvirt/cloudinit_def.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func (ci *defCloudInit) CreateAndUpload(virConn *libvirt.Connect) (string, error
9292
}
9393

9494
volumeDef.Capacity.Unit = "B"
95-
volumeDef.Capacity.Amount = size
95+
volumeDef.Capacity.Value = size
9696
volumeDef.Target.Format.Type = "raw"
9797

9898
volumeDefXml, err := xml.Marshal(volumeDef)

libvirt/coreos_ignition_def.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (ign *defIgnition) CreateAndUpload(virConn *libvirt.Connect) (string, error
7272
}
7373

7474
volumeDef.Capacity.Unit = "B"
75-
volumeDef.Capacity.Amount = size
75+
volumeDef.Capacity.Value = size
7676
volumeDef.Target.Format.Type = "raw"
7777

7878
volumeDefXml, err := xml.Marshal(volumeDef)
@@ -88,7 +88,7 @@ func (ign *defIgnition) CreateAndUpload(virConn *libvirt.Connect) (string, error
8888
defer volume.Free()
8989

9090
// upload ignition file
91-
err = img.Import(newCopier(virConn, volume, volumeDef.Capacity.Amount), volumeDef)
91+
err = img.Import(newCopier(virConn, volume, volumeDef.Capacity.Value), volumeDef)
9292
if err != nil {
9393
return "", fmt.Errorf("Error while uploading ignition file %s: %s", img.String(), err)
9494
}

libvirt/resource_libvirt_volume.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error
159159
} else {
160160
log.Printf("Image %s image is: %d bytes", img, size)
161161
volumeDef.Capacity.Unit = "B"
162-
volumeDef.Capacity.Amount = size
162+
volumeDef.Capacity.Value = size
163163
}
164164
} else {
165165
_, noSize := d.GetOk("size")
@@ -168,7 +168,7 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error
168168
if noSize && noBaseVol {
169169
return fmt.Errorf("'size' needs to be specified if no 'source' or 'base_volume_id' is given.")
170170
}
171-
volumeDef.Capacity.Amount = uint64(d.Get("size").(int))
171+
volumeDef.Capacity.Value = uint64(d.Get("size").(int))
172172
}
173173

174174
if baseVolumeId, ok := d.GetOk("base_volume_id"); ok {
@@ -250,7 +250,7 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error
250250

251251
// upload source if present
252252
if _, ok := d.GetOk("source"); ok {
253-
err = img.Import(newCopier(virConn, volume, volumeDef.Capacity.Amount), volumeDef)
253+
err = img.Import(newCopier(virConn, volume, volumeDef.Capacity.Value), volumeDef)
254254
if err != nil {
255255
return fmt.Errorf("Error while uploading source %s: %s", img.String(), err)
256256
}

libvirt/utils_volume.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@ import (
99
"os"
1010
"strconv"
1111
"strings"
12+
"time"
1213

1314
libvirt "github.com/libvirt/libvirt-go"
15+
"github.com/libvirt/libvirt-go-xml"
1416
)
1517

1618
// network transparent image
1719
type image interface {
1820
Size() (uint64, error)
19-
Import(func(io.Reader) error, defVolume) error
21+
Import(func(io.Reader) error, libvirtxml.StorageVolume) error
2022
String() string
2123
}
2224

@@ -41,8 +43,7 @@ func (i *localImage) Size() (uint64, error) {
4143
return uint64(fi.Size()), nil
4244
}
4345

44-
func (i *localImage) Import(copier func(io.Reader) error, vol defVolume) error {
45-
46+
func (i *localImage) Import(copier func(io.Reader) error, vol libvirtxml.StorageVolume) error {
4647
file, err := os.Open(i.path)
4748
defer file.Close()
4849
if err != nil {
@@ -53,9 +54,8 @@ func (i *localImage) Import(copier func(io.Reader) error, vol defVolume) error {
5354
return err
5455
} else {
5556
// we can skip the upload if the modification times are the same
56-
if vol.Target.Timestamps != nil && vol.Target.Timestamps.Modification != nil {
57-
modTime := UnixTimestamp{fi.ModTime()}
58-
if modTime == *vol.Target.Timestamps.Modification {
57+
if vol.Target.Timestamps != nil && vol.Target.Timestamps.Mtime != "" {
58+
if fi.ModTime() == timeFromEpoch(vol.Target.Timestamps.Mtime) {
5959
log.Printf("Modification time is the same: skipping image copy")
6060
return nil
6161
}
@@ -98,13 +98,12 @@ func (i *httpImage) Size() (uint64, error) {
9898
return uint64(length), nil
9999
}
100100

101-
func (i *httpImage) Import(copier func(io.Reader) error, vol defVolume) error {
101+
func (i *httpImage) Import(copier func(io.Reader) error, vol libvirtxml.StorageVolume) error {
102102
client := &http.Client{}
103103
req, _ := http.NewRequest("GET", i.url.String(), nil)
104104

105-
if vol.Target.Timestamps != nil && vol.Target.Timestamps.Modification != nil {
106-
t := vol.Target.Timestamps.Modification.UTC().Format(http.TimeFormat)
107-
req.Header.Set("If-Modified-Since", t)
105+
if vol.Target.Timestamps != nil && vol.Target.Timestamps.Mtime != "" {
106+
req.Header.Set("If-Modified-Since", timeFromEpoch(vol.Target.Timestamps.Mtime).UTC().Format(http.TimeFormat))
108107
}
109108
response, err := client.Do(req)
110109
defer response.Body.Close()
@@ -155,3 +154,15 @@ func newCopier(virConn *libvirt.Connect, volume *libvirt.StorageVol, size uint64
155154
}
156155
return copier
157156
}
157+
158+
func timeFromEpoch(str string) time.Time {
159+
var s, ns int
160+
161+
ts := strings.Split(str, ".")
162+
if len(ts) == 2 {
163+
ns, _ = strconv.Atoi(ts[1])
164+
}
165+
s, _ = strconv.Atoi(ts[0])
166+
167+
return time.Unix(int64(s), int64(ns))
168+
}

libvirt/utils_volume_test.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import (
66
"io/ioutil"
77
"os"
88
"testing"
9+
"time"
10+
11+
"github.com/libvirt/libvirt-go-xml"
912
)
1013

1114
func TestLocalImageDownload(t *testing.T) {
@@ -24,7 +27,6 @@ func TestLocalImageDownload(t *testing.T) {
2427
if err != nil {
2528
t.Fatal(err)
2629
}
27-
2830
url := fmt.Sprintf("file://%s", tmpfile.Name())
2931
image, err := newImage(url)
3032
if err != nil {
@@ -33,17 +35,16 @@ func TestLocalImageDownload(t *testing.T) {
3335

3436
t.Logf("Importing %s", url)
3537
vol := newDefVolume()
36-
modTime := UnixTimestamp{tmpfileStat.ModTime()}
37-
vol.Target.Timestamps = &defTimestamps{
38-
Modification: &modTime,
38+
vol.Target.Timestamps = &libvirtxml.StorageVolumeTargetTimestamps{
39+
Mtime: fmt.Sprintf("%d.%d", tmpfileStat.ModTime().Unix(), tmpfileStat.ModTime().Nanosecond()),
3940
}
4041

4142
copier := func(r io.Reader) error {
4243
t.Fatalf("ERROR: starting copy of %s... but the file is the same!", url)
4344
return nil
4445
}
4546
if err = image.Import(copier, vol); err != nil {
46-
t.Fatal("Could not copy image from %s: %v", url, err)
47+
t.Fatalf("Could not copy image from %s: %v", url, err)
4748
}
4849
t.Log("File not copied because modification time was the same")
4950
}
@@ -72,17 +73,34 @@ func TestRemoteImageDownload(t *testing.T) {
7273

7374
t.Logf("Importing %s", url)
7475
vol := newDefVolume()
75-
modTime := UnixTimestamp{tmpfileStat.ModTime()}
76-
vol.Target.Timestamps = &defTimestamps{
77-
Modification: &modTime,
76+
vol.Target.Timestamps = &libvirtxml.StorageVolumeTargetTimestamps{
77+
Mtime: fmt.Sprintf("%d.%d", tmpfileStat.ModTime().Unix(), tmpfileStat.ModTime().Nanosecond()),
7878
}
7979
copier := func(r io.Reader) error {
8080
t.Fatalf("ERROR: starting copy of %s... but the file is the same!", url)
8181
return nil
8282
}
8383
if err = image.Import(copier, vol); err != nil {
84-
t.Fatal("Could not copy image from %s: %v", url, err)
84+
t.Fatalf("Could not copy image from %s: %v", url, err)
8585
}
8686
t.Log("File not copied because modification time was the same")
8787

8888
}
89+
90+
func TestTimeFromEpoch(t *testing.T) {
91+
if ts := timeFromEpoch(""); ts.UnixNano() > 0 {
92+
t.Fatalf("expected timestamp '0.0', got %v.%v", ts.Unix(), ts.Nanosecond())
93+
}
94+
95+
if ts := timeFromEpoch("abc"); ts.UnixNano() > 0 {
96+
t.Fatalf("expected timestamp '0.0', got %v.%v", ts.Unix(), ts.Nanosecond())
97+
}
98+
99+
if ts := timeFromEpoch("123"); ts.UnixNano() != time.Unix(123, 0).UnixNano() {
100+
t.Fatalf("expected timestamp '123.0', got %v.%v", ts.Unix(), ts.Nanosecond())
101+
}
102+
103+
if ts := timeFromEpoch("123.456"); ts.UnixNano() != time.Unix(123, 456).UnixNano() {
104+
t.Fatalf("expected timestamp '123.456', got %v.%v", ts.Unix(), ts.Nanosecond())
105+
}
106+
}

libvirt/volume_def.go

Lines changed: 31 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -3,116 +3,68 @@ package libvirt
33
import (
44
"encoding/xml"
55
"fmt"
6-
"math"
7-
"strconv"
8-
"time"
96

107
libvirt "github.com/libvirt/libvirt-go"
8+
"github.com/libvirt/libvirt-go-xml"
119
)
1210

13-
type UnixTimestamp struct{ time.Time }
14-
15-
func (t *UnixTimestamp) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
16-
var content string
17-
if err := d.DecodeElement(&content, &start); err != nil {
18-
return err
19-
}
20-
21-
ts, err := strconv.ParseFloat(content, 64)
22-
if err != nil {
23-
return err
11+
func newDefVolume() libvirtxml.StorageVolume {
12+
return libvirtxml.StorageVolume{
13+
Target: &libvirtxml.StorageVolumeTarget{
14+
Format: &libvirtxml.StorageVolumeTargetFormat{
15+
Type: "qcow2",
16+
},
17+
Permissions: &libvirtxml.StorageVolumeTargetPermissions{
18+
Mode: "644",
19+
},
20+
},
21+
Capacity: &libvirtxml.StorageVolumeSize{
22+
Unit: "bytes",
23+
Value: 1,
24+
},
2425
}
25-
s, ns := math.Modf(ts)
26-
*t = UnixTimestamp{time.Time(time.Unix(int64(s), int64(ns)))}
27-
return nil
28-
}
29-
30-
func (t *UnixTimestamp) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
31-
s := t.UTC().Unix()
32-
ns := t.UTC().UnixNano()
33-
return e.EncodeElement(fmt.Sprintf("%d.%d", s, ns), start)
34-
}
35-
36-
type defTimestamps struct {
37-
Change *UnixTimestamp `xml:"ctime,omitempty"`
38-
Modification *UnixTimestamp `xml:"mtime,omitempty"`
39-
Access *UnixTimestamp `xml:"atime,omitempty"`
40-
}
41-
42-
type defBackingStore struct {
43-
Path string `xml:"path"`
44-
Format struct {
45-
Type string `xml:"type,attr"`
46-
} `xml:"format"`
47-
Timestamps *defTimestamps `xml:"timestamps,omitempty"`
48-
}
49-
50-
type defVolume struct {
51-
XMLName xml.Name `xml:"volume"`
52-
Name string `xml:"name"`
53-
Target struct {
54-
Format struct {
55-
Type string `xml:"type,attr"`
56-
} `xml:"format"`
57-
Permissions struct {
58-
Mode int `xml:"mode,omitempty"`
59-
} `xml:"permissions,omitempty"`
60-
Timestamps *defTimestamps `xml:"timestamps,omitempty"`
61-
} `xml:"target"`
62-
Allocation int `xml:"allocation"`
63-
Capacity struct {
64-
Unit string `xml:"unit,attr"`
65-
Amount uint64 `xml:"chardata"`
66-
} `xml:"capacity"`
67-
BackingStore *defBackingStore `xml:"backingStore,omitempty"`
68-
}
69-
70-
func newDefVolume() defVolume {
71-
volumeDef := defVolume{}
72-
volumeDef.Target.Format.Type = "qcow2"
73-
volumeDef.Target.Permissions.Mode = 644
74-
volumeDef.Capacity.Unit = "bytes"
75-
volumeDef.Capacity.Amount = 1
76-
return volumeDef
7726
}
7827

7928
// Creates a volume definition from a XML
80-
func newDefVolumeFromXML(s string) (defVolume, error) {
81-
var volumeDef defVolume
29+
func newDefVolumeFromXML(s string) (libvirtxml.StorageVolume, error) {
30+
var volumeDef libvirtxml.StorageVolume
8231
err := xml.Unmarshal([]byte(s), &volumeDef)
8332
if err != nil {
84-
return defVolume{}, err
33+
return libvirtxml.StorageVolume{}, err
8534
}
8635
return volumeDef, nil
8736
}
8837

89-
func newDefVolumeFromLibvirt(volume *libvirt.StorageVol) (defVolume, error) {
38+
func newDefVolumeFromLibvirt(volume *libvirt.StorageVol) (libvirtxml.StorageVolume, error) {
9039
name, err := volume.GetName()
9140
if err != nil {
92-
return defVolume{}, fmt.Errorf("could not get name for volume: %s.", err)
41+
return libvirtxml.StorageVolume{}, fmt.Errorf("could not get name for volume: %s.", err)
9342
}
9443
volumeDefXml, err := volume.GetXMLDesc(0)
9544
if err != nil {
96-
return defVolume{}, fmt.Errorf("could not get XML description for volume %s: %s.", name, err)
45+
return libvirtxml.StorageVolume{}, fmt.Errorf("could not get XML description for volume %s: %s.", name, err)
9746
}
9847
volumeDef, err := newDefVolumeFromXML(volumeDefXml)
9948
if err != nil {
100-
return defVolume{}, fmt.Errorf("could not get a volume definition from XML for %s: %s.", volumeDef.Name, err)
49+
return libvirtxml.StorageVolume{}, fmt.Errorf("could not get a volume definition from XML for %s: %s.", volumeDef.Name, err)
10150
}
10251
return volumeDef, nil
10352
}
10453

105-
func newDefBackingStoreFromLibvirt(baseVolume *libvirt.StorageVol) (defBackingStore, error) {
54+
func newDefBackingStoreFromLibvirt(baseVolume *libvirt.StorageVol) (libvirtxml.StorageVolumeBackingStore, error) {
10655
baseVolumeDef, err := newDefVolumeFromLibvirt(baseVolume)
10756
if err != nil {
108-
return defBackingStore{}, fmt.Errorf("could not get volume: %s.", err)
57+
return libvirtxml.StorageVolumeBackingStore{}, fmt.Errorf("could not get volume: %s.", err)
10958
}
11059
baseVolPath, err := baseVolume.GetPath()
11160
if err != nil {
112-
return defBackingStore{}, fmt.Errorf("could not get base image path: %s", err)
61+
return libvirtxml.StorageVolumeBackingStore{}, fmt.Errorf("could not get base image path: %s", err)
62+
}
63+
backingStoreDef := libvirtxml.StorageVolumeBackingStore{
64+
Path: baseVolPath,
65+
Format: &libvirtxml.StorageVolumeTargetFormat{
66+
Type: baseVolumeDef.Target.Format.Type,
67+
},
11368
}
114-
var backingStoreDef defBackingStore
115-
backingStoreDef.Path = baseVolPath
116-
backingStoreDef.Format.Type = baseVolumeDef.Target.Format.Type
11769
return backingStoreDef, nil
11870
}

0 commit comments

Comments
 (0)