[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