Browse Source

Merge pull request #9201 from vieux/add_hostname_docker_info

Add hostname and ID docker info
Tibor Vass 10 years ago
parent
commit
998b591a71

+ 6 - 0
api/client/commands.go

@@ -508,6 +508,12 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
 	if remoteInfo.Exists("MemTotal") {
 	if remoteInfo.Exists("MemTotal") {
 		fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(remoteInfo.GetInt64("MemTotal"))))
 		fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(remoteInfo.GetInt64("MemTotal"))))
 	}
 	}
+	if remoteInfo.Exists("Name") {
+		fmt.Fprintf(cli.out, "Name: %s\n", remoteInfo.Get("Name"))
+	}
+	if remoteInfo.Exists("ID") {
+		fmt.Fprintf(cli.out, "ID: %s\n", remoteInfo.Get("ID"))
+	}
 
 
 	if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
 	if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
 		if remoteInfo.Exists("Debug") {
 		if remoteInfo.Exists("Debug") {

+ 25 - 0
api/common.go

@@ -3,12 +3,15 @@ package api
 import (
 import (
 	"fmt"
 	"fmt"
 	"mime"
 	"mime"
+	"os"
+	"path"
 	"strings"
 	"strings"
 
 
 	log "github.com/Sirupsen/logrus"
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/version"
 	"github.com/docker/docker/pkg/version"
+	"github.com/docker/docker/vendor/src/github.com/docker/libtrust"
 )
 )
 
 
 const (
 const (
@@ -47,3 +50,25 @@ func MatchesContentType(contentType, expectedType string) bool {
 	}
 	}
 	return err == nil && mimetype == expectedType
 	return err == nil && mimetype == expectedType
 }
 }
+
+// LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
+// otherwise generates a new one
+func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
+	err := os.MkdirAll(path.Dir(trustKeyPath), 0700)
+	if err != nil {
+		return nil, err
+	}
+	trustKey, err := libtrust.LoadKeyFile(trustKeyPath)
+	if err == libtrust.ErrKeyFileDoesNotExist {
+		trustKey, err = libtrust.GenerateECP256PrivateKey()
+		if err != nil {
+			return nil, fmt.Errorf("Error generating key: %s", err)
+		}
+		if err := libtrust.SaveKey(trustKeyPath, trustKey); err != nil {
+			return nil, fmt.Errorf("Error saving key file: %s", err)
+		}
+	} else if err != nil {
+		return nil, fmt.Errorf("Error loading key file: %s", err)
+	}
+	return trustKey, nil
+}

+ 1 - 0
daemon/config.go

@@ -40,6 +40,7 @@ type Config struct {
 	DisableNetwork              bool
 	DisableNetwork              bool
 	EnableSelinuxSupport        bool
 	EnableSelinuxSupport        bool
 	Context                     map[string][]string
 	Context                     map[string][]string
+	TrustKeyPath                string
 }
 }
 
 
 // InstallFlags adds command-line options to the top-level flag parser for
 // InstallFlags adds command-line options to the top-level flag parser for

+ 8 - 0
daemon/daemon.go

@@ -15,6 +15,7 @@ import (
 	"github.com/docker/libcontainer/label"
 	"github.com/docker/libcontainer/label"
 
 
 	log "github.com/Sirupsen/logrus"
 	log "github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver/execdrivers"
 	"github.com/docker/docker/daemon/execdriver/execdrivers"
 	"github.com/docker/docker/daemon/execdriver/lxc"
 	"github.com/docker/docker/daemon/execdriver/lxc"
@@ -83,6 +84,7 @@ func (c *contStore) List() []*Container {
 }
 }
 
 
 type Daemon struct {
 type Daemon struct {
+	ID             string
 	repository     string
 	repository     string
 	sysInitPath    string
 	sysInitPath    string
 	containers     *contStore
 	containers     *contStore
@@ -893,7 +895,13 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error)
 		return nil, err
 		return nil, err
 	}
 	}
 
 
+	trustKey, err := api.LoadOrCreateTrustKey(config.TrustKeyPath)
+	if err != nil {
+		return nil, err
+	}
+
 	daemon := &Daemon{
 	daemon := &Daemon{
+		ID:             trustKey.PublicKey().KeyID(),
 		repository:     daemonRepo,
 		repository:     daemonRepo,
 		containers:     &contStore{s: make(map[string]*Container)},
 		containers:     &contStore{s: make(map[string]*Container)},
 		execCommands:   newExecStore(),
 		execCommands:   newExecStore(),

+ 4 - 0
daemon/info.go

@@ -56,6 +56,7 @@ func (daemon *Daemon) CmdInfo(job *engine.Job) engine.Status {
 		return job.Error(err)
 		return job.Error(err)
 	}
 	}
 	v := &engine.Env{}
 	v := &engine.Env{}
+	v.Set("ID", daemon.ID)
 	v.SetInt("Containers", len(daemon.List()))
 	v.SetInt("Containers", len(daemon.List()))
 	v.SetInt("Images", imgcount)
 	v.SetInt("Images", imgcount)
 	v.Set("Driver", daemon.GraphDriver().String())
 	v.Set("Driver", daemon.GraphDriver().String())
@@ -75,6 +76,9 @@ func (daemon *Daemon) CmdInfo(job *engine.Job) engine.Status {
 	v.Set("InitPath", initPath)
 	v.Set("InitPath", initPath)
 	v.SetInt("NCPU", runtime.NumCPU())
 	v.SetInt("NCPU", runtime.NumCPU())
 	v.SetInt64("MemTotal", meminfo.MemTotal)
 	v.SetInt64("MemTotal", meminfo.MemTotal)
+	if hostname, err := os.Hostname(); err == nil {
+		v.Set("Name", hostname)
+	}
 	if _, err := v.WriteTo(job.Stdout); err != nil {
 	if _, err := v.WriteTo(job.Stdout); err != nil {
 		return job.Error(err)
 		return job.Error(err)
 	}
 	}

+ 2 - 0
docker/daemon.go

@@ -34,6 +34,8 @@ func mainDaemon() {
 	eng := engine.New()
 	eng := engine.New()
 	signal.Trap(eng.Shutdown)
 	signal.Trap(eng.Shutdown)
 
 
+	daemonCfg.TrustKeyPath = *flTrustKey
+
 	// Load builtins
 	// Load builtins
 	if err := builtins.Register(eng); err != nil {
 	if err := builtins.Register(eng); err != nil {
 		log.Fatal(err)
 		log.Fatal(err)

+ 2 - 2
docs/sources/reference/api/docker_remote_api.md

@@ -49,8 +49,8 @@ You can still call an old version of the API using
 `GET /info`
 `GET /info`
 
 
 **New!**
 **New!**
-`info` now returns the number of CPUs available on the machine (`NCPU`) and
-total memory available (`MemTotal`).
+`info` now returns the number of CPUs available on the machine (`NCPU`),
+total memory available (`MemTotal`), a user-friendly name describing the running Docker daemon (`Name`), and a unique ID identifying the daemon (`ID`).
 
 
 `POST /containers/create`
 `POST /containers/create`
 
 

+ 2 - 0
docs/sources/reference/api/docker_remote_api_v1.16.md

@@ -1220,6 +1220,8 @@ Display system-wide information
              "KernelVersion":"3.12.0-1-amd64"
              "KernelVersion":"3.12.0-1-amd64"
              "NCPU":1,
              "NCPU":1,
              "MemTotal":2099236864,
              "MemTotal":2099236864,
+             "Name":"prod-server-42",
+             "ID":"7TRN:IPZB:QYBB:VPBQ:UMPP:KARE:6ZNR:XE6T:7EWV:PKF4:ZOJD:TPYS",
              "Debug":false,
              "Debug":false,
              "NFd": 11,
              "NFd": 11,
              "NGoroutines":21,
              "NGoroutines":21,

+ 2 - 0
docs/sources/reference/commandline/cli.md

@@ -856,6 +856,8 @@ For example:
     Kernel Version: 3.13.0-24-generic
     Kernel Version: 3.13.0-24-generic
     Operating System: Ubuntu 14.04 LTS
     Operating System: Ubuntu 14.04 LTS
     CPUs: 1
     CPUs: 1
+    Name: prod-server-42
+    ID: 7TRN:IPZB:QYBB:VPBQ:UMPP:KARE:6ZNR:XE6T:7EWV:PKF4:ZOJD:TPYS
     Total Memory: 2 GiB
     Total Memory: 2 GiB
     Debug mode (server): false
     Debug mode (server): false
     Debug mode (client): true
     Debug mode (client): true

+ 2 - 0
integration/utils_test.go

@@ -9,6 +9,7 @@ import (
 	"net/http/httptest"
 	"net/http/httptest"
 	"os"
 	"os"
 	"path"
 	"path"
+	"path/filepath"
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 	"time"
 	"time"
@@ -187,6 +188,7 @@ func newTestEngine(t Fataler, autorestart bool, root string) *engine.Engine {
 		// Either InterContainerCommunication or EnableIptables must be set,
 		// Either InterContainerCommunication or EnableIptables must be set,
 		// otherwise NewDaemon will fail because of conflicting settings.
 		// otherwise NewDaemon will fail because of conflicting settings.
 		InterContainerCommunication: true,
 		InterContainerCommunication: true,
+		TrustKeyPath:                filepath.Join(root, "key.json"),
 	}
 	}
 	d, err := daemon.NewDaemon(cfg, eng)
 	d, err := daemon.NewDaemon(cfg, eng)
 	if err != nil {
 	if err != nil {

+ 1 - 1
project/vendor.sh

@@ -51,7 +51,7 @@ clone hg code.google.com/p/go.net 84a4013f96e0
 
 
 clone hg code.google.com/p/gosqlite 74691fb6f837
 clone hg code.google.com/p/gosqlite 74691fb6f837
 
 
-clone git github.com/docker/libtrust d273ef2565ca
+clone git github.com/docker/libtrust 230dfd18c232
 
 
 clone git github.com/Sirupsen/logrus v0.6.0
 clone git github.com/Sirupsen/logrus v0.6.0
 
 

+ 1 - 10
vendor/src/github.com/docker/libtrust/ec_key.go

@@ -55,16 +55,7 @@ func (k *ecPublicKey) CurveName() string {
 
 
 // KeyID returns a distinct identifier which is unique to this Public Key.
 // KeyID returns a distinct identifier which is unique to this Public Key.
 func (k *ecPublicKey) KeyID() string {
 func (k *ecPublicKey) KeyID() string {
-	// Generate and return a libtrust fingerprint of the EC public key.
-	// For an EC key this should be:
-	//   SHA256("EC"+curveName+bytes(X)+bytes(Y))
-	// Then truncated to 240 bits and encoded into 12 base32 groups like so:
-	//   ABCD:EFGH:IJKL:MNOP:QRST:UVWX:YZ23:4567:ABCD:EFGH:IJKL:MNOP
-	hasher := crypto.SHA256.New()
-	hasher.Write([]byte(k.KeyType() + k.CurveName()))
-	hasher.Write(k.X.Bytes())
-	hasher.Write(k.Y.Bytes())
-	return keyIDEncode(hasher.Sum(nil)[:30])
+	return keyIDFromCryptoKey(k)
 }
 }
 
 
 func (k *ecPublicKey) String() string {
 func (k *ecPublicKey) String() string {

+ 15 - 9
vendor/src/github.com/docker/libtrust/filter.go

@@ -11,9 +11,21 @@ func FilterByHosts(keys []PublicKey, host string, includeEmpty bool) ([]PublicKe
 	filtered := make([]PublicKey, 0, len(keys))
 	filtered := make([]PublicKey, 0, len(keys))
 
 
 	for _, pubKey := range keys {
 	for _, pubKey := range keys {
-		hosts, ok := pubKey.GetExtendedField("hosts").([]interface{})
+		var hosts []string
+		switch v := pubKey.GetExtendedField("hosts").(type) {
+		case []string:
+			hosts = v
+		case []interface{}:
+			for _, value := range v {
+				h, ok := value.(string)
+				if !ok {
+					continue
+				}
+				hosts = append(hosts, h)
+			}
+		}
 
 
-		if !ok || (ok && len(hosts) == 0) {
+		if len(hosts) == 0 {
 			if includeEmpty {
 			if includeEmpty {
 				filtered = append(filtered, pubKey)
 				filtered = append(filtered, pubKey)
 			}
 			}
@@ -21,12 +33,7 @@ func FilterByHosts(keys []PublicKey, host string, includeEmpty bool) ([]PublicKe
 		}
 		}
 
 
 		// Check if any hosts match pattern
 		// Check if any hosts match pattern
-		for _, hostVal := range hosts {
-			hostPattern, ok := hostVal.(string)
-			if !ok {
-				continue
-			}
-
+		for _, hostPattern := range hosts {
 			match, err := filepath.Match(hostPattern, host)
 			match, err := filepath.Match(hostPattern, host)
 			if err != nil {
 			if err != nil {
 				return nil, err
 				return nil, err
@@ -37,7 +44,6 @@ func FilterByHosts(keys []PublicKey, host string, includeEmpty bool) ([]PublicKe
 				continue
 				continue
 			}
 			}
 		}
 		}
-
 	}
 	}
 
 
 	return filtered, nil
 	return filtered, nil

+ 4 - 2
vendor/src/github.com/docker/libtrust/filter_test.go

@@ -27,6 +27,8 @@ func TestFilter(t *testing.T) {
 			t.Fatal(err)
 			t.Fatal(err)
 		}
 		}
 
 
+		// we use both []interface{} and []string here because jwt uses
+		// []interface{} format, while PEM uses []string
 		switch {
 		switch {
 		case i == 0:
 		case i == 0:
 			// Don't add entries for this key, key 0.
 			// Don't add entries for this key, key 0.
@@ -36,10 +38,10 @@ func TestFilter(t *testing.T) {
 			key.AddExtendedField("hosts", []interface{}{"*.even.example.com"})
 			key.AddExtendedField("hosts", []interface{}{"*.even.example.com"})
 		case i == 7:
 		case i == 7:
 			// Should catch only the last key, and make it match any hostname.
 			// Should catch only the last key, and make it match any hostname.
-			key.AddExtendedField("hosts", []interface{}{"*"})
+			key.AddExtendedField("hosts", []string{"*"})
 		default:
 		default:
 			// should catch keys 1, 3, 5.
 			// should catch keys 1, 3, 5.
-			key.AddExtendedField("hosts", []interface{}{"*.example.com"})
+			key.AddExtendedField("hosts", []string{"*.example.com"})
 		}
 		}
 
 
 		keys = append(keys, key)
 		keys = append(keys, key)

+ 2 - 2
vendor/src/github.com/docker/libtrust/key_files_test.go

@@ -138,7 +138,7 @@ func testTrustedHostKeysFile(t *testing.T, trustedHostKeysFilename string) {
 	}
 	}
 
 
 	for addr, hostKey := range trustedHostKeysMapping {
 	for addr, hostKey := range trustedHostKeysMapping {
-		t.Logf("Host Address: %s\n", addr)
+		t.Logf("Host Address: %d\n", addr)
 		t.Logf("Host Key: %s\n\n", hostKey)
 		t.Logf("Host Key: %s\n\n", hostKey)
 	}
 	}
 
 
@@ -160,7 +160,7 @@ func testTrustedHostKeysFile(t *testing.T, trustedHostKeysFilename string) {
 	}
 	}
 
 
 	for addr, hostKey := range trustedHostKeysMapping {
 	for addr, hostKey := range trustedHostKeysMapping {
-		t.Logf("Host Address: %s\n", addr)
+		t.Logf("Host Address: %d\n", addr)
 		t.Logf("Host Key: %s\n\n", hostKey)
 		t.Logf("Host Key: %s\n\n", hostKey)
 	}
 	}
 
 

+ 1 - 10
vendor/src/github.com/docker/libtrust/rsa_key.go

@@ -34,16 +34,7 @@ func (k *rsaPublicKey) KeyType() string {
 
 
 // KeyID returns a distinct identifier which is unique to this Public Key.
 // KeyID returns a distinct identifier which is unique to this Public Key.
 func (k *rsaPublicKey) KeyID() string {
 func (k *rsaPublicKey) KeyID() string {
-	// Generate and return a 'libtrust' fingerprint of the RSA public key.
-	// For an RSA key this should be:
-	//   SHA256("RSA"+bytes(N)+bytes(E))
-	// Then truncated to 240 bits and encoded into 12 base32 groups like so:
-	//   ABCD:EFGH:IJKL:MNOP:QRST:UVWX:YZ23:4567:ABCD:EFGH:IJKL:MNOP
-	hasher := crypto.SHA256.New()
-	hasher.Write([]byte(k.KeyType()))
-	hasher.Write(k.N.Bytes())
-	hasher.Write(serializeRSAPublicExponentParam(k.E))
-	return keyIDEncode(hasher.Sum(nil)[:30])
+	return keyIDFromCryptoKey(k)
 }
 }
 
 
 func (k *rsaPublicKey) String() string {
 func (k *rsaPublicKey) String() string {

+ 2 - 2
vendor/src/github.com/docker/libtrust/trustgraph/statement_test.go

@@ -201,7 +201,7 @@ func TestCollapseGrants(t *testing.T) {
 
 
 	collapsedGrants, expiration, err := CollapseStatements(statements, false)
 	collapsedGrants, expiration, err := CollapseStatements(statements, false)
 	if len(collapsedGrants) != 12 {
 	if len(collapsedGrants) != 12 {
-		t.Fatalf("Unexpected number of grants\n\tExpected: %d\n\tActual: %s", 12, len(collapsedGrants))
+		t.Fatalf("Unexpected number of grants\n\tExpected: %d\n\tActual: %d", 12, len(collapsedGrants))
 	}
 	}
 	if expiration.After(time.Now().Add(time.Hour*5)) || expiration.Before(time.Now()) {
 	if expiration.After(time.Now().Add(time.Hour*5)) || expiration.Before(time.Now()) {
 		t.Fatalf("Unexpected expiration time: %s", expiration.String())
 		t.Fatalf("Unexpected expiration time: %s", expiration.String())
@@ -261,7 +261,7 @@ func TestCollapseGrants(t *testing.T) {
 
 
 	collapsedGrants, expiration, err = CollapseStatements(statements, false)
 	collapsedGrants, expiration, err = CollapseStatements(statements, false)
 	if len(collapsedGrants) != 12 {
 	if len(collapsedGrants) != 12 {
-		t.Fatalf("Unexpected number of grants\n\tExpected: %d\n\tActual: %s", 12, len(collapsedGrants))
+		t.Fatalf("Unexpected number of grants\n\tExpected: %d\n\tActual: %d", 12, len(collapsedGrants))
 	}
 	}
 	if expiration.After(time.Now().Add(time.Hour*5)) || expiration.Before(time.Now()) {
 	if expiration.After(time.Now().Add(time.Hour*5)) || expiration.Before(time.Now()) {
 		t.Fatalf("Unexpected expiration time: %s", expiration.String())
 		t.Fatalf("Unexpected expiration time: %s", expiration.String())

+ 16 - 0
vendor/src/github.com/docker/libtrust/util.go

@@ -2,6 +2,7 @@ package libtrust
 
 
 import (
 import (
 	"bytes"
 	"bytes"
+	"crypto"
 	"crypto/elliptic"
 	"crypto/elliptic"
 	"crypto/x509"
 	"crypto/x509"
 	"encoding/base32"
 	"encoding/base32"
@@ -52,6 +53,21 @@ func keyIDEncode(b []byte) string {
 	return buf.String()
 	return buf.String()
 }
 }
 
 
+func keyIDFromCryptoKey(pubKey PublicKey) string {
+	// Generate and return a 'libtrust' fingerprint of the public key.
+	// For an RSA key this should be:
+	//   SHA256(DER encoded ASN1)
+	// Then truncated to 240 bits and encoded into 12 base32 groups like so:
+	//   ABCD:EFGH:IJKL:MNOP:QRST:UVWX:YZ23:4567:ABCD:EFGH:IJKL:MNOP
+	derBytes, err := x509.MarshalPKIXPublicKey(pubKey.CryptoPublicKey())
+	if err != nil {
+		return ""
+	}
+	hasher := crypto.SHA256.New()
+	hasher.Write(derBytes)
+	return keyIDEncode(hasher.Sum(nil)[:30])
+}
+
 func stringFromMap(m map[string]interface{}, key string) (string, error) {
 func stringFromMap(m map[string]interface{}, key string) (string, error) {
 	val, ok := m[key]
 	val, ok := m[key]
 	if !ok {
 	if !ok {

+ 23 - 0
vendor/src/github.com/docker/libtrust/util_test.go

@@ -0,0 +1,23 @@
+package libtrust
+
+import (
+	"encoding/pem"
+	"reflect"
+	"testing"
+)
+
+func TestAddPEMHeadersToKey(t *testing.T) {
+	pk := &rsaPublicKey{nil, map[string]interface{}{}}
+	blk := &pem.Block{Headers: map[string]string{"hosts": "localhost,127.0.0.1"}}
+	addPEMHeadersToKey(blk, pk)
+
+	val := pk.GetExtendedField("hosts")
+	hosts, ok := val.([]string)
+	if !ok {
+		t.Fatalf("hosts type(%v), expected []string", reflect.TypeOf(val))
+	}
+	expected := []string{"localhost", "127.0.0.1"}
+	if !reflect.DeepEqual(hosts, expected) {
+		t.Errorf("hosts(%v), expected %v", hosts, expected)
+	}
+}