Browse code

Add OS to docker info

Docker-DCO-1.1-Signed-off-by: Tibor Vass <teabee89@gmail.com> (github: tiborvass)

Tibor Vass authored on 2014/07/25 00:42:38
Showing 6 changed files
... ...
@@ -493,6 +493,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
493 493
 	}
494 494
 	fmt.Fprintf(cli.out, "Execution Driver: %s\n", remoteInfo.Get("ExecutionDriver"))
495 495
 	fmt.Fprintf(cli.out, "Kernel Version: %s\n", remoteInfo.Get("KernelVersion"))
496
+	fmt.Fprintf(cli.out, "Operating System: %s\n", remoteInfo.Get("OperatingSystem"))
496 497
 
497 498
 	if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
498 499
 		fmt.Fprintf(cli.out, "Debug mode (server): %v\n", remoteInfo.GetBool("Debug"))
... ...
@@ -29,18 +29,14 @@ There are no available options.
29 29
 Here is a sample output:
30 30
 
31 31
     # docker info
32
-    Containers: 18
33
-    Images: 95
34
-    Storage Driver: devicemapper
35
-     Pool Name: docker-8:1-170408448-pool
36
-     Data file: /var/lib/docker/devicemapper/devicemapper/data
37
-     Metadata file: /var/lib/docker/devicemapper/devicemapper/metadata
38
-     Data Space Used: 9946.3 Mb
39
-     Data Space Total: 102400.0 Mb
40
-     Metadata Space Used: 9.9 Mb
41
-     Metadata Space Total: 2048.0 Mb
42
-    Execution Driver: native-0.1
43
-    Kernel Version: 3.10.0-116.el7.x86_64
32
+    Containers: 14
33
+    Images: 52
34
+    Storage Driver: aufs
35
+     Root Dir: /var/lib/docker/aufs
36
+     Dirs: 80
37
+    Execution Driver: native-0.2
38
+    Kernel Version: 3.13.0-24-generic
39
+    Operating System: Ubuntu 14.04 LTS
44 40
 
45 41
 # HISTORY
46 42
 April 2014, Originally compiled by William Henry (whenry at redhat dot com)
... ...
@@ -605,18 +605,19 @@ tar, then the ownerships might not get preserved.
605 605
 For example:
606 606
 
607 607
     $ sudo docker -D info
608
-    Containers: 16
609
-    Images: 2138
608
+    Containers: 14
609
+    Images: 52
610 610
     Storage Driver: btrfs
611
-    Execution Driver: native-0.1
612
-    Kernel Version: 3.12.0-1-amd64
611
+    Execution Driver: native-0.2
612
+    Kernel Version: 3.13.0-24-generic
613
+    Operating System: Ubuntu 14.04 LTS
613 614
     Debug mode (server): false
614 615
     Debug mode (client): true
615
-    Fds: 16
616
-    Goroutines: 104
616
+    Fds: 10
617
+    Goroutines: 9
617 618
     EventsListeners: 0
618 619
     Init Path: /usr/bin/docker
619
-    Sockets: [unix:///var/run/docker.sock tcp://0.0.0.0:4243]
620
+    Sockets: [unix:///var/run/docker.sock]
620 621
     Username: svendowideit
621 622
     Registry: [https://index.docker.io/v1/]
622 623
 
623 624
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+package operatingsystem
1
+
2
+import (
3
+	"bytes"
4
+	"errors"
5
+	"io/ioutil"
6
+)
7
+
8
+var (
9
+	// file to use to detect if the daemon is running in a container
10
+	proc1Cgroup = "/proc/1/cgroup"
11
+
12
+	// file to check to determine Operating System
13
+	etcOsRelease = "/etc/os-release"
14
+)
15
+
16
+func GetOperatingSystem() (string, error) {
17
+	b, err := ioutil.ReadFile(etcOsRelease)
18
+	if err != nil {
19
+		return "", err
20
+	}
21
+	if i := bytes.Index(b, []byte("PRETTY_NAME")); i >= 0 {
22
+		b = b[i+13:]
23
+		return string(b[:bytes.IndexByte(b, '"')]), nil
24
+	}
25
+	return "", errors.New("PRETTY_NAME not found")
26
+}
27
+
28
+func IsContainerized() (bool, error) {
29
+	b, err := ioutil.ReadFile(proc1Cgroup)
30
+	if err != nil {
31
+		return false, err
32
+	}
33
+	for _, line := range bytes.Split(b, []byte{'\n'}) {
34
+		if len(line) > 0 && !bytes.HasSuffix(line, []byte{'/'}) {
35
+			return true, nil
36
+		}
37
+	}
38
+	return false, nil
39
+}
0 40
new file mode 100644
... ...
@@ -0,0 +1,123 @@
0
+package operatingsystem
1
+
2
+import (
3
+	"io/ioutil"
4
+	"os"
5
+	"path/filepath"
6
+	"testing"
7
+)
8
+
9
+func TestGetOperatingSystem(t *testing.T) {
10
+	var (
11
+		backup       = etcOsRelease
12
+		ubuntuTrusty = []byte(`NAME="Ubuntu"
13
+VERSION="14.04, Trusty Tahr"
14
+ID=ubuntu
15
+ID_LIKE=debian
16
+PRETTY_NAME="Ubuntu 14.04 LTS"
17
+VERSION_ID="14.04"
18
+HOME_URL="http://www.ubuntu.com/"
19
+SUPPORT_URL="http://help.ubuntu.com/"
20
+BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`)
21
+		gentoo = []byte(`NAME=Gentoo
22
+ID=gentoo
23
+PRETTY_NAME="Gentoo/Linux"
24
+ANSI_COLOR="1;32"
25
+HOME_URL="http://www.gentoo.org/"
26
+SUPPORT_URL="http://www.gentoo.org/main/en/support.xml"
27
+BUG_REPORT_URL="https://bugs.gentoo.org/"
28
+`)
29
+		noPrettyName = []byte(`NAME="Ubuntu"
30
+VERSION="14.04, Trusty Tahr"
31
+ID=ubuntu
32
+ID_LIKE=debian
33
+VERSION_ID="14.04"
34
+HOME_URL="http://www.ubuntu.com/"
35
+SUPPORT_URL="http://help.ubuntu.com/"
36
+BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`)
37
+	)
38
+
39
+	dir := os.TempDir()
40
+	defer func() {
41
+		etcOsRelease = backup
42
+		os.RemoveAll(dir)
43
+	}()
44
+
45
+	etcOsRelease = filepath.Join(dir, "etcOsRelease")
46
+	for expect, osRelease := range map[string][]byte{
47
+		"Ubuntu 14.04 LTS": ubuntuTrusty,
48
+		"Gentoo/Linux":     gentoo,
49
+		"":                 noPrettyName,
50
+	} {
51
+		if err := ioutil.WriteFile(etcOsRelease, osRelease, 0600); err != nil {
52
+			t.Fatalf("failed to write to %s: %v", etcOsRelease, err)
53
+		}
54
+		s, err := GetOperatingSystem()
55
+		if s != expect {
56
+			if expect == "" {
57
+				t.Fatalf("Expected error 'PRETTY_NAME not found', but got %v", err)
58
+			} else {
59
+				t.Fatalf("Expected '%s', but got '%s'. Err=%v", expect, s, err)
60
+			}
61
+		}
62
+	}
63
+}
64
+
65
+func TestIsContainerized(t *testing.T) {
66
+	var (
67
+		backup                      = proc1Cgroup
68
+		nonContainerizedProc1Cgroup = []byte(`14:name=systemd:/
69
+13:hugetlb:/
70
+12:net_prio:/
71
+11:perf_event:/
72
+10:bfqio:/
73
+9:blkio:/
74
+8:net_cls:/
75
+7:freezer:/
76
+6:devices:/
77
+5:memory:/
78
+4:cpuacct:/
79
+3:cpu:/
80
+2:cpuset:/
81
+`)
82
+		containerizedProc1Cgroup = []byte(`9:perf_event:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
83
+8:blkio:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
84
+7:net_cls:/
85
+6:freezer:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
86
+5:devices:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
87
+4:memory:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
88
+3:cpuacct:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
89
+2:cpu:/docker/3cef1b53c50b0fa357d994f8a1a8cd783c76bbf4f5dd08b226e38a8bd331338d
90
+1:cpuset:/`)
91
+	)
92
+
93
+	dir := os.TempDir()
94
+	defer func() {
95
+		proc1Cgroup = backup
96
+		os.RemoveAll(dir)
97
+	}()
98
+
99
+	proc1Cgroup = filepath.Join(dir, "proc1Cgroup")
100
+
101
+	if err := ioutil.WriteFile(proc1Cgroup, nonContainerizedProc1Cgroup, 0600); err != nil {
102
+		t.Fatalf("failed to write to %s: %v", proc1Cgroup, err)
103
+	}
104
+	inContainer, err := IsContainerized()
105
+	if err != nil {
106
+		t.Fatal(err)
107
+	}
108
+	if inContainer {
109
+		t.Fatal("Wrongly assuming containerized")
110
+	}
111
+
112
+	if err := ioutil.WriteFile(proc1Cgroup, containerizedProc1Cgroup, 0600); err != nil {
113
+		t.Fatalf("failed to write to %s: %v", proc1Cgroup, err)
114
+	}
115
+	inContainer, err = IsContainerized()
116
+	if err != nil {
117
+		t.Fatal(err)
118
+	}
119
+	if !inContainer {
120
+		t.Fatal("Wrongly assuming non-containerized")
121
+	}
122
+}
... ...
@@ -57,6 +57,7 @@ import (
57 57
 	"github.com/docker/docker/pkg/parsers"
58 58
 	"github.com/docker/docker/pkg/parsers/filters"
59 59
 	"github.com/docker/docker/pkg/parsers/kernel"
60
+	"github.com/docker/docker/pkg/parsers/operatingsystem"
60 61
 	"github.com/docker/docker/pkg/signal"
61 62
 	"github.com/docker/docker/pkg/tailfile"
62 63
 	"github.com/docker/docker/registry"
... ...
@@ -795,6 +796,17 @@ func (srv *Server) DockerInfo(job *engine.Job) engine.Status {
795 795
 		kernelVersion = kv.String()
796 796
 	}
797 797
 
798
+	operatingSystem := "<unknown>"
799
+	if s, err := operatingsystem.GetOperatingSystem(); err == nil {
800
+		operatingSystem = s
801
+	}
802
+	if inContainer, err := operatingsystem.IsContainerized(); err != nil {
803
+		utils.Errorf("Could not determine if daemon is containerized: %v", err)
804
+		operatingSystem += " (error determining if containerized)"
805
+	} else if inContainer {
806
+		operatingSystem += " (containerized)"
807
+	}
808
+
798 809
 	// if we still have the original dockerinit binary from before we copied it locally, let's return the path to that, since that's more intuitive (the copied path is trivial to derive by hand given VERSION)
799 810
 	initPath := utils.DockerInitPath("")
800 811
 	if initPath == "" {
... ...
@@ -816,6 +828,7 @@ func (srv *Server) DockerInfo(job *engine.Job) engine.Status {
816 816
 	v.Set("ExecutionDriver", srv.daemon.ExecutionDriver().Name())
817 817
 	v.SetInt("NEventsListener", srv.eventPublisher.SubscribersCount())
818 818
 	v.Set("KernelVersion", kernelVersion)
819
+	v.Set("OperatingSystem", operatingSystem)
819 820
 	v.Set("IndexServerAddress", registry.IndexServerAddress())
820 821
 	v.Set("InitSha1", dockerversion.INITSHA1)
821 822
 	v.Set("InitPath", initPath)