The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/3831

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Closes #3819 
From fc6528884afba76fb96043f376d58f4f0271e991 Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.don...@canonical.com>
Date: Wed, 20 Sep 2017 15:18:06 +0200
Subject: [PATCH 1/6] shared/util: extract helper to get uname

Signed-off-by: Alberto Donato <alberto.don...@canonical.com>
---
 lxd/api_1.0.go                       | 42 ++++---------------------------
 shared/osarch/architectures_linux.go | 17 ++++---------
 shared/util_linux.go                 | 48 ++++++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 49 deletions(-)

diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 7b68acdb3..0dd41bfaa 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -6,7 +6,6 @@ import (
        "net/http"
        "os"
        "reflect"
-       "syscall"
 
        "gopkg.in/lxc/go-lxc.v2"
 
@@ -140,42 +139,11 @@ func api10Get(d *Daemon, r *http.Request) Response {
 
        srv.Auth = "trusted"
 
-       /*
-        * Based on: 
https://groups.google.com/forum/#!topic/golang-nuts/Jel8Bb-YwX8
-        * there is really no better way to do this, which is
-        * unfortunate. Also, we ditch the more accepted CharsToString
-        * version in that thread, since it doesn't seem as portable,
-        * viz. github issue #206.
-        */
-       uname := syscall.Utsname{}
-       if err := syscall.Uname(&uname); err != nil {
+       uname, err := shared.Uname()
+       if err != nil {
                return InternalError(err)
        }
 
-       kernel := ""
-       for _, c := range uname.Sysname {
-               if c == 0 {
-                       break
-               }
-               kernel += string(byte(c))
-       }
-
-       kernelVersion := ""
-       for _, c := range uname.Release {
-               if c == 0 {
-                       break
-               }
-               kernelVersion += string(byte(c))
-       }
-
-       kernelArchitecture := ""
-       for _, c := range uname.Machine {
-               if c == 0 {
-                       break
-               }
-               kernelArchitecture += string(byte(c))
-       }
-
        addresses, err := 
util.ListenAddresses(daemonConfig["core.https_address"].Get())
        if err != nil {
                return InternalError(err)
@@ -208,9 +176,9 @@ func api10Get(d *Daemon, r *http.Request) Response {
                CertificateFingerprint: certificateFingerprint,
                Driver:                 "lxc",
                DriverVersion:          lxc.Version(),
-               Kernel:                 kernel,
-               KernelArchitecture:     kernelArchitecture,
-               KernelVersion:          kernelVersion,
+               Kernel:                 uname.Sysname,
+               KernelArchitecture:     uname.Machine,
+               KernelVersion:          uname.Release,
                Server:                 "lxd",
                ServerPid:              os.Getpid(),
                ServerVersion:          version.Version}
diff --git a/shared/osarch/architectures_linux.go 
b/shared/osarch/architectures_linux.go
index c95b58a73..a87e795a8 100644
--- a/shared/osarch/architectures_linux.go
+++ b/shared/osarch/architectures_linux.go
@@ -3,22 +3,15 @@
 package osarch
 
 import (
-       "syscall"
+       "github.com/lxc/lxd/shared"
 )
 
+// ArchitectureGetLocal returns the local hardware architecture
 func ArchitectureGetLocal() (string, error) {
-       uname := syscall.Utsname{}
-       if err := syscall.Uname(&uname); err != nil {
+       uname, err := shared.Uname()
+       if err != nil {
                return ArchitectureDefault, err
        }
 
-       architectureName := ""
-       for _, c := range uname.Machine {
-               if c == 0 {
-                       break
-               }
-               architectureName += string(byte(c))
-       }
-
-       return architectureName, nil
+       return uname.Machine, nil
 }
diff --git a/shared/util_linux.go b/shared/util_linux.go
index 77daf1051..369898eb1 100644
--- a/shared/util_linux.go
+++ b/shared/util_linux.go
@@ -769,3 +769,51 @@ func GetErrno(err error) (errno error, iserrno bool) {
 
        return nil, false
 }
+
+// Utsname returns the same info as syscall.Utsname, as strings
+type Utsname struct {
+       Sysname    string
+       Nodename   string
+       Release    string
+       Version    string
+       Machine    string
+       Domainname string
+}
+
+// Uname returns Utsname as strings
+func Uname() (*Utsname, error) {
+       /*
+        * Based on: 
https://groups.google.com/forum/#!topic/golang-nuts/Jel8Bb-YwX8
+        * there is really no better way to do this, which is
+        * unfortunate. Also, we ditch the more accepted CharsToString
+        * version in that thread, since it doesn't seem as portable,
+        * viz. github issue #206.
+        */
+
+       uname := syscall.Utsname{}
+       err := syscall.Uname(&uname)
+       if err != nil {
+               return nil, err
+       }
+
+       return &Utsname{
+               Sysname:    intArrayToString(uname.Sysname),
+               Nodename:   intArrayToString(uname.Nodename),
+               Release:    intArrayToString(uname.Release),
+               Version:    intArrayToString(uname.Version),
+               Machine:    intArrayToString(uname.Machine),
+               Domainname: intArrayToString(uname.Domainname),
+       }, nil
+}
+
+func intArrayToString(arr [65]int8) string {
+       s := ""
+       for _, c := range arr {
+               if c == 0 {
+                       break
+               }
+               s += string(byte(c))
+       }
+
+       return s
+}

From 0002355d93d88880ad708cb7f0cc84a82f573fe8 Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.don...@canonical.com>
Date: Thu, 21 Sep 2017 10:48:22 +0200
Subject: [PATCH 2/6] shared/util: add helper to create tempfiles

Signed-off-by: Alberto Donato <alberto.don...@canonical.com>
---
 shared/testhelpers/tempfile.go | 19 +++++++++++++++++++
 shared/util.go                 | 12 ++++++++++++
 2 files changed, 31 insertions(+)
 create mode 100644 shared/testhelpers/tempfile.go

diff --git a/shared/testhelpers/tempfile.go b/shared/testhelpers/tempfile.go
new file mode 100644
index 000000000..b1abebe7e
--- /dev/null
+++ b/shared/testhelpers/tempfile.go
@@ -0,0 +1,19 @@
+package testhelpers
+
+import (
+       "os"
+
+       "github.com/stretchr/testify/suite"
+
+       "github.com/lxc/lxd/shared"
+)
+
+// WriteTempFile writes content to a temporary file.
+func WriteTempFile(s suite.Suite, dir string, prefix string, content string) 
(string, func()) {
+       filename, err := shared.WriteTempFile(dir, prefix, content)
+       if err != nil {
+               s.T().Fatalf("failed to create temporary file: %v", err)
+       }
+
+       return filename, func() { os.Remove(filename) }
+}
diff --git a/shared/util.go b/shared/util.go
index e49e8d058..260b32c8a 100644
--- a/shared/util.go
+++ b/shared/util.go
@@ -857,3 +857,15 @@ func Round(x float64) int64 {
 
        return int64(math.Floor(x + 0.5))
 }
+
+// WriteTempFile creates a temp file with the specified content
+func WriteTempFile(dir string, prefix string, content string) (string, error) {
+       f, err := ioutil.TempFile(dir, prefix)
+       if err != nil {
+               return "", err
+       }
+       defer f.Close()
+
+       _, err = f.WriteString(content)
+       return f.Name(), err
+}

From bb5ecf8fb53228ad93878e3e44e89aa95a2159f1 Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.don...@canonical.com>
Date: Wed, 20 Sep 2017 20:35:12 +0200
Subject: [PATCH 3/6] shared/osarch: add missing architecture aliases

Signed-off-by: Alberto Donato <alberto.don...@canonical.com>
---
 shared/osarch/architectures.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/shared/osarch/architectures.go b/shared/osarch/architectures.go
index 265d7cb02..e35b12772 100644
--- a/shared/osarch/architectures.go
+++ b/shared/osarch/architectures.go
@@ -28,12 +28,12 @@ var architectureNames = map[int]string{
 }
 
 var architectureAliases = map[int][]string{
-       ARCH_32BIT_INTEL_X86:             {"i386"},
+       ARCH_32BIT_INTEL_X86:             {"i386", "386"},
        ARCH_64BIT_INTEL_X86:             {"amd64"},
-       ARCH_32BIT_ARMV7_LITTLE_ENDIAN:   {"armel", "armhf"},
+       ARCH_32BIT_ARMV7_LITTLE_ENDIAN:   {"armel", "armhf", "arm"},
        ARCH_64BIT_ARMV8_LITTLE_ENDIAN:   {"arm64"},
        ARCH_32BIT_POWERPC_BIG_ENDIAN:    {"powerpc"},
-       ARCH_64BIT_POWERPC_BIG_ENDIAN:    {"powerpc64"},
+       ARCH_64BIT_POWERPC_BIG_ENDIAN:    {"powerpc64", "ppc64"},
        ARCH_64BIT_POWERPC_LITTLE_ENDIAN: {"ppc64el"},
 }
 

From dbdb5db247f112aa2863c7314d82d4b4f4b01bc6 Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.don...@canonical.com>
Date: Thu, 21 Sep 2017 09:45:25 +0200
Subject: [PATCH 4/6] shared/osarch: add function for parsing /etc/os-release

Signed-off-by: Alberto Donato <alberto.don...@canonical.com>
---
 shared/osarch/release.go      | 42 ++++++++++++++++++++
 shared/osarch/release_test.go | 90 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 132 insertions(+)
 create mode 100644 shared/osarch/release.go
 create mode 100644 shared/osarch/release_test.go

diff --git a/shared/osarch/release.go b/shared/osarch/release.go
new file mode 100644
index 000000000..22ba8d09b
--- /dev/null
+++ b/shared/osarch/release.go
@@ -0,0 +1,42 @@
+package osarch
+
+import (
+       "fmt"
+       "io/ioutil"
+       "os"
+       "strings"
+)
+
+// GetLSBRelease returns a map with Linux distribution information
+func GetLSBRelease() (map[string]string, error) {
+       osRelease, err := getLSBRelease("/etc/os-release")
+       if os.IsNotExist(err) {
+               return getLSBRelease("/usr/lib/os-release")
+       }
+       return osRelease, err
+}
+
+func getLSBRelease(filename string) (map[string]string, error) {
+       osRelease := make(map[string]string)
+
+       data, err := ioutil.ReadFile(filename)
+       if err != nil {
+               return osRelease, err
+       }
+       for i, line := range strings.Split(string(data), "\n") {
+               if len(line) == 0 {
+                       continue
+               }
+               if strings.HasPrefix(line, "#") {
+                       continue
+               }
+
+               tokens := strings.SplitN(line, "=", 2)
+               if len(tokens) != 2 {
+                       return osRelease, fmt.Errorf("%s: invalid format on 
line %d", filename, i+1)
+               }
+               osRelease[tokens[0]] = strings.Trim(tokens[1], `'"`)
+       }
+
+       return osRelease, nil
+}
diff --git a/shared/osarch/release_test.go b/shared/osarch/release_test.go
new file mode 100644
index 000000000..55b830849
--- /dev/null
+++ b/shared/osarch/release_test.go
@@ -0,0 +1,90 @@
+package osarch
+
+import (
+       "fmt"
+       "testing"
+
+       "github.com/stretchr/testify/suite"
+
+       "github.com/lxc/lxd/shared/testhelpers"
+)
+
+type releaseTestSuite struct {
+       suite.Suite
+}
+
+func TestReleaseTestSuite(t *testing.T) {
+       suite.Run(t, new(releaseTestSuite))
+}
+
+func (s *releaseTestSuite) TestGetLSBRelease() {
+       content := `NAME="Ubuntu"
+ID="ubuntu"
+VERSION_ID="16.04"
+`
+       filename, cleanup := testhelpers.WriteTempFile(s.Suite, "", 
"os-release", content)
+       defer cleanup()
+
+       lsbRelease, err := getLSBRelease(filename)
+       s.Nil(err)
+       s.Equal(
+               map[string]string{
+                       "NAME":       "Ubuntu",
+                       "ID":         "ubuntu",
+                       "VERSION_ID": "16.04",
+               }, lsbRelease)
+}
+
+func (s *releaseTestSuite) TestGetLSBReleaseSingleQuotes() {
+       content := `NAME='Ubuntu'`
+       filename, cleanup := testhelpers.WriteTempFile(s.Suite, "", 
"os-release", content)
+       defer cleanup()
+
+       lsbRelease, err := getLSBRelease(filename)
+       s.Nil(err)
+       s.Equal(map[string]string{"NAME": "Ubuntu"}, lsbRelease)
+}
+
+func (s *releaseTestSuite) TestGetLSBReleaseNoQuotes() {
+       content := `NAME=Ubuntu`
+       filename, cleanup := testhelpers.WriteTempFile(s.Suite, "", 
"os-release", content)
+       defer cleanup()
+
+       lsbRelease, err := getLSBRelease(filename)
+       s.Nil(err)
+       s.Equal(map[string]string{"NAME": "Ubuntu"}, lsbRelease)
+}
+
+func (s *releaseTestSuite) TestGetLSBReleaseSkipCommentsEmpty() {
+       content := `
+NAME="Ubuntu"
+
+ID="ubuntu"
+# skip this line
+VERSION_ID="16.04"
+`
+       filename, cleanup := testhelpers.WriteTempFile(s.Suite, "", 
"os-release", content)
+       defer cleanup()
+
+       lsbRelease, err := getLSBRelease(filename)
+       s.Nil(err)
+       s.Equal(
+               map[string]string{
+                       "NAME":       "Ubuntu",
+                       "ID":         "ubuntu",
+                       "VERSION_ID": "16.04",
+               }, lsbRelease)
+}
+
+func (s *releaseTestSuite) TestGetLSBReleaseInvalidLine() {
+       content := `
+NAME="Ubuntu"
+this is invalid
+ID="ubuntu"
+`
+       filename, cleanup := testhelpers.WriteTempFile(s.Suite, "", 
"os-release", content)
+       defer cleanup()
+
+       _, err := getLSBRelease(filename)
+       s.EqualError(err, fmt.Sprintf("%s: invalid format on line 3", filename))
+}

From 6f23fc799bef0e468a00b8d993adf51b80c83ddd Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.don...@canonical.com>
Date: Thu, 21 Sep 2017 09:50:40 +0200
Subject: [PATCH 5/6] shared/version: add helper to get platform-specific
 versions

Signed-off-by: Alberto Donato <alberto.don...@canonical.com>
---
 shared/version/platform_linux.go  | 32 ++++++++++++++++++++++++++++++++
 shared/version/platform_others.go |  7 +++++++
 2 files changed, 39 insertions(+)
 create mode 100644 shared/version/platform_linux.go
 create mode 100644 shared/version/platform_others.go

diff --git a/shared/version/platform_linux.go b/shared/version/platform_linux.go
new file mode 100644
index 000000000..252a80bc3
--- /dev/null
+++ b/shared/version/platform_linux.go
@@ -0,0 +1,32 @@
+// +build linux
+
+package version
+
+import (
+       "github.com/lxc/lxd/shared"
+       "github.com/lxc/lxd/shared/osarch"
+)
+
+func getPlatformVersionStrings() []string {
+       versions := []string{}
+
+       // add kernel version
+       uname, err := shared.Uname()
+       if err == nil {
+               versions = append(versions, uname.Release)
+       }
+
+       // add distribution info
+       lsbRelease, err := osarch.GetLSBRelease()
+       if err == nil {
+               distroName, ok := lsbRelease["NAME"]
+               if ok {
+                       versions = append(versions, distroName)
+               }
+               distroRelease, ok := lsbRelease["VERSION_ID"]
+               if ok {
+                       versions = append(versions, distroRelease)
+               }
+       }
+       return versions
+}
diff --git a/shared/version/platform_others.go 
b/shared/version/platform_others.go
new file mode 100644
index 000000000..d29148682
--- /dev/null
+++ b/shared/version/platform_others.go
@@ -0,0 +1,7 @@
+// +build !linux
+
+package version
+
+func getPlatformVersionStrings() []string {
+       return []string{}
+}

From da95c8ced76dab98f08c69d15a9cb04f17674ee6 Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.don...@canonical.com>
Date: Thu, 21 Sep 2017 09:56:12 +0200
Subject: [PATCH 6/6] shared/version: include OS, architecture and possibly
 kernel and distro info in User-Agent

Signed-off-by: Alberto Donato <alberto.don...@canonical.com>
---
 shared/version/flex.go | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/shared/version/flex.go b/shared/version/flex.go
index 5feeedbba..48a3537a4 100644
--- a/shared/version/flex.go
+++ b/shared/version/flex.go
@@ -1,10 +1,33 @@
 package version
 
+import (
+       "fmt"
+       "runtime"
+       "strings"
+
+       "github.com/lxc/lxd/shared/osarch"
+)
+
 // Version contains the LXD version number
 var Version = "2.18"
 
 // UserAgent contains a string suitable as a user-agent
-var UserAgent = "LXD " + Version
+var UserAgent = getUserAgent()
 
 // APIVersion contains the API base version. Only bumped for backward 
incompatible changes.
 var APIVersion = "1.0"
+
+func getUserAgent() string {
+       archID, err := osarch.ArchitectureId(runtime.GOARCH)
+       if err != nil {
+               panic(err)
+       }
+       arch, err := osarch.ArchitectureName(archID)
+       if err != nil {
+               panic(err)
+       }
+
+       tokens := []string{strings.Title(runtime.GOOS), arch}
+       tokens = append(tokens, getPlatformVersionStrings()...)
+       return fmt.Sprintf("LXD %s (%s)", Version, strings.Join(tokens, "; "))
+}
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to