[libvirt] [PATCH go-xml] Added Storage Pool and Storage Volume XML schemes.

Alexey Slaykovsky aslaikov at redhat.com
Fri Jan 6 14:09:59 UTC 2017


Signed-off-by: Alexey Slaykovsky <aslaikov at redhat.com>
---
 domain.go       |   9 +-
 domain_test.go  |   8 +-
 memory.go       |  31 +++++
 storage.go      | 159 ++++++++++++++++++++++
 storage_test.go | 413 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 609 insertions(+), 11 deletions(-)
 create mode 100644 memory.go
 create mode 100644 storage.go
 create mode 100644 storage_test.go

diff --git a/domain.go b/domain.go
index ec2bd02..f8833a1 100644
--- a/domain.go
+++ b/domain.go
@@ -121,11 +121,6 @@ type DomainDeviceList struct {
 	Videos      []DomainVideo      `xml:"video"`
 }
 
-type DomainMemory struct {
-	Value string `xml:",chardata"`
-	Unit  string `xml:"unit,attr"`
-}
-
 type DomainOSType struct {
 	Arch    string `xml:"arch,attr"`
 	Machine string `xml:"machine,attr"`
@@ -194,8 +189,8 @@ type Domain struct {
 	Type          string            `xml:"type,attr"`
 	Name          string            `xml:"name"`
 	UUID          *string           `xml:"uuid"`
-	Memory        *DomainMemory     `xml:"memory"`
-	CurrentMemory *DomainMemory     `xml:"currentMemory"`
+	Memory        *Memory           `xml:"memory"`
+	CurrentMemory *Memory           `xml:"currentMemory"`
 	Devices       *DomainDeviceList `xml:"devices"`
 	OS            *DomainOS         `xml:"os"`
 	SysInfo       *DomainSysInfo    `xml:"sysinfo"`
diff --git a/domain_test.go b/domain_test.go
index ae262e5..c22c384 100644
--- a/domain_test.go
+++ b/domain_test.go
@@ -125,13 +125,13 @@ var domainTestData = []struct {
 		Object: &Domain{
 			Type: "kvm",
 			Name: "test",
-			Memory: &DomainMemory{
+			Memory: &Memory{
 				Unit:  "KiB",
-				Value: "8192",
+				Value: 8192,
 			},
-			CurrentMemory: &DomainMemory{
+			CurrentMemory: &Memory{
 				Unit:  "KiB",
-				Value: "4096",
+				Value: 4096,
 			},
 			OS: &DomainOS{
 				Type: &DomainOSType{
diff --git a/memory.go b/memory.go
new file mode 100644
index 0000000..78844ac
--- /dev/null
+++ b/memory.go
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the libvirt-go-xml project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ */
+
+package libvirtxml
+
+type Memory struct {
+	Unit  string `xml:"unit,attr,omitempty"`
+	Value uint64 `xml:",chardata"`
+}
diff --git a/storage.go b/storage.go
new file mode 100644
index 0000000..eccbee5
--- /dev/null
+++ b/storage.go
@@ -0,0 +1,159 @@
+/*
+ * This file is part of the libvirt-go-xml project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ */
+
+package libvirtxml
+
+import "encoding/xml"
+
+type StorageFormat struct {
+	Type string `xml:"type,attr"`
+}
+
+type StoragePermissions struct {
+	Owner string `xml:"owner,omitempty"`
+	Group string `xml:"group,omitempty"`
+	Mode  string `xml:"mode,omitempty"`
+	Label string `xml:"label,omitempty"`
+}
+
+type StorageTargetEncryptionSecret struct {
+	Type string `xml:"type,attr,omitempty"`
+	UUID string `xml:"uuid,attr,omitempty"`
+}
+
+type StorageTargetEncryption struct {
+	Type   string                         `xml:"type,attr,omitempty"`
+	Format string                         `xml:"format,attr,omitempty"`
+	Secret *StorageTargetEncryptionSecret `xml:"secret"`
+}
+
+type StorageTargetTimestamps struct {
+	Atime string `xml:"atime"`
+	Mtime string `xml:"mtime"`
+	Ctime string `xml:"ctime"`
+}
+
+type StorageTargetFeature struct {
+	LazyRefcounts *struct{} `xml:"lazy_refcounts"`
+}
+
+type StorageTarget struct {
+	Path        string                   `xml:"path,omitempty"`
+	Format      *StorageFormat           `xml:"format"`
+	Permissions *StoragePermissions      `xml:"permissions"`
+	Timestamps  *StorageTargetTimestamps `xml:"timestamps"`
+	Compat      string                   `xml:"compat,omitempty"`
+	NoCOW       *struct{}                `xml:"nocow"`
+	Features    []StorageTargetFeature   `xml:"features"`
+	Encryption  *StorageTargetEncryption `xml:"encryption"`
+}
+
+type StoragePoolSourceHost struct {
+	Name string `xml:"name,attr"`
+}
+
+type StoragePoolSourceDevice struct {
+	Path          string `xml:"path,attr"`
+	PartSeparator string `xml:"part_separator,attr,omitempty"`
+}
+
+type StoragePoolSourceAuthSecret struct {
+	Usage string `xml:"usage,attr"`
+}
+
+type StoragePoolSourceAuth struct {
+	Type     string                       `xml:"type,attr"`
+	Username string                       `xml:"username,attr"`
+	Secret   *StoragePoolSourceAuthSecret `xml:"secret"`
+}
+
+type StoragePoolSourceVendor struct {
+	Name string `xml:"name,attr"`
+}
+
+type StoragePoolSourceProduct struct {
+	Name string `xml:"name,attr"`
+}
+
+type StoragePoolSourceAdapterParentAddrAddress struct {
+	Domain string `xml:"domain,attr"`
+	Bus    string `xml:"bus,attr"`
+	Slot   string `xml:"slot,attr"`
+	Addr   string `xml:"addr,attr"`
+}
+
+type StoragePoolSourceAdapterParentAddr struct {
+	UniqueID uint64                                     `xml:"unique_id,attr"`
+	Address  *StoragePoolSourceAdapterParentAddrAddress `xml:"address"`
+}
+
+type StoragePoolSourceAdapter struct {
+	Type       string                              `xml:"type,attr"`
+	Name       string                              `xml:"name,attr,omitempty"`
+	Parent     string                              `xml:"parent,attr,omitempty"`
+	WWNN       string                              `xml:"wwnn,attr,omitempty"`
+	WWPN       string                              `xml:"wwpn,attr,omitempty"`
+	ParentAddr *StoragePoolSourceAdapterParentAddr `xml:"parentaddr"`
+}
+
+type StoragePoolSource struct {
+	Host    *StoragePoolSourceHost    `xml:"host"`
+	Device  *StoragePoolSourceDevice  `xml:"device"`
+	Auth    *StoragePoolSourceAuth    `xml:"auth"`
+	Vendor  *StoragePoolSourceVendor  `xml:"vendor"`
+	Product *StoragePoolSourceProduct `xml:"product"`
+	Format  *StorageFormat            `xml:"format"`
+	Adapter *StoragePoolSourceAdapter `xml:"adapter"`
+}
+
+type StoragePool struct {
+	XMLName    xml.Name           `xml:"pool"`
+	Type       string             `xml:"type,attr"`
+	Name       string             `xml:"name"`
+	UUID       string             `xml:"uuid,omitempty"`
+	Allocation *Memory            `xml:"allocation"`
+	Capacity   *Memory            `xml:"capacity"`
+	Available  *Memory            `xml:"available"`
+	Target     *StorageTarget     `xml:"target"`
+	Source     *StoragePoolSource `xml:"source"`
+}
+
+type StorageVolumeBackingStore struct {
+	Path        string              `xml:"path"`
+	Format      *StorageFormat      `xml:"format"`
+	Permissions *StoragePermissions `xml:"permissions"`
+}
+
+type StorageVolume struct {
+	XMLName      xml.Name                   `xml:"volume"`
+	Type         string                     `xml:"type,attr,omitempty"`
+	Name         string                     `xml:"name"`
+	Key          string                     `xml:"key,omitempty"`
+	Allocation   *Memory                    `xml:"allocation"`
+	Capacity     *Memory                    `xml:"capacity"`
+	Physical     *Memory                    `xml:"physical"`
+	Target       *StorageTarget             `xml:"target"`
+	BackingStore *StorageVolumeBackingStore `xml:"backingStore"`
+}
diff --git a/storage_test.go b/storage_test.go
new file mode 100644
index 0000000..f47634a
--- /dev/null
+++ b/storage_test.go
@@ -0,0 +1,413 @@
+/*
+ * This file is part of the libvirt-go-xml project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ */
+
+package libvirtxml
+
+import (
+	"encoding/xml"
+	"strings"
+	"testing"
+)
+
+var storagePoolTestData = []struct {
+	Object   *StoragePool
+	Expected []string
+}{
+	{
+		Object: &StoragePool{
+			Type: "dir",
+			Name: "pool",
+			UUID: "3e3fce45-4f53-4fa7-bb32-11f34168b82b",
+			Allocation: &Memory{
+				Value: 1000000,
+			},
+			Capacity: &Memory{
+				Value: 5000000,
+			},
+			Available: &Memory{
+				Value: 3000000,
+			},
+		},
+		Expected: []string{
+			`<pool type="dir">`,
+			`  <name>pool</name>`,
+			`  <uuid>3e3fce45-4f53-4fa7-bb32-11f34168b82b</uuid>`,
+			`  <allocation>1000000</allocation>`,
+			`  <capacity>5000000</capacity>`,
+			`  <available>3000000</available>`,
+			`</pool>`,
+		},
+	},
+	{
+		Object: &StoragePool{
+			Type: "iscsi",
+			Name: "pool",
+			Source: &StoragePoolSource{
+				Host: &StoragePoolSourceHost{
+					Name: "host.example.com",
+				},
+				Device: &StoragePoolSourceDevice{
+					Path: "pool.example.com:iscsi-pool",
+				},
+				Auth: &StoragePoolSourceAuth{
+					Type:     "chap",
+					Username: "username",
+					Secret: &StoragePoolSourceAuthSecret{
+						Usage: "cluster",
+					},
+				},
+				Vendor: &StoragePoolSourceVendor{
+					Name: "vendor",
+				},
+				Product: &StoragePoolSourceProduct{
+					Name: "product",
+				},
+			},
+		},
+		Expected: []string{
+			`<pool type="iscsi">`,
+			`  <name>pool</name>`,
+			`  <source>`,
+			`    <host name="host.example.com"></host>`,
+			`    <device path="pool.example.com:iscsi-pool"></device>`,
+			`    <auth type="chap" username="username">`,
+			`      <secret usage="cluster"></secret>`,
+			`    </auth>`,
+			`    <vendor name="vendor"></vendor>`,
+			`    <product name="product"></product>`,
+			`  </source>`,
+			`</pool>`,
+		},
+	},
+	{
+		Object: &StoragePool{
+			Type: "disk",
+			Name: "pool",
+			Source: &StoragePoolSource{
+				Device: &StoragePoolSourceDevice{
+					Path:          "/dev/mapper/pool",
+					PartSeparator: "no",
+				},
+				Format: &StorageFormat{
+					Type: "gpt",
+				},
+			},
+		},
+		Expected: []string{
+			`<pool type="disk">`,
+			`  <name>pool</name>`,
+			`  <source>`,
+			`    <device path="/dev/mapper/pool" part_separator="no"></device>`,
+			`    <format type="gpt"></format>`,
+			`  </source>`,
+			`</pool>`,
+		},
+	},
+	{
+		Object: &StoragePool{
+			Type: "scsi",
+			Name: "pool",
+			Source: &StoragePoolSource{
+				Adapter: &StoragePoolSourceAdapter{
+					Type: "scsi_host",
+					Name: "scsi_host",
+				},
+			},
+		},
+		Expected: []string{
+			`<pool type="scsi">`,
+			`  <name>pool</name>`,
+			`  <source>`,
+			`    <adapter type="scsi_host" name="scsi_host"></adapter>`,
+			`  </source>`,
+			`</pool>`,
+		},
+	},
+	{
+		Object: &StoragePool{
+			Type: "scsi",
+			Name: "pool",
+			Source: &StoragePoolSource{
+				Adapter: &StoragePoolSourceAdapter{
+					Type: "scsi_host",
+					ParentAddr: &StoragePoolSourceAdapterParentAddr{
+						UniqueID: 1,
+						Address: &StoragePoolSourceAdapterParentAddrAddress{
+							Domain: "0x0000",
+							Bus:    "0x00",
+							Slot:   "0x1f",
+							Addr:   "0x2",
+						},
+					},
+				},
+			},
+		},
+		Expected: []string{
+			`<pool type="scsi">`,
+			`  <name>pool</name>`,
+			`  <source>`,
+			`    <adapter type="scsi_host">`,
+			`      <parentaddr unique_id="1">`,
+			`        <address domain="0x0000" bus="0x00" slot="0x1f" addr="0x2"></address>`,
+			`      </parentaddr>`,
+			`    </adapter>`,
+			`  </source>`,
+			`</pool>`,
+		},
+	},
+	{
+		Object: &StoragePool{
+			Type: "fs",
+			Name: "pool",
+			Source: &StoragePoolSource{
+				Adapter: &StoragePoolSourceAdapter{
+					Type:   "fc_host",
+					Parent: "scsi_parent",
+					WWNN:   "20000000c9831b4b",
+					WWPN:   "10000000c9831b4b",
+				},
+			},
+		},
+		Expected: []string{
+			`<pool type="fs">`,
+			`  <name>pool</name>`,
+			`  <source>`,
+			`    <adapter type="fc_host" parent="scsi_parent" wwnn="20000000c9831b4b" wwpn="10000000c9831b4b"></adapter>`,
+			`  </source>`,
+			`</pool>`,
+		},
+	},
+	{
+		Object: &StoragePool{
+			Type: "dir",
+			Name: "pool",
+			Target: &StorageTarget{
+				Path: "/pool",
+				Permissions: &StoragePermissions{
+					Owner: "1",
+					Group: "1",
+					Mode:  "0744",
+					Label: "pool",
+				},
+			},
+		},
+		Expected: []string{
+			`<pool type="dir">`,
+			`  <name>pool</name>`,
+			`  <target>`,
+			`    <path>/pool</path>`,
+			`    <permissions>`,
+			`      <owner>1</owner>`,
+			`      <group>1</group>`,
+			`      <mode>0744</mode>`,
+			`      <label>pool</label>`,
+			`    </permissions>`,
+			`  </target>`,
+			`</pool>`,
+		},
+	},
+}
+
+func TestStoragePool(t *testing.T) {
+	for _, test := range storagePoolTestData {
+		doc, err := xml.MarshalIndent(test.Object, "", "  ")
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		expect := strings.Join(test.Expected, "\n")
+
+		if string(doc) != expect {
+			t.Fatal("Bad xml:\n", string(doc), "\n does not match\n", expect, "\n")
+		}
+	}
+}
+
+var storageVolumeTestData = []struct {
+	Object   *StorageVolume
+	Expected []string
+}{
+	{
+		Object: &StorageVolume{
+			Type: "file",
+			Name: "file.img",
+			Key:  "/file.img",
+			Allocation: &Memory{
+				Value: 0,
+			},
+
+			Capacity: &Memory{
+				Unit:  "T",
+				Value: 1,
+			},
+		},
+		Expected: []string{
+			`<volume type="file">`,
+			`  <name>file.img</name>`,
+			`  <key>/file.img</key>`,
+			`  <allocation>0</allocation>`,
+			`  <capacity unit="T">1</capacity>`,
+			`</volume>`,
+		},
+	},
+	{
+		Object: &StorageVolume{
+			Type: "file",
+			Name: "file.img",
+			Target: &StorageTarget{
+				Path: "/file.img",
+				Format: &StorageFormat{
+					Type: "qcow2",
+				},
+				Permissions: &StoragePermissions{
+					Owner: "107",
+					Group: "107",
+					Mode:  "0744",
+					Label: "image",
+				},
+				Timestamps: &StorageTargetTimestamps{
+					Atime: "1341933637.273190990",
+					Mtime: "1341930622.047245868",
+					Ctime: "1341930622.047245868",
+				},
+				Compat: "1.1",
+				NoCOW:  &struct{}{},
+				Features: []StorageTargetFeature{
+					StorageTargetFeature{
+						LazyRefcounts: &struct{}{},
+					},
+				},
+			},
+		},
+		Expected: []string{
+			`<volume type="file">`,
+			`  <name>file.img</name>`,
+			`  <target>`,
+			`    <path>/file.img</path>`,
+			`    <format type="qcow2"></format>`,
+			`    <permissions>`,
+			`      <owner>107</owner>`,
+			`      <group>107</group>`,
+			`      <mode>0744</mode>`,
+			`      <label>image</label>`,
+			`    </permissions>`,
+			`    <timestamps>`,
+			`      <atime>1341933637.273190990</atime>`,
+			`      <mtime>1341930622.047245868</mtime>`,
+			`      <ctime>1341930622.047245868</ctime>`,
+			`    </timestamps>`,
+			`    <compat>1.1</compat>`,
+			`    <nocow></nocow>`,
+			`    <features>`,
+			`      <lazy_refcounts></lazy_refcounts>`,
+			`    </features>`,
+			`  </target>`,
+			`</volume>`,
+		},
+	},
+	{
+		Object: &StorageVolume{
+			Type: "file",
+			Name: "file.img",
+			BackingStore: &StorageVolumeBackingStore{
+				Path: "/master.img",
+				Format: &StorageFormat{
+					Type: "raw",
+				},
+				Permissions: &StoragePermissions{
+					Owner: "107",
+					Group: "107",
+					Mode:  "0744",
+					Label: "label",
+				},
+			},
+		},
+		Expected: []string{
+			`<volume type="file">`,
+			`  <name>file.img</name>`,
+			`  <backingStore>`,
+			`    <path>/master.img</path>`,
+			`    <format type="raw"></format>`,
+			`    <permissions>`,
+			`      <owner>107</owner>`,
+			`      <group>107</group>`,
+			`      <mode>0744</mode>`,
+			`      <label>label</label>`,
+			`    </permissions>`,
+			`  </backingStore>`,
+			`</volume>`,
+		},
+	},
+	{
+		Object: &StorageVolume{
+			Name: "luks.img",
+			Capacity: &Memory{
+				Unit:  "G",
+				Value: 5,
+			},
+			Target: &StorageTarget{
+				Path: "/luks.img",
+				Format: &StorageFormat{
+					Type: "raw",
+				},
+				Encryption: &StorageTargetEncryption{
+					Format: "luks",
+					Secret: &StorageTargetEncryptionSecret{
+						Type: "passphrase",
+						UUID: "f52a81b2-424e-490c-823d-6bd4235bc572",
+					},
+				},
+			},
+		},
+		Expected: []string{
+			`<volume>`,
+			`  <name>luks.img</name>`,
+			`  <capacity unit="G">5</capacity>`,
+			`  <target>`,
+			`    <path>/luks.img</path>`,
+			`    <format type="raw"></format>`,
+			`    <encryption format="luks">`,
+			`      <secret type="passphrase" uuid="f52a81b2-424e-490c-823d-6bd4235bc572"></secret>`,
+			`    </encryption>`,
+			`  </target>`,
+			`</volume>`,
+		},
+	},
+}
+
+func TestStorageVolume(t *testing.T) {
+	for _, test := range storageVolumeTestData {
+		doc, err := xml.MarshalIndent(test.Object, "", "  ")
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		expect := strings.Join(test.Expected, "\n")
+
+		if string(doc) != expect {
+			t.Fatal("Bad xml:\n", string(doc), "\n does not match\n", expect, "\n")
+		}
+	}
+}
-- 
2.11.0




More information about the libvir-list mailing list