1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
package libvirt
import (
"encoding/xml"
"fmt"
"math"
"strconv"
"time"
libvirt "github.com/libvirt/libvirt-go"
)
type UnixTimestamp struct{ time.Time }
func (t *UnixTimestamp) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var content string
if err := d.DecodeElement(&content, &start); err != nil {
return err
}
ts, err := strconv.ParseFloat(content, 64)
if err != nil {
return err
}
s, ns := math.Modf(ts)
*t = UnixTimestamp{time.Time(time.Unix(int64(s), int64(ns)))}
return nil
}
func (t *UnixTimestamp) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
s := t.UTC().Unix()
ns := t.UTC().UnixNano()
return e.EncodeElement(fmt.Sprintf("%d.%d", s, ns), start)
}
type defTimestamps struct {
Change *UnixTimestamp `xml:"ctime,omitempty"`
Modification *UnixTimestamp `xml:"mtime,omitempty"`
Access *UnixTimestamp `xml:"atime,omitempty"`
}
type defBackingStore struct {
Path string `xml:"path"`
Format struct {
Type string `xml:"type,attr"`
} `xml:"format"`
Timestamps *defTimestamps `xml:"timestamps,omitempty"`
}
type defVolume struct {
XMLName xml.Name `xml:"volume"`
Name string `xml:"name"`
Target struct {
Format struct {
Type string `xml:"type,attr"`
} `xml:"format"`
Permissions struct {
Mode int `xml:"mode,omitempty"`
} `xml:"permissions,omitempty"`
Timestamps *defTimestamps `xml:"timestamps,omitempty"`
} `xml:"target"`
Allocation int `xml:"allocation"`
Capacity struct {
Unit string `xml:"unit,attr"`
Amount uint64 `xml:"chardata"`
} `xml:"capacity"`
BackingStore *defBackingStore `xml:"backingStore,omitempty"`
}
func newDefVolume() defVolume {
volumeDef := defVolume{}
volumeDef.Target.Format.Type = "qcow2"
volumeDef.Target.Permissions.Mode = 644
volumeDef.Capacity.Unit = "bytes"
volumeDef.Capacity.Amount = 1
return volumeDef
}
// Creates a volume definition from a XML
func newDefVolumeFromXML(s string) (defVolume, error) {
var volumeDef defVolume
err := xml.Unmarshal([]byte(s), &volumeDef)
if err != nil {
return defVolume{}, err
}
return volumeDef, nil
}
func newDefVolumeFromLibvirt(volume *libvirt.StorageVol) (defVolume, error) {
name, err := volume.GetName()
if err != nil {
return defVolume{}, fmt.Errorf("could not get name for volume: %s.", err)
}
volumeDefXml, err := volume.GetXMLDesc(0)
if err != nil {
return defVolume{}, fmt.Errorf("could not get XML description for volume %s: %s.", name, err)
}
volumeDef, err := newDefVolumeFromXML(volumeDefXml)
if err != nil {
return defVolume{}, fmt.Errorf("could not get a volume definition from XML for %s: %s.", volumeDef.Name, err)
}
return volumeDef, nil
}
func newDefBackingStoreFromLibvirt(baseVolume *libvirt.StorageVol) (defBackingStore, error) {
baseVolumeDef, err := newDefVolumeFromLibvirt(baseVolume)
if err != nil {
return defBackingStore{}, fmt.Errorf("could not get volume: %s.", err)
}
baseVolPath, err := baseVolume.GetPath()
if err != nil {
return defBackingStore{}, fmt.Errorf("could not get base image path: %s", err)
}
var backingStoreDef defBackingStore
backingStoreDef.Path = baseVolPath
backingStoreDef.Format.Type = baseVolumeDef.Target.Format.Type
return backingStoreDef, nil
}
|