[lxc-devel] [lxd/master] Add description field to networks
albertodonato on Github
lxc-bot at linuxcontainers.org
Wed Apr 26 11:47:13 UTC 2017
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 379 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170426/d4ab5137/attachment.bin>
-------------- next part --------------
From d7053f8c4e4a1c88d623710064a95fa21fda5d57 Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.donato at canonical.com>
Date: Wed, 26 Apr 2017 11:05:07 +0200
Subject: [PATCH] Add description field to networks.
Signed-off-by: Alberto Donato <alberto.donato at canonical.com>
---
doc/api-extensions.md | 3 +++
doc/rest-api.md | 1 +
lxc/network.go | 3 ++-
lxd/api_1.0.go | 1 +
lxd/db.go | 1 +
lxd/db_networks.go | 23 ++++++++++++++++++-----
lxd/db_update.go | 6 ++++++
lxd/networks.go | 43 ++++++++++++++++++++++++-------------------
shared/api/network.go | 7 ++++---
test/suites/network.sh | 11 +++++++++++
10 files changed, 71 insertions(+), 28 deletions(-)
mode change 100644 => 100755 test/suites/network.sh
diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 8cf17f3..2c96f5d 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -264,3 +264,6 @@ places an upper limit on the amount of socket I/O allowed.
This introduces a new tunnel.NAME.interface option for networks.
This key control what host network interface is used for a VXLAN tunnel.
+
+## entity\_description
+This adds descriptions to entities like containers, snapshots, networks, storage pools and volumes.
diff --git a/doc/rest-api.md b/doc/rest-api.md
index 94a883c..8b92db3 100644
--- a/doc/rest-api.md
+++ b/doc/rest-api.md
@@ -1562,6 +1562,7 @@ Input:
{
"name": "my-network",
+ "description": "My network",
"config": {
"ipv4.address": "none",
"ipv6.address": "2001:470:b368:4242::1/64",
diff --git a/lxc/network.go b/lxc/network.go
index 920a67e..0fdea24 100644
--- a/lxc/network.go
+++ b/lxc/network.go
@@ -447,7 +447,7 @@ func (c *networkCmd) doNetworkList(config *lxd.Config, args []string) error {
}
strUsedBy := fmt.Sprintf("%d", len(network.UsedBy))
- data = append(data, []string{network.Name, network.Type, strManaged, strUsedBy})
+ data = append(data, []string{network.Name, network.Type, strManaged, network.Description, strUsedBy})
}
table := tablewriter.NewWriter(os.Stdout)
@@ -458,6 +458,7 @@ func (c *networkCmd) doNetworkList(config *lxd.Config, args []string) error {
i18n.G("NAME"),
i18n.G("TYPE"),
i18n.G("MANAGED"),
+ i18n.G("DESCRIPTION"),
i18n.G("USED BY")})
sort.Sort(byName(data))
table.AppendBulk(data)
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index bdf7c54..122a2c7 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -104,6 +104,7 @@ func api10Get(d *Daemon, r *http.Request) Response {
"storage_lvm_use_thinpool",
"storage_rsync_bwlimit",
"network_vxlan_interface",
+ "entity_description",
},
APIStatus: "stable",
APIVersion: version.APIVersion,
diff --git a/lxd/db.go b/lxd/db.go
index 923c293..49461dc 100644
--- a/lxd/db.go
+++ b/lxd/db.go
@@ -128,6 +128,7 @@ CREATE TABLE IF NOT EXISTS images_source (
CREATE TABLE IF NOT EXISTS networks (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
+ description TEXT,
UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS networks_config (
diff --git a/lxd/db_networks.go b/lxd/db_networks.go
index 3040617..425edf6 100644
--- a/lxd/db_networks.go
+++ b/lxd/db_networks.go
@@ -29,11 +29,12 @@ func dbNetworks(db *sql.DB) ([]string, error) {
}
func dbNetworkGet(db *sql.DB, name string) (int64, *api.Network, error) {
+ description := sql.NullString{}
id := int64(-1)
- q := "SELECT id FROM networks WHERE name=?"
+ q := "SELECT id, description FROM networks WHERE name=?"
arg1 := []interface{}{name}
- arg2 := []interface{}{&id}
+ arg2 := []interface{}{&id, &description}
err := dbQueryRowScan(db, q, arg1, arg2)
if err != nil {
return -1, nil, err
@@ -49,6 +50,7 @@ func dbNetworkGet(db *sql.DB, name string) (int64, *api.Network, error) {
Managed: true,
Type: "bridge",
}
+ network.Description = description.String
network.Config = config
return id, &network, nil
@@ -140,13 +142,13 @@ func dbNetworkConfigGet(db *sql.DB, id int64) (map[string]string, error) {
return config, nil
}
-func dbNetworkCreate(db *sql.DB, name string, config map[string]string) (int64, error) {
+func dbNetworkCreate(db *sql.DB, name, description string, config map[string]string) (int64, error) {
tx, err := dbBegin(db)
if err != nil {
return -1, err
}
- result, err := tx.Exec("INSERT INTO networks (name) VALUES (?)", name)
+ result, err := tx.Exec("INSERT INTO networks (name, description) VALUES (?, ?)", name, description)
if err != nil {
tx.Rollback()
return -1, err
@@ -172,7 +174,7 @@ func dbNetworkCreate(db *sql.DB, name string, config map[string]string) (int64,
return id, nil
}
-func dbNetworkUpdate(db *sql.DB, name string, config map[string]string) error {
+func dbNetworkUpdate(db *sql.DB, name, description string, config map[string]string) error {
id, _, err := dbNetworkGet(db, name)
if err != nil {
return err
@@ -183,6 +185,12 @@ func dbNetworkUpdate(db *sql.DB, name string, config map[string]string) error {
return err
}
+ err = dbNetworkUpdateDescription(tx, id, description)
+ if err != nil {
+ tx.Rollback()
+ return err
+ }
+
err = dbNetworkConfigClear(tx, id)
if err != nil {
tx.Rollback()
@@ -198,6 +206,11 @@ func dbNetworkUpdate(db *sql.DB, name string, config map[string]string) error {
return txCommit(tx)
}
+func dbNetworkUpdateDescription(tx *sql.Tx, id int64, description string) error {
+ _, err := tx.Exec("UPDATE networks SET description=? WHERE id=?", description, id)
+ return err
+}
+
func dbNetworkConfigAdd(tx *sql.Tx, id int64, config map[string]string) error {
str := fmt.Sprintf("INSERT INTO networks_config (network_id, key, value) VALUES(?, ?, ?)")
stmt, err := tx.Prepare(str)
diff --git a/lxd/db_update.go b/lxd/db_update.go
index ee1dc71..72c60d5 100644
--- a/lxd/db_update.go
+++ b/lxd/db_update.go
@@ -69,6 +69,7 @@ var dbUpdates = []dbUpdate{
{version: 33, run: dbUpdateFromV32},
{version: 34, run: dbUpdateFromV33},
{version: 35, run: dbUpdateFromV34},
+ {version: 36, run: dbUpdateFromV35},
}
type dbUpdate struct {
@@ -125,6 +126,11 @@ func dbUpdatesApplyAll(d *Daemon) error {
}
// Schema updates begin here
+func dbUpdateFromV35(currentVersion int, version int, d *Daemon) error {
+ _, err := d.db.Exec("ALTER TABLE networks ADD COLUMN description TEXT;")
+ return err
+}
+
func dbUpdateFromV34(currentVersion int, version int, d *Daemon) error {
stmt := `
CREATE TABLE IF NOT EXISTS storage_pools (
diff --git a/lxd/networks.go b/lxd/networks.go
index 1f54977..cefcb38 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -126,7 +126,7 @@ func networksPost(d *Daemon, r *http.Request) Response {
}
// Create the database entry
- _, err = dbNetworkCreate(d.db, req.Name, req.Config)
+ _, err = dbNetworkCreate(d.db, req.Name, req.Description, req.Config)
if err != nil {
return InternalError(
fmt.Errorf("Error inserting %s into database: %s", req.Name, err))
@@ -157,7 +157,7 @@ func networkGet(d *Daemon, r *http.Request) Response {
return SmartError(err)
}
- etag := []interface{}{n.Name, n.Managed, n.Type, n.Config}
+ etag := []interface{}{n.Name, n.Description, n.Managed, n.Type, n.Config}
return SyncResponseETag(true, &n, etag)
}
@@ -201,6 +201,7 @@ func doNetworkGet(d *Daemon, name string) (api.Network, error) {
} else if dbInfo != nil || shared.PathExists(fmt.Sprintf("/sys/class/net/%s/bridge", n.Name)) {
if dbInfo != nil {
n.Managed = true
+ n.Description = dbInfo.Description
n.Config = dbInfo.Config
}
@@ -301,7 +302,7 @@ func networkPut(d *Daemon, r *http.Request) Response {
}
// Validate the ETag
- etag := []interface{}{dbInfo.Name, dbInfo.Managed, dbInfo.Type, dbInfo.Config}
+ etag := []interface{}{dbInfo.Name, dbInfo.Managed, dbInfo.Type, dbInfo.Description, dbInfo.Config}
err = etagCheck(r, etag)
if err != nil {
@@ -313,7 +314,7 @@ func networkPut(d *Daemon, r *http.Request) Response {
return BadRequest(err)
}
- return doNetworkUpdate(d, name, dbInfo.Config, req.Config)
+ return doNetworkUpdate(d, name, dbInfo.Config, req)
}
func networkPatch(d *Daemon, r *http.Request) Response {
@@ -326,7 +327,7 @@ func networkPatch(d *Daemon, r *http.Request) Response {
}
// Validate the ETag
- etag := []interface{}{dbInfo.Name, dbInfo.Managed, dbInfo.Type, dbInfo.Config}
+ etag := []interface{}{dbInfo.Name, dbInfo.Managed, dbInfo.Type, dbInfo.Description, dbInfo.Config}
err = etagCheck(r, etag)
if err != nil {
@@ -350,20 +351,20 @@ func networkPatch(d *Daemon, r *http.Request) Response {
}
}
- return doNetworkUpdate(d, name, dbInfo.Config, req.Config)
+ return doNetworkUpdate(d, name, dbInfo.Config, req)
}
-func doNetworkUpdate(d *Daemon, name string, oldConfig map[string]string, newConfig map[string]string) Response {
+func doNetworkUpdate(d *Daemon, name string, oldConfig map[string]string, req api.NetworkPut) Response {
// Validate the configuration
- err := networkValidateConfig(name, newConfig)
+ err := networkValidateConfig(name, req.Config)
if err != nil {
return BadRequest(err)
}
// When switching to a fan bridge, auto-detect the underlay
- if newConfig["bridge.mode"] == "fan" {
- if newConfig["fan.underlay_subnet"] == "" {
- newConfig["fan.underlay_subnet"] = "auto"
+ if req.Config["bridge.mode"] == "fan" {
+ if req.Config["fan.underlay_subnet"] == "" {
+ req.Config["fan.underlay_subnet"] = "auto"
}
}
@@ -373,7 +374,7 @@ func doNetworkUpdate(d *Daemon, name string, oldConfig map[string]string, newCon
return NotFound
}
- err = n.Update(api.NetworkPut{Config: newConfig})
+ err = n.Update(req)
if err != nil {
return SmartError(err)
}
@@ -390,7 +391,7 @@ func networkLoadByName(d *Daemon, name string) (*network, error) {
return nil, err
}
- n := network{daemon: d, id: id, name: name, config: dbInfo.Config}
+ n := network{daemon: d, id: id, name: name, description: dbInfo.Description, config: dbInfo.Config}
return &n, nil
}
@@ -421,9 +422,10 @@ func networkStartup(d *Daemon) error {
type network struct {
// Properties
- daemon *Daemon
- id int64
- name string
+ daemon *Daemon
+ id int64
+ name string
+ description string
// config
config map[string]string
@@ -1271,6 +1273,7 @@ func (n *network) Update(newNetwork api.NetworkPut) error {
// Backup the current state
oldConfig := map[string]string{}
+ oldDescription := n.description
err = shared.DeepCopy(&n.config, &oldConfig)
if err != nil {
return err
@@ -1284,6 +1287,7 @@ func (n *network) Update(newNetwork api.NetworkPut) error {
defer func() {
if undoChanges {
n.config = oldConfig
+ n.description = oldDescription
}
}()
@@ -1315,7 +1319,7 @@ func (n *network) Update(newNetwork api.NetworkPut) error {
}
// Skip on no change
- if len(changedConfig) == 0 {
+ if len(changedConfig) == 0 && newNetwork.Description == n.description {
return nil
}
@@ -1351,11 +1355,12 @@ func (n *network) Update(newNetwork api.NetworkPut) error {
}
}
- // Apply the new configuration
+ // Apply changes
n.config = newConfig
+ n.description = newNetwork.Description
// Update the database
- err = dbNetworkUpdate(n.daemon.db, n.name, n.config)
+ err = dbNetworkUpdate(n.daemon.db, n.name, n.description, n.config)
if err != nil {
return err
}
diff --git a/shared/api/network.go b/shared/api/network.go
index 21db460..d5c5590 100644
--- a/shared/api/network.go
+++ b/shared/api/network.go
@@ -22,6 +22,7 @@ type NetworkPost struct {
//
// API extension: network
type NetworkPut struct {
+ Description string `json:"description" yaml:"description"`
Config map[string]string `json:"config" yaml:"config"`
}
@@ -29,9 +30,9 @@ type NetworkPut struct {
type Network struct {
NetworkPut `yaml:",inline"`
- Name string `json:"name" yaml:"name"`
- Type string `json:"type" yaml:"type"`
- UsedBy []string `json:"used_by" yaml:"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" yaml:"managed"`
diff --git a/test/suites/network.sh b/test/suites/network.sh
old mode 100644
new mode 100755
index fe66bea..6f8fc47
--- a/test/suites/network.sh
+++ b/test/suites/network.sh
@@ -1,6 +1,9 @@
#!/bin/sh
test_network() {
+ # shellcheck disable=2039
+ local config_file
+
ensure_import_testimage
ensure_has_localhost_remote "${LXD_ADDR}"
@@ -15,6 +18,14 @@ test_network() {
lxc network set lxdt$$ ipv6.dhcp.stateful true
lxc network delete lxdt$$
+ # edit network description
+ config_file=$(mktemp)
+ lxc network create lxdt$$
+ lxc network show lxdt$$ | sed 's/^description:/description: foo/' > "$config_file"
+ lxc network edit lxdt$$ < "$config_file"
+ lxc network show lxdt$$ | grep -q 'description: foo'
+ lxc network delete lxdt$$
+
# Unconfigured bridge
lxc network create lxdt$$ ipv4.address=none ipv6.address=none
lxc network delete lxdt$$
More information about the lxc-devel
mailing list