[lxc-devel] [lxd/master] Bugfixes

stgraber on Github lxc-bot at linuxcontainers.org
Wed Feb 15 21:48:05 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170215/854e752b/attachment.bin>
-------------- next part --------------
From 5f4f9c6bbadf58792bd707e2720385be67d9ffc0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Feb 2017 12:09:41 -0500
Subject: [PATCH 01/10] doc: Fix storage documentation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

 - No such thing as storage.default_pool
 - Fix markdown escaping
 - Align table columns

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 doc/configuration.md | 37 ++++++++++++++++++-------------------
 1 file changed, 18 insertions(+), 19 deletions(-)

diff --git a/doc/configuration.md b/doc/configuration.md
index b791fbd..a4532fa 100644
--- a/doc/configuration.md
+++ b/doc/configuration.md
@@ -36,7 +36,6 @@ storage.lvm\_volume\_size       | string    | 10GiB     | -
 storage.zfs\_pool\_name         | string    | -         | -                                 | ZFS pool name
 storage.zfs\_remove\_snapshots  | boolean   | false     | storage\_zfs\_remove\_snapshots   | Automatically remove any needed snapshot when attempting a container restore
 storage.zfs\_use\_refquota      | boolean   | false     | storage\_zfs\_use\_refquota       | Don't include snapshots as part of container quota (size property) or in reported disk usage
-storage.default_pool            | string    | -         | storage                           | The default storage pool on which to create containers.
 images.compression\_algorithm   | string    | gzip      | -                                 | Compression algorithm to use for new images (bzip2, gzip, lzma, xz or none)
 images.remote\_cache\_expiry    | integer   | 10        | -                                 | Number of days after which an unused cached remote image will be flushed
 images.auto\_update\_interval   | integer   | 6         | -                                 | Interval in hours at which to look for update to cached images (0 disables it)
@@ -386,17 +385,17 @@ overridden on a per-volume basis.
 
 ## Storage pool configuration
 
-Key                         | Type   | Condition                     | Default          | Description
-:--                         | :--    | :--                           | :--              | :--
-size                        | string | appropriate driver and source | 0                | Size of the storage pool in bytes (suffixes supported). (Currently valid for loop based pools and zfs.)
-source                      | string | -                             | -                | Path to block device or loop file or filesystem entry
-volume.block.filesystem     | string | block based driver (lvm)      | ext4             | Filesystem to use for new volumes
-volume.block.mount_options  | string | block based driver (lvm)      | discard          | Mount options for block devices
-volume.lvm.thinpool_name    | string | lvm driver                    | LXDPool          | Thin pool where images and containers are created.
-volume.size                 | string | appropriate driver            | 0                | Default volume size
-volume.zfs.remove_snapshots | bool   | zfs driver                    | false            | Remove snapshots as needed
-volume.zfs.use_refquota     | bool   | zfs driver                    | false            | Use refquota instead of quota for space.
-zfs.pool_name               | string | zfs driver                    | name of the pool | Name of the zpool
+Key                             | Type      | Condition                         | Default           | Description
+:--                             | :--       | :--                               | :--               | :--
+size                            | string    | appropriate driver and source     | 0                 | Size of the storage pool in bytes (suffixes supported). (Currently valid for loop based pools and zfs.)
+source                          | string    | -                                 | -                 | Path to block device or loop file or filesystem entry
+volume.block.filesystem         | string    | block based driver (lvm)          | ext4              | Filesystem to use for new volumes
+volume.block.mount\_options     | string    | block based driver (lvm)          | discard           | Mount options for block devices
+volume.lvm.thinpool\_name       | string    | lvm driver                        | LXDPool           | Thin pool where images and containers are created.
+volume.size                     | string    | appropriate driver                | 0                 | Default volume size
+volume.zfs.remove\_snapshots    | bool      | zfs driver                        | false             | Remove snapshots as needed
+volume.zfs.use\_refquota        | bool      | zfs driver                        | false             | Use refquota instead of quota for space.
+zfs.pool\_name                  | string    | zfs driver                        | name of the pool  | Name of the zpool
 
 Storage pool configuration keys can be set using the lxc tool with:
 
@@ -404,13 +403,13 @@ Storage pool configuration keys can be set using the lxc tool with:
 
 ## Storage volume configuration
 
-Key                  | Type   | Condition                | Default                             | Description
-:--                  | :--    | :--                      | :--                                 | :--
-size                 | string | appropriate driver       | 0                                   | Mount options for block devices
-block.filesystem     | string | block based driver (lvm) | ext4                                | Path to block device or loop file or filesystem entry
-block.mount_options  | string |                          | discard                             | Name of the storage driver (btrfs, dir, lvm, zfs)
-zfs.remove_snapshots | string | zfs driver               | same as volume.zfs.remove_snapshots | Default volume size
-zfs.use_refquota     | string | zfs driver               | same as volume.zfs.zfs_requota      | Filesystem to use for new volumes
+Key                     | Type      | Condition                 | Default                               | Description
+:--                     | :--       | :--                       | :--                                   | :--
+size                    | string    | appropriate driver        | 0                                     | Mount options for block devices
+block.filesystem        | string    | block based driver (lvm)  | ext4                                  | Path to block device or loop file or filesystem entry
+block.mount\_options    | string    |                           | discard                               | Name of the storage driver (btrfs, dir, lvm, zfs)
+zfs.remove\_snapshots   | string    | zfs driver                | same as volume.zfs.remove\_snapshots  | Default volume size
+zfs.use\_refquota       | string    | zfs driver                | same as volume.zfs.zfs\_requota       | Filesystem to use for new volumes
 
 Storage volume configuration keys can be set using the lxc tool with:
 

From f06fbe43cee910b9702fdaf1cca5a627d9098e5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Feb 2017 16:01:44 -0500
Subject: [PATCH 02/10] list: Fix regression in json output
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #2887

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxc/list.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxc/list.go b/lxc/list.go
index dad018d..fbbec03 100644
--- a/lxc/list.go
+++ b/lxc/list.go
@@ -368,8 +368,8 @@ func (c *listCmd) listContainers(d *lxd.Client, cinfos []api.Container, filters
 type listContainerItem struct {
 	*api.Container
 
-	State     *api.ContainerState
-	Snapshots []api.ContainerSnapshot
+	State     *api.ContainerState     `json:"state" yaml:"state"`
+	Snapshots []api.ContainerSnapshot `json:"snapshots" yaml:"snapshots"`
 }
 
 func (c *listCmd) run(config *lxd.Config, args []string) error {

From 8ac43624bfdb2393457429c617116ace94b4b47b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Feb 2017 16:02:19 -0500
Subject: [PATCH 03/10] api: Use consistent json and yaml field names
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This will allow us to change the struct members as we see fit without
impacting the output of our commands and on-disk files.

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/api/certificate.go        | 12 ++++----
 shared/api/container.go          | 62 ++++++++++++++++++-------------------
 shared/api/container_exec.go     | 20 ++++++------
 shared/api/container_snapshot.go | 30 +++++++++---------
 shared/api/container_state.go    | 66 ++++++++++++++++++++--------------------
 shared/api/image.go              | 56 +++++++++++++++++-----------------
 shared/api/network.go            | 18 +++++------
 shared/api/operation.go          | 20 ++++++------
 shared/api/profile.go            | 14 ++++-----
 shared/api/response.go           | 16 +++++-----
 shared/api/server.go             | 42 ++++++++++++-------------
 11 files changed, 178 insertions(+), 178 deletions(-)

diff --git a/shared/api/certificate.go b/shared/api/certificate.go
index 2dd0c51..56664fa 100644
--- a/shared/api/certificate.go
+++ b/shared/api/certificate.go
@@ -4,24 +4,24 @@ package api
 type CertificatesPost struct {
 	CertificatePut `yaml:",inline"`
 
-	Certificate string `json:"certificate"`
-	Password    string `json:"password"`
+	Certificate string `json:"certificate" yaml:"certificate"`
+	Password    string `json:"password" yaml:"password"`
 }
 
 // CertificatePut represents the modifiable fields of a LXD certificate
 //
 // API extension: certificate_update
 type CertificatePut struct {
-	Name string `json:"name"`
-	Type string `json:"type"`
+	Name string `json:"name" yaml:"name"`
+	Type string `json:"type" yaml:"type"`
 }
 
 // Certificate represents a LXD certificate
 type Certificate struct {
 	CertificatePut `yaml:",inline"`
 
-	Certificate string `json:"certificate"`
-	Fingerprint string `json:"fingerprint"`
+	Certificate string `json:"certificate" yaml:"certificate"`
+	Fingerprint string `json:"fingerprint" yaml:"fingerprint"`
 }
 
 // Writable converts a full Certificate struct into a CertificatePut struct (filters read-only fields)
diff --git a/shared/api/container.go b/shared/api/container.go
index 1c57590..33154bb 100644
--- a/shared/api/container.go
+++ b/shared/api/container.go
@@ -8,23 +8,23 @@ import (
 type ContainersPost struct {
 	ContainerPut `yaml:",inline"`
 
-	Name   string          `json:"name"`
-	Source ContainerSource `json:"source"`
+	Name   string          `json:"name" yaml:"name"`
+	Source ContainerSource `json:"source" yaml:"source"`
 }
 
 // ContainerPost represents the fields required to rename/move a LXD container
 type ContainerPost struct {
-	Migration bool   `json:"migration"`
-	Name      string `json:"name"`
+	Migration bool   `json:"migration" yaml:"migration"`
+	Name      string `json:"name" yaml:"name"`
 }
 
 // ContainerPut represents the modifiable fields of a LXD container
 type ContainerPut struct {
-	Architecture string                       `json:"architecture"`
-	Config       map[string]string            `json:"config"`
-	Devices      map[string]map[string]string `json:"devices"`
-	Ephemeral    bool                         `json:"ephemeral"`
-	Profiles     []string                     `json:"profiles"`
+	Architecture string                       `json:"architecture" yaml:"architecture"`
+	Config       map[string]string            `json:"config" yaml:"config"`
+	Devices      map[string]map[string]string `json:"devices" yaml:"devices"`
+	Ephemeral    bool                         `json:"ephemeral" yaml:"ephemeral"`
+	Profiles     []string                     `json:"profiles" yaml:"profiles"`
 	Restore      string                       `json:"restore,omitempty" yaml:"restore,omitempty"`
 }
 
@@ -32,16 +32,16 @@ type ContainerPut struct {
 type Container struct {
 	ContainerPut `yaml:",inline"`
 
-	CreatedAt       time.Time                    `json:"created_at"`
-	ExpandedConfig  map[string]string            `json:"expanded_config"`
-	ExpandedDevices map[string]map[string]string `json:"expanded_devices"`
-	Name            string                       `json:"name"`
-	Stateful        bool                         `json:"stateful"`
-	Status          string                       `json:"status"`
-	StatusCode      StatusCode                   `json:"status_code"`
+	CreatedAt       time.Time                    `json:"created_at" yaml:"created_at"`
+	ExpandedConfig  map[string]string            `json:"expanded_config" yaml:"expanded_config"`
+	ExpandedDevices map[string]map[string]string `json:"expanded_devices" yaml:"expanded_devices"`
+	Name            string                       `json:"name" yaml:"name"`
+	Stateful        bool                         `json:"stateful" yaml:"stateful"`
+	Status          string                       `json:"status" yaml:"status"`
+	StatusCode      StatusCode                   `json:"status_code" yaml:"status_code"`
 
 	// API extension: container_last_used_at
-	LastUsedAt time.Time `json:"last_used_at"`
+	LastUsedAt time.Time `json:"last_used_at" yaml:"last_used_at"`
 }
 
 // Writable converts a full Container struct into a ContainerPut struct (filters read-only fields)
@@ -63,28 +63,28 @@ func (c Container) IsActive() bool {
 
 // ContainerSource represents the creation source for a new container
 type ContainerSource struct {
-	Type        string `json:"type"`
-	Certificate string `json:"certificate"`
+	Type        string `json:"type" yaml:"type"`
+	Certificate string `json:"certificate" yaml:"certificate"`
 
 	// For "image" type
-	Alias       string            `json:"alias,omitempty"`
-	Fingerprint string            `json:"fingerprint,omitempty"`
-	Properties  map[string]string `json:"properties,omitempty"`
-	Server      string            `json:"server,omitempty"`
-	Secret      string            `json:"secret,omitempty"`
-	Protocol    string            `json:"protocol,omitempty"`
+	Alias       string            `json:"alias,omitempty" yaml:"alias,omitempty"`
+	Fingerprint string            `json:"fingerprint,omitempty" yaml:"fingerprint,omitempty"`
+	Properties  map[string]string `json:"properties,omitempty" yaml:"properties,omitempty"`
+	Server      string            `json:"server,omitempty" yaml:"server,omitempty"`
+	Secret      string            `json:"secret,omitempty" yaml:"secret,omitempty"`
+	Protocol    string            `json:"protocol,omitempty" yaml:"protocol,omitempty"`
 
 	// For "migration" and "copy" types
-	BaseImage string `json:"base-image,omitempty"`
+	BaseImage string `json:"base-image,omitempty" yaml:"base-image,omitempty"`
 
 	// For "migration" type
-	Mode       string            `json:"mode,omitempty"`
-	Operation  string            `json:"operation,omitempty"`
-	Websockets map[string]string `json:"secrets,omitempty"`
+	Mode       string            `json:"mode,omitempty" yaml:"mode,omitempty"`
+	Operation  string            `json:"operation,omitempty" yaml:"operation,omitempty"`
+	Websockets map[string]string `json:"secrets,omitempty" yaml:"secrets,omitempty"`
 
 	// API extension: container_push
-	Live bool `json:"live,omitempty"`
+	Live bool `json:"live,omitempty" yaml:"live,omitempty"`
 
 	// For "copy" type
-	Source string `json:"source,omitempty"`
+	Source string `json:"source,omitempty" yaml:"source,omitempty"`
 }
diff --git a/shared/api/container_exec.go b/shared/api/container_exec.go
index 09005ce..e243749 100644
--- a/shared/api/container_exec.go
+++ b/shared/api/container_exec.go
@@ -2,20 +2,20 @@ package api
 
 // ContainerExecControl represents a message on the container exec "control" socket
 type ContainerExecControl struct {
-	Command string            `json:"command"`
-	Args    map[string]string `json:"args"`
-	Signal  int               `json:"signal"`
+	Command string            `json:"command" yaml:"command"`
+	Args    map[string]string `json:"args" yaml:"args"`
+	Signal  int               `json:"signal" yaml:"signal"`
 }
 
 // ContainerExecPost represents a LXD container exec request
 type ContainerExecPost struct {
-	Command     []string          `json:"command"`
-	WaitForWS   bool              `json:"wait-for-websocket"`
-	Interactive bool              `json:"interactive"`
-	Environment map[string]string `json:"environment"`
-	Width       int               `json:"width"`
-	Height      int               `json:"height"`
+	Command     []string          `json:"command" yaml:"command"`
+	WaitForWS   bool              `json:"wait-for-websocket" yaml:"wait-for-websocket"`
+	Interactive bool              `json:"interactive" yaml:"interactive"`
+	Environment map[string]string `json:"environment" yaml:"environment"`
+	Width       int               `json:"width" yaml:"width"`
+	Height      int               `json:"height" yaml:"height"`
 
 	// API extension: container_exec_recording
-	RecordOutput bool `json:"record-output"`
+	RecordOutput bool `json:"record-output" yaml:"record-output"`
 }
diff --git a/shared/api/container_snapshot.go b/shared/api/container_snapshot.go
index ab65ab7..17e5d3a 100644
--- a/shared/api/container_snapshot.go
+++ b/shared/api/container_snapshot.go
@@ -6,27 +6,27 @@ import (
 
 // ContainerSnapshotsPost represents the fields available for a new LXD container snapshot
 type ContainerSnapshotsPost struct {
-	Name     string `json:"name"`
-	Stateful bool   `json:"stateful"`
+	Name     string `json:"name" yaml:"name"`
+	Stateful bool   `json:"stateful" yaml:"stateful"`
 }
 
 // ContainerSnapshotPost represents the fields required to rename/move a LXD container snapshot
 type ContainerSnapshotPost struct {
-	Name      string `json:"name"`
-	Migration bool   `json:"migration"`
+	Name      string `json:"name" yaml:"name"`
+	Migration bool   `json:"migration" yaml:"migration"`
 }
 
 // ContainerSnapshot represents a LXD conainer snapshot
 type ContainerSnapshot struct {
-	Architecture    string                       `json:"architecture"`
-	Config          map[string]string            `json:"config"`
-	CreationDate    time.Time                    `json:"created_at"`
-	Devices         map[string]map[string]string `json:"devices"`
-	Ephemeral       bool                         `json:"ephemeral"`
-	ExpandedConfig  map[string]string            `json:"expanded_config"`
-	ExpandedDevices map[string]map[string]string `json:"expanded_devices"`
-	LastUsedDate    time.Time                    `json:"last_used_at"`
-	Name            string                       `json:"name"`
-	Profiles        []string                     `json:"profiles"`
-	Stateful        bool                         `json:"stateful"`
+	Architecture    string                       `json:"architecture" yaml:"architecture"`
+	Config          map[string]string            `json:"config" yaml:"config"`
+	CreationDate    time.Time                    `json:"created_at" yaml:"created_at"`
+	Devices         map[string]map[string]string `json:"devices" yaml:"devices"`
+	Ephemeral       bool                         `json:"ephemeral" yaml:"ephemeral"`
+	ExpandedConfig  map[string]string            `json:"expanded_config" yaml:"expanded_config"`
+	ExpandedDevices map[string]map[string]string `json:"expanded_devices" yaml:"expanded_devices"`
+	LastUsedDate    time.Time                    `json:"last_used_at" yaml:"last_used_at"`
+	Name            string                       `json:"name" yaml:"name"`
+	Profiles        []string                     `json:"profiles" yaml:"profiles"`
+	Stateful        bool                         `json:"stateful" yaml:"stateful"`
 }
diff --git a/shared/api/container_state.go b/shared/api/container_state.go
index 9d38f4c..f9e1cb9 100644
--- a/shared/api/container_state.go
+++ b/shared/api/container_state.go
@@ -2,69 +2,69 @@ package api
 
 // ContainerStatePut represents the modifiable fields of a LXD container's state
 type ContainerStatePut struct {
-	Action   string `json:"action"`
-	Timeout  int    `json:"timeout"`
-	Force    bool   `json:"force"`
-	Stateful bool   `json:"stateful"`
+	Action   string `json:"action" yaml:"action"`
+	Timeout  int    `json:"timeout" yaml:"timeout"`
+	Force    bool   `json:"force" yaml:"force"`
+	Stateful bool   `json:"stateful" yaml:"stateful"`
 }
 
 // ContainerState represents a LXD container's state
 type ContainerState struct {
-	Status     string                           `json:"status"`
-	StatusCode StatusCode                       `json:"status_code"`
-	Disk       map[string]ContainerStateDisk    `json:"disk"`
-	Memory     ContainerStateMemory             `json:"memory"`
-	Network    map[string]ContainerStateNetwork `json:"network"`
-	Pid        int64                            `json:"pid"`
-	Processes  int64                            `json:"processes"`
+	Status     string                           `json:"status" yaml:"status"`
+	StatusCode StatusCode                       `json:"status_code" yaml:"status_code"`
+	Disk       map[string]ContainerStateDisk    `json:"disk" yaml:"disk"`
+	Memory     ContainerStateMemory             `json:"memory" yaml:"memory"`
+	Network    map[string]ContainerStateNetwork `json:"network" yaml:"network"`
+	Pid        int64                            `json:"pid" yaml:"pid"`
+	Processes  int64                            `json:"processes" yaml:"processes"`
 
 	// API extension: container_cpu_time
-	CPU ContainerStateCPU `json:"cpu"`
+	CPU ContainerStateCPU `json:"cpu" yaml:"cpu"`
 }
 
 // ContainerStateDisk represents the disk information section of a LXD container's state
 type ContainerStateDisk struct {
-	Usage int64 `json:"usage"`
+	Usage int64 `json:"usage" yaml:"usage"`
 }
 
 // ContainerStateCPU represents the cpu information section of a LXD container's state
 //
 // API extension: container_cpu_time
 type ContainerStateCPU struct {
-	Usage int64 `json:"usage"`
+	Usage int64 `json:"usage" yaml:"usage"`
 }
 
 // ContainerStateMemory represents the memory information section of a LXD container's state
 type ContainerStateMemory struct {
-	Usage         int64 `json:"usage"`
-	UsagePeak     int64 `json:"usage_peak"`
-	SwapUsage     int64 `json:"swap_usage"`
-	SwapUsagePeak int64 `json:"swap_usage_peak"`
+	Usage         int64 `json:"usage" yaml:"usage"`
+	UsagePeak     int64 `json:"usage_peak" yaml:"usage_peak"`
+	SwapUsage     int64 `json:"swap_usage" yaml:"swap_usage"`
+	SwapUsagePeak int64 `json:"swap_usage_peak" yaml:"swap_usage_peak"`
 }
 
 // ContainerStateNetwork represents the network information section of a LXD container's state
 type ContainerStateNetwork struct {
-	Addresses []ContainerStateNetworkAddress `json:"addresses"`
-	Counters  ContainerStateNetworkCounters  `json:"counters"`
-	Hwaddr    string                         `json:"hwaddr"`
-	HostName  string                         `json:"host_name"`
-	Mtu       int                            `json:"mtu"`
-	State     string                         `json:"state"`
-	Type      string                         `json:"type"`
+	Addresses []ContainerStateNetworkAddress `json:"addresses" yaml:"addresses"`
+	Counters  ContainerStateNetworkCounters  `json:"counters" yaml:"counters"`
+	Hwaddr    string                         `json:"hwaddr" yaml:"hwaddr"`
+	HostName  string                         `json:"host_name" yaml:"host_name"`
+	Mtu       int                            `json:"mtu" yaml:"mtu"`
+	State     string                         `json:"state" yaml:"state"`
+	Type      string                         `json:"type" yaml:"type"`
 }
 
 // ContainerStateNetworkAddress represents a network address as part of the network section of a LXD container's state
 type ContainerStateNetworkAddress struct {
-	Family  string `json:"family"`
-	Address string `json:"address"`
-	Netmask string `json:"netmask"`
-	Scope   string `json:"scope"`
+	Family  string `json:"family" yaml:"family"`
+	Address string `json:"address" yaml:"address"`
+	Netmask string `json:"netmask" yaml:"netmask"`
+	Scope   string `json:"scope" yaml:"scope"`
 }
 
 // ContainerStateNetworkCounters represents packet counters as part of the network section of a LXD container's state
 type ContainerStateNetworkCounters struct {
-	BytesReceived   int64 `json:"bytes_received"`
-	BytesSent       int64 `json:"bytes_sent"`
-	PacketsReceived int64 `json:"packets_received"`
-	PacketsSent     int64 `json:"packets_sent"`
+	BytesReceived   int64 `json:"bytes_received" yaml:"bytes_received"`
+	BytesSent       int64 `json:"bytes_sent" yaml:"bytes_sent"`
+	PacketsReceived int64 `json:"packets_received" yaml:"packets_received"`
+	PacketsSent     int64 `json:"packets_sent" yaml:"packets_sent"`
 }
diff --git a/shared/api/image.go b/shared/api/image.go
index e22667c..b162b82 100644
--- a/shared/api/image.go
+++ b/shared/api/image.go
@@ -8,36 +8,36 @@ import (
 type ImagesPost struct {
 	ImagePut `yaml:",inline"`
 
-	Filename string            `json:"filename"`
-	Source   map[string]string `json:"source"`
+	Filename string            `json:"filename" yaml:"filename"`
+	Source   map[string]string `json:"source" yaml:"source"`
 
 	// API extension: image_compression_algorithm
-	CompressionAlgorithm string `json:"compression_algorithm"`
+	CompressionAlgorithm string `json:"compression_algorithm" yaml:"compression_algorithm"`
 }
 
 // ImagePut represents the modifiable fields of a LXD image
 type ImagePut struct {
-	AutoUpdate bool              `json:"auto_update"`
-	Properties map[string]string `json:"properties"`
-	Public     bool              `json:"public"`
+	AutoUpdate bool              `json:"auto_update" yaml:"auto_update"`
+	Properties map[string]string `json:"properties" yaml:"properties"`
+	Public     bool              `json:"public" yaml:"public"`
 }
 
 // Image represents a LXD image
 type Image struct {
 	ImagePut `yaml:",inline"`
 
-	Aliases      []ImageAlias `json:"aliases"`
-	Architecture string       `json:"architecture"`
-	Cached       bool         `json:"cached"`
-	Filename     string       `json:"filename"`
-	Fingerprint  string       `json:"fingerprint"`
-	Size         int64        `json:"size"`
-	UpdateSource *ImageSource `json:"update_source,omitempty"`
-
-	CreatedAt  time.Time `json:"created_at"`
-	ExpiresAt  time.Time `json:"expires_at"`
-	LastUsedAt time.Time `json:"last_used_at"`
-	UploadedAt time.Time `json:"uploaded_at"`
+	Aliases      []ImageAlias `json:"aliases" yaml:"aliases"`
+	Architecture string       `json:"architecture" yaml:"architecture"`
+	Cached       bool         `json:"cached" yaml:"cached"`
+	Filename     string       `json:"filename" yaml:"filename"`
+	Fingerprint  string       `json:"fingerprint" yaml:"fingerprint"`
+	Size         int64        `json:"size" yaml:"size"`
+	UpdateSource *ImageSource `json:"update_source,omitempty" yaml:"update_source,omitempty"`
+
+	CreatedAt  time.Time `json:"created_at" yaml:"created_at"`
+	ExpiresAt  time.Time `json:"expires_at" yaml:"expires_at"`
+	LastUsedAt time.Time `json:"last_used_at" yaml:"last_used_at"`
+	UploadedAt time.Time `json:"uploaded_at" yaml:"uploaded_at"`
 }
 
 // Writable converts a full Image struct into a ImagePut struct (filters read-only fields)
@@ -47,16 +47,16 @@ func (img *Image) Writable() ImagePut {
 
 // ImageAlias represents an alias from the alias list of a LXD image
 type ImageAlias struct {
-	Name        string `json:"name"`
-	Description string `json:"description"`
+	Name        string `json:"name" yaml:"name"`
+	Description string `json:"description" yaml:"description"`
 }
 
 // ImageSource represents the source of a LXD image
 type ImageSource struct {
-	Alias       string `json:"alias"`
-	Certificate string `json:"certificate"`
-	Protocol    string `json:"protocol"`
-	Server      string `json:"server"`
+	Alias       string `json:"alias" yaml:"alias"`
+	Certificate string `json:"certificate" yaml:"certificate"`
+	Protocol    string `json:"protocol" yaml:"protocol"`
+	Server      string `json:"server" yaml:"server"`
 }
 
 // ImageAliasesPost represents a new LXD image alias
@@ -66,18 +66,18 @@ type ImageAliasesPost struct {
 
 // ImageAliasesEntryPost represents the required fields to rename a LXD image alias
 type ImageAliasesEntryPost struct {
-	Name string `json:"name"`
+	Name string `json:"name" yaml:"name"`
 }
 
 // ImageAliasesEntryPut represents the modifiable fields of a LXD image alias
 type ImageAliasesEntryPut struct {
-	Description string `json:"description"`
-	Target      string `json:"target"`
+	Description string `json:"description" yaml:"description"`
+	Target      string `json:"target" yaml:"target"`
 }
 
 // ImageAliasesEntry represents a LXD image alias
 type ImageAliasesEntry struct {
 	ImageAliasesEntryPut `yaml:",inline"`
 
-	Name string `json:"name"`
+	Name string `json:"name" yaml:"name"`
 }
diff --git a/shared/api/network.go b/shared/api/network.go
index 7773196..21db460 100644
--- a/shared/api/network.go
+++ b/shared/api/network.go
@@ -6,35 +6,35 @@ package api
 type NetworksPost struct {
 	NetworkPut `yaml:",inline"`
 
-	Managed bool   `json:"managed"`
-	Name    string `json:"name"`
-	Type    string `json:"type"`
+	Managed bool   `json:"managed" yaml:"managed"`
+	Name    string `json:"name" yaml:"name"`
+	Type    string `json:"type" yaml:"type"`
 }
 
 // NetworkPost represents the fields required to rename a LXD network
 //
 // API extension: network
 type NetworkPost struct {
-	Name string `json:"name"`
+	Name string `json:"name" yaml:"name"`
 }
 
 // NetworkPut represents the modifiable fields of a LXD network
 //
 // API extension: network
 type NetworkPut struct {
-	Config map[string]string `json:"config"`
+	Config map[string]string `json:"config" yaml:"config"`
 }
 
 // Network represents a LXD network
 type Network struct {
 	NetworkPut `yaml:",inline"`
 
-	Name   string   `json:"name"`
-	Type   string   `json:"type"`
-	UsedBy []string `json:"used_by"`
+	Name   string   `json:"name" yaml:"name"`
+	Type   string   `json:"type" yaml:"type"`
+	UsedBy []string `json:"used_by" yaml:"used_by"`
 
 	// API extension: network
-	Managed bool `json:"managed"`
+	Managed bool `json:"managed" yaml:"managed"`
 }
 
 // Writable converts a full Network struct into a NetworkPut struct (filters read-only fields)
diff --git a/shared/api/operation.go b/shared/api/operation.go
index 14db8fd..787c0cf 100644
--- a/shared/api/operation.go
+++ b/shared/api/operation.go
@@ -6,14 +6,14 @@ import (
 
 // Operation represents a LXD background operation
 type Operation struct {
-	ID         string                 `json:"id"`
-	Class      string                 `json:"class"`
-	CreatedAt  time.Time              `json:"created_at"`
-	UpdatedAt  time.Time              `json:"updated_at"`
-	Status     string                 `json:"status"`
-	StatusCode StatusCode             `json:"status_code"`
-	Resources  map[string][]string    `json:"resources"`
-	Metadata   map[string]interface{} `json:"metadata"`
-	MayCancel  bool                   `json:"may_cancel"`
-	Err        string                 `json:"err"`
+	ID         string                 `json:"id" yaml:"id"`
+	Class      string                 `json:"class" yaml:"class"`
+	CreatedAt  time.Time              `json:"created_at" yaml:"created_at"`
+	UpdatedAt  time.Time              `json:"updated_at" yaml:"updated_at"`
+	Status     string                 `json:"status" yaml:"status"`
+	StatusCode StatusCode             `json:"status_code" yaml:"status_code"`
+	Resources  map[string][]string    `json:"resources" yaml:"resources"`
+	Metadata   map[string]interface{} `json:"metadata" yaml:"metadata"`
+	MayCancel  bool                   `json:"may_cancel" yaml:"may_cancel"`
+	Err        string                 `json:"err" yaml:"err"`
 }
diff --git a/shared/api/profile.go b/shared/api/profile.go
index bb3a28a..c7d7f4e 100644
--- a/shared/api/profile.go
+++ b/shared/api/profile.go
@@ -4,29 +4,29 @@ package api
 type ProfilesPost struct {
 	ProfilePut `yaml:",inline"`
 
-	Name string `json:"name"`
+	Name string `json:"name" yaml:"name"`
 }
 
 // ProfilePost represents the fields required to rename a LXD profile
 type ProfilePost struct {
-	Name string `json:"name"`
+	Name string `json:"name" yaml:"name"`
 }
 
 // ProfilePut represents the modifiable fields of a LXD profile
 type ProfilePut struct {
-	Config      map[string]string            `json:"config"`
-	Description string                       `json:"description"`
-	Devices     map[string]map[string]string `json:"devices"`
+	Config      map[string]string            `json:"config" yaml:"config"`
+	Description string                       `json:"description" yaml:"description"`
+	Devices     map[string]map[string]string `json:"devices" yaml:"devices"`
 }
 
 // Profile represents a LXD profile
 type Profile struct {
 	ProfilePut `yaml:",inline"`
 
-	Name string `json:"name"`
+	Name string `json:"name" yaml:"name"`
 
 	// API extension: profile_usedby
-	UsedBy []string `json:"used_by"`
+	UsedBy []string `json:"used_by" yaml:"used_by"`
 }
 
 // Writable converts a full Profile struct into a ProfilePut struct (filters read-only fields)
diff --git a/shared/api/response.go b/shared/api/response.go
index a049c4c..71c7a0e 100644
--- a/shared/api/response.go
+++ b/shared/api/response.go
@@ -8,26 +8,26 @@ import (
 type ResponseRaw struct {
 	Response `yaml:",inline"`
 
-	Metadata interface{} `json:"metadata"`
+	Metadata interface{} `json:"metadata" yaml:"metadata"`
 }
 
 // Response represents a LXD operation
 type Response struct {
-	Type ResponseType `json:"type"`
+	Type ResponseType `json:"type" yaml:"type"`
 
 	// Valid only for Sync responses
-	Status     string `json:"status"`
-	StatusCode int    `json:"status_code"`
+	Status     string `json:"status" yaml:"status"`
+	StatusCode int    `json:"status_code" yaml:"status_code"`
 
 	// Valid only for Async responses
-	Operation string `json:"operation"`
+	Operation string `json:"operation" yaml:"operation"`
 
 	// Valid only for Error responses
-	Code  int    `json:"error_code"`
-	Error string `json:"error"`
+	Code  int    `json:"error_code" yaml:"error_code"`
+	Error string `json:"error" yaml:"error"`
 
 	// Valid for Sync and Error responses
-	Metadata json.RawMessage `json:"metadata"`
+	Metadata json.RawMessage `json:"metadata" yaml:"metadata"`
 }
 
 // MetadataAsMap parses the Response metadata into a map
diff --git a/shared/api/server.go b/shared/api/server.go
index 4790cea..53a4c81 100644
--- a/shared/api/server.go
+++ b/shared/api/server.go
@@ -2,34 +2,34 @@ package api
 
 // ServerEnvironment represents the read-only environment fields of a LXD server
 type ServerEnvironment struct {
-	Addresses              []string `json:"addresses"`
-	Architectures          []string `json:"architectures"`
-	Certificate            string   `json:"certificate"`
-	CertificateFingerprint string   `json:"certificate_fingerprint"`
-	Driver                 string   `json:"driver"`
-	DriverVersion          string   `json:"driver_version"`
-	Kernel                 string   `json:"kernel"`
-	KernelArchitecture     string   `json:"kernel_architecture"`
-	KernelVersion          string   `json:"kernel_version"`
-	Server                 string   `json:"server"`
-	ServerPid              int      `json:"server_pid"`
-	ServerVersion          string   `json:"server_version"`
-	Storage                string   `json:"storage"`
-	StorageVersion         string   `json:"storage_version"`
+	Addresses              []string `json:"addresses" yaml:"addresses"`
+	Architectures          []string `json:"architectures" yaml:"architectures"`
+	Certificate            string   `json:"certificate" yaml:"certificate"`
+	CertificateFingerprint string   `json:"certificate_fingerprint" yaml:"certificate_fingerprint"`
+	Driver                 string   `json:"driver" yaml:"driver"`
+	DriverVersion          string   `json:"driver_version" yaml:"driver_version"`
+	Kernel                 string   `json:"kernel" yaml:"kernel"`
+	KernelArchitecture     string   `json:"kernel_architecture" yaml:"kernel_architecture"`
+	KernelVersion          string   `json:"kernel_version" yaml:"kernel_version"`
+	Server                 string   `json:"server" yaml:"server"`
+	ServerPid              int      `json:"server_pid" yaml:"server_pid"`
+	ServerVersion          string   `json:"server_version" yaml:"server_version"`
+	Storage                string   `json:"storage" yaml:"storage"`
+	StorageVersion         string   `json:"storage_version" yaml:"storage_version"`
 }
 
 // ServerPut represents the modifiable fields of a LXD server configuration
 type ServerPut struct {
-	Config map[string]interface{} `json:"config"`
+	Config map[string]interface{} `json:"config" yaml:"config"`
 }
 
 // ServerUntrusted represents a LXD server for an untrusted client
 type ServerUntrusted struct {
-	APIExtensions []string `json:"api_extensions"`
-	APIStatus     string   `json:"api_status"`
-	APIVersion    string   `json:"api_version"`
-	Auth          string   `json:"auth"`
-	Public        bool     `json:"public"`
+	APIExtensions []string `json:"api_extensions" yaml:"api_extensions"`
+	APIStatus     string   `json:"api_status" yaml:"api_status"`
+	APIVersion    string   `json:"api_version" yaml:"api_version"`
+	Auth          string   `json:"auth" yaml:"auth"`
+	Public        bool     `json:"public" yaml:"public"`
 }
 
 // Server represents a LXD server
@@ -37,7 +37,7 @@ type Server struct {
 	ServerPut       `yaml:",inline"`
 	ServerUntrusted `yaml:",inline"`
 
-	Environment ServerEnvironment `json:"environment"`
+	Environment ServerEnvironment `json:"environment" yaml:"environment"`
 }
 
 // Writable converts a full Server struct into a ServerPut struct (filters read-only fields)

From 164a1110270b2c67e2c3e9bbfbe45099ae20b741 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Feb 2017 16:05:43 -0500
Subject: [PATCH 04/10] tests: Fix mixed tab/spaces
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 test/suites/storage.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/suites/storage.sh b/test/suites/storage.sh
index e90bc1c..9b010c1 100644
--- a/test/suites/storage.sh
+++ b/test/suites/storage.sh
@@ -121,7 +121,7 @@ test_storage() {
     ARCH=$(getconf LONG_BIT)
     BACKEND=btrfs
     if [ "${ARCH}" = "64" ]; then
-	    BACKEND=zfs
+      BACKEND=zfs
     fi
 
     # Create loop file zfs pool.

From 5d61dde793ad5e7fb3e60d54429ab752e1534852 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Feb 2017 16:12:00 -0500
Subject: [PATCH 05/10] scripts: Remove lxd-setup-lvm-storage
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Now replaced by the storage pool mechanism.

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 scripts/lxd-setup-lvm-storage | 230 ------------------------------------------
 1 file changed, 230 deletions(-)
 delete mode 100755 scripts/lxd-setup-lvm-storage

diff --git a/scripts/lxd-setup-lvm-storage b/scripts/lxd-setup-lvm-storage
deleted file mode 100755
index 2a65d00..0000000
--- a/scripts/lxd-setup-lvm-storage
+++ /dev/null
@@ -1,230 +0,0 @@
-#!/usr/bin/env python3
-# Let's stick to core python3 modules
-import argparse
-import gettext
-import http.client
-import json
-import os
-import socket
-from subprocess import check_output
-import sys
-
-
-DEFAULT_VGNAME = "LXDStorage"
-
-_ = gettext.gettext
-gettext.textdomain("lxd")
-
-
-class FriendlyParser(argparse.ArgumentParser):
-    def error(self, message):
-        sys.stderr.write('error: %s\n' % message)
-        self.print_help()
-        sys.exit(2)
-
-
-class UnixHTTPConnection(http.client.HTTPConnection):
-    def __init__(self, path):
-        http.client.HTTPConnection.__init__(self, 'localhost')
-        self.path = path
-
-    def connect(self):
-        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        sock.connect(self.path)
-        self.sock = sock
-
-
-class LXD(object):
-    def __init__(self, path):
-        self.lxd = UnixHTTPConnection(path)
-
-    def rest_call(self, path, data=None, method="GET", headers={}):
-        if method == "GET" and data:
-            self.lxd.request(
-                method,
-                "%s?%s" % "&".join(["%s=%s" % (key, value)
-                                    for key, value in data.items()]), headers)
-        else:
-            self.lxd.request(method, path, data, headers)
-
-        r = self.lxd.getresponse()
-        d = json.loads(r.read().decode("utf-8"))
-        return r.status, d
-
-    def set_lvm_vgname(self, vgname):
-        self._set_lvm_config("storage.lvm_vg_name", vgname)
-
-    def set_lvm_poolname(self, poolname):
-        self._set_lvm_config("storage.lvm_thinpool_name", poolname)
-
-    def _set_lvm_config(self, key, val):
-        data = json.dumps({"config": {key: val}})
-
-        status, data = self.rest_call("/1.0", data, "PUT")
-
-        if status != 200:
-            sys.stderr.write("Error in setting vgname:{}\n{}\n".format(status,
-                                                                       data))
-            raise Exception("Failed to set vgname: %s" % val)
-
-    def get_server_config(self):
-        status, config = self.rest_call("/1.0", "", "GET")
-        if status != 200:
-            sys.stderr.write("Error in getting vgname\n")
-            raise Exception("Failed to get vgname")
-
-        return config["metadata"]["config"]
-
-
-def lxd_dir():
-    if "LXD_DIR" in os.environ:
-        return os.environ["LXD_DIR"]
-    else:
-        return "/var/lib/lxd"
-
-
-def connect_to_socket():
-    lxd_socket = os.path.join(lxd_dir(), "unix.socket")
-
-    if not os.path.exists(lxd_socket):
-        print(_("LXD isn't running."))
-        sys.exit(1)
-
-    return LXD(lxd_socket)
-
-
-def create_image(args):
-    imgfname = os.path.join(lxd_dir(), "{}.img".format(args.size))
-    rollbacks = []
-    try:
-        print("Creating sparse backing file {}".format(imgfname), flush=True)
-        check_output("truncate -s {} {}".format(args.size, imgfname),
-                     shell=True)
-        rollbacks.append("rm {}".format(imgfname))
-
-        print("Setting up loop device", flush=True)
-        pvloopdev = check_output("losetup -f", shell=True).decode().strip()
-        check_output("losetup {} {}".format(pvloopdev, imgfname), shell=True)
-        rollbacks.append("losetup -d " + pvloopdev)
-
-        print("Creating LVM PV {}".format(pvloopdev), flush=True)
-        check_output("pvcreate {}".format(pvloopdev), shell=True)
-        rollbacks.append("pvremove " + pvloopdev)
-
-        print("Creating LVM VG {}".format(DEFAULT_VGNAME), flush=True)
-        check_output("vgcreate {} {}".format(DEFAULT_VGNAME, pvloopdev),
-                     shell=True)
-        rollbacks.append("vgremove {}".format(DEFAULT_VGNAME))
-
-    except Exception as e:
-        sys.stderr.write("Error: {}. Cleaning up:\n".format(e))
-        for rbcmd in reversed(rollbacks):
-            sys.stderr.write("+ {}\n".format(rbcmd))
-            check_output(rbcmd, shell=True)
-        raise e
-
-
-def destroy_image(args, lxd):
-    print("Checking current LXD configuration", flush=True)
-    cfg = lxd.get_server_config()
-    vgname = cfg.get("storage.lvm_vg_name", None)
-    if vgname is None:
-        sys.stderr.write("LXD is not configured for LVM. "
-                         "No changes will be made.\n")
-        return
-
-    lvnames = check_output("lvs {} -o name,lv_attr --noheadings"
-                           .format(vgname), shell=True).decode().strip()
-    used_lvs = []
-    for lvline in lvnames.split("\n"):
-        if lvline == '':
-            continue
-        name, attrs = lvline.split()
-        if attrs.strip().startswith("V"):
-            used_lvs.append(name)
-    if len(used_lvs) > 0:
-        print("LVM storage is still in use by the following volumes: {}"
-              .format(used_lvs))
-        print("Please delete the corresponding images and/or "
-              "containers before destroying storage.")
-        sys.exit()
-
-    pvname = check_output("vgs {} --noheadings -o pv_name"
-                          .format(vgname), shell=True).decode().strip()
-    print("Removing volume group {}".format(vgname))
-    check_output("vgremove -f {}".format(vgname), shell=True)
-    print("Removing physical volume {}".format(pvname))
-    check_output("pvremove -y {}".format(pvname), shell=True)
-
-    lostr = check_output("losetup -a | grep {}".format(pvname),
-                         shell=True).decode().strip()
-    imgfname = lostr.split('(')[-1].replace(')', '')
-    print("Detaching loop device {}".format(pvname))
-    check_output("losetup -d {}".format(pvname), shell=True)
-    print("Deleting backing file {}".format(imgfname))
-    if os.path.exists(imgfname):
-        check_output("rm '{}'".format(imgfname), shell=True)
-
-
-def do_main():
-    parser = FriendlyParser(
-        description=_("LXD: LVM storage helper"),
-        formatter_class=argparse.RawTextHelpFormatter,
-        epilog=_("""Examples:
- To create a 10G sparse loopback file and register it with LVM and LXD:
-    %s -s 10G
- To de-configure LXD and destroy the LVM volumes and backing file:
-    %s --destroy
-""" % (sys.argv[0], sys.argv[0])))
-    parser.add_argument("-s", "--size", default="10G",
-                        help=_("Size of backing file to register as LVM PV"))
-    parser.add_argument("--destroy", action="store_true", default=False,
-                        help=_("Un-configure LXD and delete image file"))
-
-    args = parser.parse_args()
-    if os.geteuid() != 0:
-        sys.exit("Configuring LVM requires root privileges.")
-
-    try:
-        check_output("type vgcreate", shell=True)
-    except:
-        sys.exit("lvm2 tools not found. try 'apt-get install lvm2 "
-                 "thin-provisioning-tools'")
-    try:
-        check_output("type thin_check", shell=True)
-    except:
-        sys.exit("lvm thin provisioning tools are required. "
-                 "try 'apt-get install thin-provisioning-tools'")
-
-    lxd = connect_to_socket()
-
-    if args.destroy:
-        try:
-            destroy_image(args, lxd)
-            print("Clearing LXD storage configuration")
-            lxd.set_lvm_vgname("")
-            lxd.set_lvm_poolname("")
-        except Exception as e:
-            sys.stderr.write("Error destroying image:")
-            sys.stderr.write(str(e))
-            sys.stderr.write("\n")
-
-    else:
-        try:
-            create_image(args)
-        except:
-            sys.stderr.write("Stopping.\n")
-        else:
-            try:
-                print("Configuring LXD")
-                lxd.set_lvm_vgname(DEFAULT_VGNAME)
-            except:
-                sys.stderr.write("Error configuring LXD, "
-                                 "removing backing file\n")
-                destroy_image(args, lxd)
-
-    print("Done.")
-
-
-if __name__ == "__main__":
-    do_main()

From f202eee103c3baad936deb2c4364c1a1c0357a86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Feb 2017 16:24:10 -0500
Subject: [PATCH 06/10] doc: Document the deprecated config options
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 doc/configuration.md | 46 +++++++++++++++++++++++-----------------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/doc/configuration.md b/doc/configuration.md
index a4532fa..daf972e 100644
--- a/doc/configuration.md
+++ b/doc/configuration.md
@@ -17,29 +17,29 @@ currently supported:
  - images (image configuration)
  - storage (storage configuration)
 
-Key                             | Type      | Default   | API extension                     | Description
-:--                             | :---      | :------   | :------------                     | :----------
-core.https\_address             | string    | -         | -                                 | Address to bind for the remote API
-core.https\_allowed\_origin     | string    | -         | -                                 | Access-Control-Allow-Origin http header value
-core.https\_allowed\_methods    | string    | -         | -                                 | Access-Control-Allow-Methods http header value
-core.https\_allowed\_headers    | string    | -         | -                                 | Access-Control-Allow-Headers http header value
-core.https\_allowed\_credentials| boolean   | -         | -                                 | Whether to set Access-Control-Allow-Credentials http header value to "true"
-core.proxy\_https               | string    | -         | -                                 | https proxy to use, if any (falls back to HTTPS\_PROXY environment variable)
-core.proxy\_http                | string    | -         | -                                 | http proxy to use, if any (falls back to HTTP\_PROXY environment variable)
-core.proxy\_ignore\_hosts       | string    | -         | -                                 | hosts which don't need the proxy for use (similar format to NO\_PROXY, e.g. 1.2.3.4,1.2.3.5, falls back to NO\_PROXY environment variable)
-core.trust\_password            | string    | -         | -                                 | Password to be provided by clients to setup a trust
-storage.lvm\_vg\_name           | string    | -         | -                                 | LVM Volume Group name to be used for container and image storage. A default Thin Pool is created using 100% of the free space in the Volume Group, unless `storage.lvm_thinpool_name` is set.
-storage.lvm\_thinpool\_name     | string    | "LXDPool" | -                                 | LVM Thin Pool to use within the Volume Group specified in `storage.lvm_vg_name`, if the default pool parameters are undesirable.
-storage.lvm\_fstype             | string    | ext4      | -                                 | Format LV with filesystem, for now it's value can be only ext4 (default) or xfs.
-storage.lvm\_mount\_options     | string    | discard   | storage\_lvm\_mount\_options      | Mount options for the LV filesystem
-storage.lvm\_volume\_size       | string    | 10GiB     | -                                 | Size of the logical volume
-storage.zfs\_pool\_name         | string    | -         | -                                 | ZFS pool name
-storage.zfs\_remove\_snapshots  | boolean   | false     | storage\_zfs\_remove\_snapshots   | Automatically remove any needed snapshot when attempting a container restore
-storage.zfs\_use\_refquota      | boolean   | false     | storage\_zfs\_use\_refquota       | Don't include snapshots as part of container quota (size property) or in reported disk usage
-images.compression\_algorithm   | string    | gzip      | -                                 | Compression algorithm to use for new images (bzip2, gzip, lzma, xz or none)
-images.remote\_cache\_expiry    | integer   | 10        | -                                 | Number of days after which an unused cached remote image will be flushed
-images.auto\_update\_interval   | integer   | 6         | -                                 | Interval in hours at which to look for update to cached images (0 disables it)
-images.auto\_update\_cached     | boolean   | true      | -                                 | Whether to automatically update any image that LXD caches
+Key                             | Type      | Default   | API extension                     | Deprecated                                    | Description
+:--                             | :---      | :------   | :------------                     | :---------                                    | :----------
+core.https\_address             | string    | -         | -                                 |                                               | Address to bind for the remote API
+core.https\_allowed\_origin     | string    | -         | -                                 |                                               | Access-Control-Allow-Origin http header value
+core.https\_allowed\_methods    | string    | -         | -                                 |                                               | Access-Control-Allow-Methods http header value
+core.https\_allowed\_headers    | string    | -         | -                                 |                                               | Access-Control-Allow-Headers http header value
+core.https\_allowed\_credentials| boolean   | -         | -                                 |                                               | Whether to set Access-Control-Allow-Credentials http header value to "true"
+core.proxy\_https               | string    | -         | -                                 |                                               | https proxy to use, if any (falls back to HTTPS\_PROXY environment variable)
+core.proxy\_http                | string    | -         | -                                 |                                               | http proxy to use, if any (falls back to HTTP\_PROXY environment variable)
+core.proxy\_ignore\_hosts       | string    | -         | -                                 |                                               | hosts which don't need the proxy for use (similar format to NO\_PROXY, e.g. 1.2.3.4,1.2.3.5, falls back to NO\_PROXY environment variable)
+core.trust\_password            | string    | -         | -                                 |                                               | Password to be provided by clients to setup a trust
+storage.lvm\_vg\_name           | string    | -         | -                                 | by pool source property                       | LVM Volume Group name to be used for container and image storage. A default Thin Pool is created using 100% of the free space in the Volume Group, unless `storage.lvm_thinpool_name` is set.
+storage.lvm\_thinpool\_name     | string    | "LXDPool" | -                                 | by volume.lvm.thinpool\_name pool property    | LVM Thin Pool to use within the Volume Group specified in `storage.lvm_vg_name`, if the default pool parameters are undesirable.
+storage.lvm\_fstype             | string    | ext4      | -                                 | by volume.block.filesystem pool property      | Format LV with filesystem, for now it's value can be only ext4 (default) or xfs.
+storage.lvm\_mount\_options     | string    | discard   | storage\_lvm\_mount\_options      | by volume.block.mount\_options pool property  | Mount options for the LV filesystem
+storage.lvm\_volume\_size       | string    | 10GiB     | -                                 | by volume.size pool property                  | Size of the logical volume
+storage.zfs\_pool\_name         | string    | -         | -                                 | by pool source property                       | ZFS pool name
+storage.zfs\_remove\_snapshots  | boolean   | false     | storage\_zfs\_remove\_snapshots   | by volume.zfs.remove\_snapshots pool property | Automatically remove any needed snapshot when attempting a container restore
+storage.zfs\_use\_refquota      | boolean   | false     | storage\_zfs\_use\_refquota       | by volume.zfs.use\_refquota pool property     | Don't include snapshots as part of container quota (size property) or in reported disk usage
+images.compression\_algorithm   | string    | gzip      | -                                 |                                               | Compression algorithm to use for new images (bzip2, gzip, lzma, xz or none)
+images.remote\_cache\_expiry    | integer   | 10        | -                                 |                                               | Number of days after which an unused cached remote image will be flushed
+images.auto\_update\_interval   | integer   | 6         | -                                 |                                               | Interval in hours at which to look for update to cached images (0 disables it)
+images.auto\_update\_cached     | boolean   | true      | -                                 |                                               | Whether to automatically update any image that LXD caches
 
 Those keys can be set using the lxc tool with:
 

From 6310b73ae9c40aecccfb6550bd05c63257fd1e56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Feb 2017 16:44:21 -0500
Subject: [PATCH 07/10] doc: Update README for new storage commands
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 README.md | 85 +++++++++++----------------------------------------------------
 1 file changed, 15 insertions(+), 70 deletions(-)

diff --git a/README.md b/README.md
index 7d46c27..5fdc5eb 100644
--- a/README.md
+++ b/README.md
@@ -223,85 +223,30 @@ certificate from `.config/lxc/client.crt` to the server and adding it with:
     lxc config trust add client.crt
 
 
-#### How do I configure alternative storage backends for LXD?
+#### How do I configure LXD storage?
 
-LXD supports various storage backends; below are instructions on how to
-configure some of them. By default, we use a simple directory backed storage
-mechanism, but we recommend using ZFS for best results.
+LXD supports btrfs, directory, lvm and zfs based storage.
 
-###### ZFS
+First make sure you have the relevant tools for your filesystem of
+choice installed on the machine (btrfs-progs, lvm2 or zfsutils-linux).
 
-First, you need to install the ZFS tooling. On Wily and above this is just:
+By default, LXD comes with no configured network or storage.
+You can get a basic configuration done with:
 
-    sudo apt-get install zfsutils-linux
+    sudo lxd init
 
-ZFS has many different ways to procure a zpool, which is what you need to feed
-LXD. For example, if you have an extra block device laying around, you can
-just:
+"lxd init" supports both directory based storage and ZFS.
+If you want something else, you'll need to use the "lxc storage" command:
 
-    sudo zpool create lxd /dev/sdc6 -m none
+    lxc storage create default BACKEND [OPTIONS...]
+    lxc profile device add default root disk path=/ pool=default
 
-However, if you want to test things out on a laptop or don't have an extra disk
-laying around, ZFS has its own loopback driver and can be used directly on a
-(sparse) file. To do this, first create the sparse file:
-
-    sudo truncate -s 100G /var/lib/lxd.img
-
-then,
-
-    sudo zpool create lxd /var/lib/lxd.img -m none
-
-Finally, whichever method you used to create your zpool, you need to tell LXD
-to use it:
-
-    lxc config set storage.zfs_pool_name lxd
-
-###### BTRFS
-
-The setup for btrfs is fairly simple, just mount /var/lib/lxd (or whatever your
-chosen `LXD_DIR` is) as a btrfs filesystem before you start LXD, and you're
-good to go. First install the btrfs userspace tools,
-
-    sudo apt-get install btrfs-tools
-
-Now, you need to create a btrfs filesystem. If you don't have an extra disk
-laying around, you'll have to create your own loopback device manually:
-
-    sudo truncate -s 100G /var/lib/lxd.img
-    sudo losetup /dev/loop0 /var/lib/lxd.img
-
-Once you've got a loopback device (or an actual device), you can create the
-btrfs filesystem and mount it:
-
-    sudo mkfs.btrfs /dev/loop0 # or your real device
-    sudo mount /dev/loop0 /var/lib/lxd
-
-###### LVM
-
-To set up LVM, the instructions are similar to the above. First, install the
-userspace tools:
-
-    sudo apt-get install lvm2 thin-provisioning-tools
-
-Then, if you have a block device laying around:
-
-    sudo pvcreate /dev/sdc6
-    sudo vgcreate lxd /dev/sdc6
-    lxc config set storage.lvm_vg_name lxd
-
-Alternatively, if you want to try it via a loopback device, there is a script
-provided in
-[/scripts/lxd-setup-lvm-storage](https://raw.githubusercontent.com/lxc/lxd/master/scripts/lxd-setup-lvm-storage)
-which will do it for you. It can be run via:
-
-    sudo apt-get install lvm2
-    ./scripts/lxd-setup-lvm-storage -s 10G
-
-And it has a --destroy argument to clean up the bits as well:
-
-    ./scripts/lxd-setup-lvm-storage --destroy
+BACKEND is one of "btrfs", "dir", "lvm" or "zfs".
 
+Unless specified otherwise, LXD will setup loop based storage with a sane default size.
 
+For production environments, you should be using block backed storage
+instead both for performance and reliability reasons.
 
 #### How can I live migrate a container using LXD?
 

From 4a2fdbd96c4e1bfeb5bdc770c65130436a9c142f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Feb 2017 16:44:43 -0500
Subject: [PATCH 08/10] storage: Remove references to deprecated options
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 doc/rest-api.md  | 2 +-
 lxd/images.go    | 2 +-
 lxd/main_init.go | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/doc/rest-api.md b/doc/rest-api.md
index d883338..6cedd23 100644
--- a/doc/rest-api.md
+++ b/doc/rest-api.md
@@ -282,7 +282,7 @@ Input (replaces any existing config with the provided one):
     {
         "config": {
             "core.trust_password": "my-new-password",
-            "storage.zfs_pool_name": "lxd"
+            "core.https_address": "1.2.3.4:8443"
         }
     }
 
diff --git a/lxd/images.go b/lxd/images.go
index 54d4a53..d483d2e 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -130,7 +130,7 @@ func unpack(d *Daemon, file string, path string, sType storageType) error {
 		// Check if we're running out of space
 		if int64(fs.Bfree) < int64(2*fs.Bsize) {
 			if sType == storageTypeLvm {
-				return fmt.Errorf("Unable to unpack image, run out of disk space (consider increasing storage.lvm_volume_size).")
+				return fmt.Errorf("Unable to unpack image, run out of disk space (consider increasing your pool's volume.size).")
 			} else {
 				return fmt.Errorf("Unable to unpack image, run out of disk space.")
 			}
diff --git a/lxd/main_init.go b/lxd/main_init.go
index 9e6d0f3..0063bd3 100644
--- a/lxd/main_init.go
+++ b/lxd/main_init.go
@@ -352,8 +352,8 @@ they otherwise would.
 	}
 
 	if storageSetup {
-		// Unset all storage keys, core.https_address and core.trust_password
-		for _, key := range []string{"storage.zfs_pool_name", "core.https_address", "core.trust_password"} {
+		// Unset core.https_address and core.trust_password
+		for _, key := range []string{"core.https_address", "core.trust_password"} {
 			_, err = c.SetServerConfig(key, "")
 			if err != nil {
 				return err

From 2e2effd9a289c8a0383b261a4b3f5b6663faf171 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Feb 2017 16:45:26 -0500
Subject: [PATCH 09/10] extra: Add ipv{4,6}.dhcp.expiry to bash completion
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 config/bash/lxd-client | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config/bash/lxd-client b/config/bash/lxd-client
index 6191b5a..e7efe70 100644
--- a/config/bash/lxd-client
+++ b/config/bash/lxd-client
@@ -74,8 +74,8 @@ _have lxc && {
 
     networks_keys="bridge.driver bridge.external_interfaces bridge.mtu bridge.mode \
       fan.underlay_subnet fan.overlay_subnet fan.type ipv4.address ipv4.nat ipv4.dhcp \
-      ipv4.dhcp.ranges ipv4.routing ipv6.address ipv6.nat ipv6.dhcp ipv6.dhcp.stateful \
-      ipv6.dhcp.ranges ipv6.routing dns.domain dns.mode raw.dnsmasq"
+      ipv4.dhcp.expiry ipv4.dhcp.ranges ipv4.routing ipv6.address ipv6.nat ipv6.dhcp ipv6.dhcp.stateful \
+      ipv6.dhcp.expiry ipv6.dhcp.ranges ipv6.routing dns.domain dns.mode raw.dnsmasq"
 
     if [ $COMP_CWORD -eq 1 ]; then
       COMPREPLY=( $(compgen -W "$lxc_cmds" -- ${COMP_WORDS[COMP_CWORD]}) )

From 5aaed610e7ce1873646fc0ec7d5326fcfe8497ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Feb 2017 16:46:04 -0500
Subject: [PATCH 10/10] extra: Add "lxc file delete" to bash completion
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 config/bash/lxd-client | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config/bash/lxd-client b/config/bash/lxd-client
index e7efe70..bdc3981 100644
--- a/config/bash/lxd-client
+++ b/config/bash/lxd-client
@@ -140,7 +140,7 @@ _have lxc && {
         _lxd_names "RUNNING"
         ;;
       "file")
-        COMPREPLY=( $(compgen -W "pull push edit" -- $cur) )
+        COMPREPLY=( $(compgen -W "pull push edit delete" -- $cur) )
         ;;
       "help")
         COMPREPLY=( $(compgen -W "$lxc_cmds" -- $cur) )


More information about the lxc-devel mailing list