summaryrefslogtreecommitdiff
path: root/libvirt/volume_def.go
blob: 7d33812816b78d4525a35f6d3d98962af4f67d7e (plain)
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
}