Merge pull request #9201 from vieux/add_hostname_docker_info
Add hostname and ID docker info
This commit is contained in:
commit
998b591a71
19 changed files with 119 additions and 38 deletions
|
@ -508,6 +508,12 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
|||
if remoteInfo.Exists("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.Exists("Debug") {
|
||||
|
|
|
@ -3,12 +3,15 @@ package api
|
|||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/engine"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/version"
|
||||
"github.com/docker/docker/vendor/src/github.com/docker/libtrust"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -47,3 +50,25 @@ func MatchesContentType(contentType, expectedType string) bool {
|
|||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ type Config struct {
|
|||
DisableNetwork bool
|
||||
EnableSelinuxSupport bool
|
||||
Context map[string][]string
|
||||
TrustKeyPath string
|
||||
}
|
||||
|
||||
// InstallFlags adds command-line options to the top-level flag parser for
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/docker/libcontainer/label"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/daemon/execdriver/execdrivers"
|
||||
"github.com/docker/docker/daemon/execdriver/lxc"
|
||||
|
@ -83,6 +84,7 @@ func (c *contStore) List() []*Container {
|
|||
}
|
||||
|
||||
type Daemon struct {
|
||||
ID string
|
||||
repository string
|
||||
sysInitPath string
|
||||
containers *contStore
|
||||
|
@ -893,7 +895,13 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
trustKey, err := api.LoadOrCreateTrustKey(config.TrustKeyPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
daemon := &Daemon{
|
||||
ID: trustKey.PublicKey().KeyID(),
|
||||
repository: daemonRepo,
|
||||
containers: &contStore{s: make(map[string]*Container)},
|
||||
execCommands: newExecStore(),
|
||||
|
|
|
@ -56,6 +56,7 @@ func (daemon *Daemon) CmdInfo(job *engine.Job) engine.Status {
|
|||
return job.Error(err)
|
||||
}
|
||||
v := &engine.Env{}
|
||||
v.Set("ID", daemon.ID)
|
||||
v.SetInt("Containers", len(daemon.List()))
|
||||
v.SetInt("Images", imgcount)
|
||||
v.Set("Driver", daemon.GraphDriver().String())
|
||||
|
@ -75,6 +76,9 @@ func (daemon *Daemon) CmdInfo(job *engine.Job) engine.Status {
|
|||
v.Set("InitPath", initPath)
|
||||
v.SetInt("NCPU", runtime.NumCPU())
|
||||
v.SetInt64("MemTotal", meminfo.MemTotal)
|
||||
if hostname, err := os.Hostname(); err == nil {
|
||||
v.Set("Name", hostname)
|
||||
}
|
||||
if _, err := v.WriteTo(job.Stdout); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ func mainDaemon() {
|
|||
eng := engine.New()
|
||||
signal.Trap(eng.Shutdown)
|
||||
|
||||
daemonCfg.TrustKeyPath = *flTrustKey
|
||||
|
||||
// Load builtins
|
||||
if err := builtins.Register(eng); err != nil {
|
||||
log.Fatal(err)
|
||||
|
|
|
@ -49,8 +49,8 @@ You can still call an old version of the API using
|
|||
`GET /info`
|
||||
|
||||
**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`
|
||||
|
||||
|
|
|
@ -1220,6 +1220,8 @@ Display system-wide information
|
|||
"KernelVersion":"3.12.0-1-amd64"
|
||||
"NCPU":1,
|
||||
"MemTotal":2099236864,
|
||||
"Name":"prod-server-42",
|
||||
"ID":"7TRN:IPZB:QYBB:VPBQ:UMPP:KARE:6ZNR:XE6T:7EWV:PKF4:ZOJD:TPYS",
|
||||
"Debug":false,
|
||||
"NFd": 11,
|
||||
"NGoroutines":21,
|
||||
|
|
|
@ -856,6 +856,8 @@ For example:
|
|||
Kernel Version: 3.13.0-24-generic
|
||||
Operating System: Ubuntu 14.04 LTS
|
||||
CPUs: 1
|
||||
Name: prod-server-42
|
||||
ID: 7TRN:IPZB:QYBB:VPBQ:UMPP:KARE:6ZNR:XE6T:7EWV:PKF4:ZOJD:TPYS
|
||||
Total Memory: 2 GiB
|
||||
Debug mode (server): false
|
||||
Debug mode (client): true
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"net/http/httptest"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -187,6 +188,7 @@ func newTestEngine(t Fataler, autorestart bool, root string) *engine.Engine {
|
|||
// Either InterContainerCommunication or EnableIptables must be set,
|
||||
// otherwise NewDaemon will fail because of conflicting settings.
|
||||
InterContainerCommunication: true,
|
||||
TrustKeyPath: filepath.Join(root, "key.json"),
|
||||
}
|
||||
d, err := daemon.NewDaemon(cfg, eng)
|
||||
if err != nil {
|
||||
|
|
|
@ -51,7 +51,7 @@ clone hg code.google.com/p/go.net 84a4013f96e0
|
|||
|
||||
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
|
||||
|
||||
|
|
11
vendor/src/github.com/docker/libtrust/ec_key.go
vendored
11
vendor/src/github.com/docker/libtrust/ec_key.go
vendored
|
@ -55,16 +55,7 @@ func (k *ecPublicKey) CurveName() string {
|
|||
|
||||
// KeyID returns a distinct identifier which is unique to this Public Key.
|
||||
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 {
|
||||
|
|
24
vendor/src/github.com/docker/libtrust/filter.go
vendored
24
vendor/src/github.com/docker/libtrust/filter.go
vendored
|
@ -11,9 +11,21 @@ func FilterByHosts(keys []PublicKey, host string, includeEmpty bool) ([]PublicKe
|
|||
filtered := make([]PublicKey, 0, len(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 {
|
||||
filtered = append(filtered, pubKey)
|
||||
}
|
||||
|
@ -21,12 +33,7 @@ func FilterByHosts(keys []PublicKey, host string, includeEmpty bool) ([]PublicKe
|
|||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -37,7 +44,6 @@ func FilterByHosts(keys []PublicKey, host string, includeEmpty bool) ([]PublicKe
|
|||
continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return filtered, nil
|
||||
|
|
|
@ -27,6 +27,8 @@ func TestFilter(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// we use both []interface{} and []string here because jwt uses
|
||||
// []interface{} format, while PEM uses []string
|
||||
switch {
|
||||
case i == 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"})
|
||||
case i == 7:
|
||||
// Should catch only the last key, and make it match any hostname.
|
||||
key.AddExtendedField("hosts", []interface{}{"*"})
|
||||
key.AddExtendedField("hosts", []string{"*"})
|
||||
default:
|
||||
// should catch keys 1, 3, 5.
|
||||
key.AddExtendedField("hosts", []interface{}{"*.example.com"})
|
||||
key.AddExtendedField("hosts", []string{"*.example.com"})
|
||||
}
|
||||
|
||||
keys = append(keys, key)
|
||||
|
|
|
@ -138,7 +138,7 @@ func testTrustedHostKeysFile(t *testing.T, trustedHostKeysFilename string) {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ func testTrustedHostKeysFile(t *testing.T, trustedHostKeysFilename string) {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
11
vendor/src/github.com/docker/libtrust/rsa_key.go
vendored
11
vendor/src/github.com/docker/libtrust/rsa_key.go
vendored
|
@ -34,16 +34,7 @@ func (k *rsaPublicKey) KeyType() string {
|
|||
|
||||
// KeyID returns a distinct identifier which is unique to this Public Key.
|
||||
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 {
|
||||
|
|
|
@ -201,7 +201,7 @@ func TestCollapseGrants(t *testing.T) {
|
|||
|
||||
collapsedGrants, expiration, err := CollapseStatements(statements, false)
|
||||
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()) {
|
||||
t.Fatalf("Unexpected expiration time: %s", expiration.String())
|
||||
|
@ -261,7 +261,7 @@ func TestCollapseGrants(t *testing.T) {
|
|||
|
||||
collapsedGrants, expiration, err = CollapseStatements(statements, false)
|
||||
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()) {
|
||||
t.Fatalf("Unexpected expiration time: %s", expiration.String())
|
||||
|
|
16
vendor/src/github.com/docker/libtrust/util.go
vendored
16
vendor/src/github.com/docker/libtrust/util.go
vendored
|
@ -2,6 +2,7 @@ package libtrust
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/elliptic"
|
||||
"crypto/x509"
|
||||
"encoding/base32"
|
||||
|
@ -52,6 +53,21 @@ func keyIDEncode(b []byte) 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) {
|
||||
val, ok := m[key]
|
||||
if !ok {
|
||||
|
|
23
vendor/src/github.com/docker/libtrust/util_test.go
vendored
Normal file
23
vendor/src/github.com/docker/libtrust/util_test.go
vendored
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue