[lxc-devel] [lxd/master] Add network state API
monstermunchkin on Github
lxc-bot at linuxcontainers.org
Fri Jun 22 08:48:38 UTC 2018
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/20180622/4a5cdaa3/attachment.bin>
-------------- next part --------------
From 2613eb60df419c1854610cceacf06bb83c3804d1 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Fri, 22 Jun 2018 09:38:14 +0200
Subject: [PATCH 1/2] lxd,shared: Move parseNumberFromFile to shared
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/util/resources.go | 32 +++++++++-----------------------
shared/util.go | 15 +++++++++++++++
2 files changed, 24 insertions(+), 23 deletions(-)
diff --git a/lxd/util/resources.go b/lxd/util/resources.go
index 708062693..2b1f2b99a 100644
--- a/lxd/util/resources.go
+++ b/lxd/util/resources.go
@@ -8,6 +8,7 @@ import (
"strconv"
"strings"
+ "github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
)
@@ -21,21 +22,6 @@ type thread struct {
frequencyTurbo uint64
}
-func parseNumberFromFile(file string) (int64, error) {
- buf, err := ioutil.ReadFile(file)
- if err != nil {
- return int64(0), err
- }
-
- str := strings.TrimSpace(string(buf))
- nr, err := strconv.Atoi(str)
- if err != nil {
- return int64(0), err
- }
-
- return int64(nr), nil
-}
-
func parseCpuinfo() ([]thread, error) {
f, err := os.Open("/proc/cpuinfo")
if err != nil {
@@ -67,7 +53,7 @@ func parseCpuinfo() ([]thread, error) {
t.ID = uint64(id)
path := fmt.Sprintf("/sys/devices/system/cpu/cpu%d/topology/core_id", t.ID)
- coreID, err := parseNumberFromFile(path)
+ coreID, err := shared.ParseNumberFromFile(path)
if err != nil {
return nil, err
}
@@ -75,7 +61,7 @@ func parseCpuinfo() ([]thread, error) {
t.coreID = uint64(coreID)
path = fmt.Sprintf("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", t.ID)
- sockID, err := parseNumberFromFile(path)
+ sockID, err := shared.ParseNumberFromFile(path)
if err != nil {
return nil, err
}
@@ -83,7 +69,7 @@ func parseCpuinfo() ([]thread, error) {
t.socketID = uint64(sockID)
path = fmt.Sprintf("/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", t.ID)
- freq, err := parseNumberFromFile(path)
+ freq, err := shared.ParseNumberFromFile(path)
if err != nil {
if !os.IsNotExist(err) {
return nil, err
@@ -93,7 +79,7 @@ func parseCpuinfo() ([]thread, error) {
}
path = fmt.Sprintf("/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", t.ID)
- freq, err = parseNumberFromFile(path)
+ freq, err = shared.ParseNumberFromFile(path)
if err != nil {
if !os.IsNotExist(err) {
return nil, err
@@ -179,7 +165,7 @@ func parseSysDevSystemCPU() ([]thread, error) {
t := thread{}
t.ID = uint64(idx)
path := fmt.Sprintf("/sys/devices/system/cpu/cpu%d/topology/core_id", t.ID)
- coreID, err := parseNumberFromFile(path)
+ coreID, err := shared.ParseNumberFromFile(path)
if err != nil {
return nil, err
}
@@ -187,7 +173,7 @@ func parseSysDevSystemCPU() ([]thread, error) {
t.coreID = uint64(coreID)
path = fmt.Sprintf("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", t.ID)
- sockID, err := parseNumberFromFile(path)
+ sockID, err := shared.ParseNumberFromFile(path)
if err != nil {
return nil, err
}
@@ -195,7 +181,7 @@ func parseSysDevSystemCPU() ([]thread, error) {
t.socketID = uint64(sockID)
path = fmt.Sprintf("/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", t.ID)
- freq, err := parseNumberFromFile(path)
+ freq, err := shared.ParseNumberFromFile(path)
if err != nil {
if !os.IsNotExist(err) {
return nil, err
@@ -205,7 +191,7 @@ func parseSysDevSystemCPU() ([]thread, error) {
}
path = fmt.Sprintf("/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", t.ID)
- freq, err = parseNumberFromFile(path)
+ freq, err = shared.ParseNumberFromFile(path)
if err != nil {
if !os.IsNotExist(err) {
return nil, err
diff --git a/shared/util.go b/shared/util.go
index 8b264081a..61a834324 100644
--- a/shared/util.go
+++ b/shared/util.go
@@ -1047,3 +1047,18 @@ func downloadFileSha(httpClient *http.Client, useragent string, progress func(pr
return size, nil
}
+
+func ParseNumberFromFile(file string) (int64, error) {
+ buf, err := ioutil.ReadFile(file)
+ if err != nil {
+ return int64(0), err
+ }
+
+ str := strings.TrimSpace(string(buf))
+ nr, err := strconv.Atoi(str)
+ if err != nil {
+ return int64(0), err
+ }
+
+ return int64(nr), nil
+}
From 44f9e0ffc35d5a09d8fa7a9e7ca1b66f956f0ea4 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Fri, 22 Jun 2018 09:45:04 +0200
Subject: [PATCH 2/2] lxd,shared: Add network state API
Resolves #4665
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/api_1.0.go | 1 +
lxd/networks.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++----
shared/api/network.go | 20 ++++++++++++
shared/version/api.go | 1 +
4 files changed, 100 insertions(+), 6 deletions(-)
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index ad2bc7050..4853226c8 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -51,6 +51,7 @@ var api10 = []Command{
networksCmd,
networkCmd,
networkLeasesCmd,
+ networkStateCmd,
api10Cmd,
certificatesCmd,
certificateFingerprintCmd,
diff --git a/lxd/networks.go b/lxd/networks.go
index b3589c39a..cb06ae5e3 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -30,6 +30,31 @@ import (
// Lock to prevent concurent networks creation
var networkCreateLock sync.Mutex
+var networksCmd = Command{
+ name: "networks",
+ get: networksGet,
+ post: networksPost,
+}
+
+var networkCmd = Command{
+ name: "networks/{name}",
+ get: networkGet,
+ delete: networkDelete,
+ post: networkPost,
+ put: networkPut,
+ patch: networkPatch,
+}
+
+var networkLeasesCmd = Command{
+ name: "networks/{name}/leases",
+ get: networkLeasesGet,
+}
+
+var networkStateCmd = Command{
+ name: "networks/{name}/state",
+ get: networkStateGet,
+}
+
// API endpoints
func networksGet(d *Daemon, r *http.Request) Response {
recursion := util.IsRecursionRequest(r)
@@ -313,8 +338,6 @@ func doNetworksCreate(d *Daemon, req api.NetworksPost, withDatabase bool) error
return nil
}
-var networksCmd = Command{name: "networks", get: networksGet, post: networksPost}
-
func networkGet(d *Daemon, r *http.Request) Response {
// If a target was specified, forward the request to the relevant node.
response := ForwardedResponseIfTargetIsRemote(d, r)
@@ -626,8 +649,6 @@ func doNetworkUpdate(d *Daemon, name string, oldConfig map[string]string, req ap
return EmptySyncResponse
}
-var networkCmd = Command{name: "networks/{name}", get: networkGet, delete: networkDelete, post: networkPost, put: networkPut, patch: networkPatch}
-
func networkLeasesGet(d *Daemon, r *http.Request) Response {
name := mux.Vars(r)["name"]
leaseFile := shared.VarPath("networks", name, "dnsmasq.leases")
@@ -741,8 +762,6 @@ func networkLeasesGet(d *Daemon, r *http.Request) Response {
return SyncResponse(true, leases)
}
-var networkLeasesCmd = Command{name: "networks/{name}/leases", get: networkLeasesGet}
-
// The network structs and functions
func networkLoadByName(s *state.State, name string) (*network, error) {
id, dbInfo, err := s.Cluster.NetworkGet(name)
@@ -806,6 +825,59 @@ func networkShutdown(s *state.State) error {
return nil
}
+func networkStateGet(d *Daemon, r *http.Request) Response {
+ name := mux.Vars(r)["name"]
+
+ // Get some information
+ osInfo, _ := net.InterfaceByName(name)
+ _, dbInfo, _ := d.cluster.NetworkGet(name)
+
+ // Sanity check
+ if osInfo == nil && dbInfo == nil {
+ return NotFound(fmt.Errorf("Interface '%s' not found", name))
+ }
+
+ // Prepare the response
+ n := api.NetworkState{
+ MTU: osInfo.MTU,
+ Hwaddr: osInfo.HardwareAddr.String(),
+ }
+ addrs, err := osInfo.Addrs()
+ if err != nil {
+ return SmartError(err)
+ }
+
+ for _, addr := range addrs {
+ n.Addresses = append(n.Addresses, addr.String())
+ }
+
+ n.Stats.BytesTransmitted, err = shared.ParseNumberFromFile(
+ fmt.Sprintf("/sys/class/net/%s/statistics/tx_bytes", name))
+ if err != nil {
+ return SmartError(err)
+ }
+
+ n.Stats.BytesReceived, err = shared.ParseNumberFromFile(
+ fmt.Sprintf("/sys/class/net/%s/statistics/rx_bytes", name))
+ if err != nil {
+ return SmartError(err)
+ }
+
+ n.Stats.PacketsTransmitted, err = shared.ParseNumberFromFile(
+ fmt.Sprintf("/sys/class/net/%s/statistics/tx_packets", name))
+ if err != nil {
+ return SmartError(err)
+ }
+
+ n.Stats.PacketsReceived, err = shared.ParseNumberFromFile(
+ fmt.Sprintf("/sys/class/net/%s/statistics/rx_packets", name))
+ if err != nil {
+ return SmartError(err)
+ }
+
+ return SyncResponse(true, n)
+}
+
type network struct {
// Properties
db *db.Node
diff --git a/shared/api/network.go b/shared/api/network.go
index 19a0eae19..d26208262 100644
--- a/shared/api/network.go
+++ b/shared/api/network.go
@@ -58,3 +58,23 @@ type NetworkLease struct {
Address string `json:"address" yaml:"address"`
Type string `json:"type" yaml:"type"`
}
+
+// NetworkStateStats represents statistics about an interface
+//
+// API extension: network_state
+type NetworkStateStats struct {
+ BytesTransmitted int64 `json:"bytes_transmitted" yaml:"bytes_transmitted"`
+ BytesReceived int64 `json:"bytes_received" yaml:"bytes_received"`
+ PacketsTransmitted int64 `json:"packets_transmitted" yaml:"packets_transmitted"`
+ PacketsReceived int64 `json:"packets_received" yaml:"packets_received"`
+}
+
+// NetworkState represents the state of an interface
+//
+// API extension: network_state
+type NetworkState struct {
+ MTU int `json:"mtu" yaml:"mtu"`
+ Hwaddr string `json:"hwaddr" yaml:"hwaddr"`
+ Addresses []string `json:"addresses" yaml:"addresses"`
+ Stats NetworkStateStats `json:"stats" yaml:"stats"`
+}
diff --git a/shared/version/api.go b/shared/version/api.go
index 2acf2831d..3c23bf0dc 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -110,6 +110,7 @@ var APIExtensions = []string{
"proxy_udp",
"clustering_join",
"proxy_tcp_udp_multi_port_handling",
+ "network_state",
}
// APIExtensionsCount returns the number of available API extensions.
More information about the lxc-devel
mailing list