2017-08-24 18:42:11 -04:00
|
|
|
package system
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base64"
|
|
|
|
"net"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2018-12-19 09:49:20 -05:00
|
|
|
pluginmanager "github.com/docker/cli/cli-plugins/manager"
|
2017-08-24 18:42:11 -04:00
|
|
|
"github.com/docker/cli/internal/test"
|
2022-03-04 08:38:45 -05:00
|
|
|
registrytypes "github.com/docker/docker/api/types/registry"
|
2017-08-24 18:42:11 -04:00
|
|
|
"github.com/docker/docker/api/types/swarm"
|
2023-07-14 17:42:40 -04:00
|
|
|
"github.com/docker/docker/api/types/system"
|
2020-02-22 12:12:14 -05:00
|
|
|
"gotest.tools/v3/assert"
|
|
|
|
is "gotest.tools/v3/assert/cmp"
|
|
|
|
"gotest.tools/v3/golden"
|
2017-08-24 18:42:11 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// helper function that base64 decodes a string and ignores the error
|
|
|
|
func base64Decode(val string) []byte {
|
|
|
|
decoded, _ := base64.StdEncoding.DecodeString(val)
|
|
|
|
return decoded
|
|
|
|
}
|
|
|
|
|
2019-01-23 09:26:12 -05:00
|
|
|
const sampleID = "EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX"
|
|
|
|
|
2023-07-14 17:42:40 -04:00
|
|
|
var sampleInfoNoSwarm = system.Info{
|
2019-01-23 09:26:12 -05:00
|
|
|
ID: sampleID,
|
2017-08-24 18:42:11 -04:00
|
|
|
Containers: 0,
|
|
|
|
ContainersRunning: 0,
|
|
|
|
ContainersPaused: 0,
|
|
|
|
ContainersStopped: 0,
|
|
|
|
Images: 0,
|
2023-05-18 18:53:34 -04:00
|
|
|
Driver: "overlay2",
|
2017-08-24 18:42:11 -04:00
|
|
|
DriverStatus: [][2]string{
|
|
|
|
{"Backing Filesystem", "extfs"},
|
2023-05-18 18:53:34 -04:00
|
|
|
{"Supports d_type", "true"},
|
|
|
|
{"Using metacopy", "false"},
|
|
|
|
{"Native Overlay Diff", "true"},
|
2017-08-24 18:42:11 -04:00
|
|
|
},
|
|
|
|
SystemStatus: nil,
|
2023-07-14 17:42:40 -04:00
|
|
|
Plugins: system.PluginsInfo{
|
2017-08-24 18:42:11 -04:00
|
|
|
Volume: []string{"local"},
|
|
|
|
Network: []string{"bridge", "host", "macvlan", "null", "overlay"},
|
|
|
|
Authorization: nil,
|
|
|
|
Log: []string{"awslogs", "fluentd", "gcplogs", "gelf", "journald", "json-file", "logentries", "splunk", "syslog"},
|
|
|
|
},
|
|
|
|
MemoryLimit: true,
|
|
|
|
SwapLimit: true,
|
|
|
|
KernelMemory: true,
|
|
|
|
CPUCfsPeriod: true,
|
|
|
|
CPUCfsQuota: true,
|
|
|
|
CPUShares: true,
|
|
|
|
CPUSet: true,
|
|
|
|
IPv4Forwarding: true,
|
|
|
|
BridgeNfIptables: true,
|
|
|
|
BridgeNfIP6tables: true,
|
|
|
|
Debug: true,
|
|
|
|
NFd: 33,
|
|
|
|
OomKillDisable: true,
|
|
|
|
NGoroutines: 135,
|
|
|
|
SystemTime: "2017-08-24T17:44:34.077811894Z",
|
|
|
|
LoggingDriver: "json-file",
|
|
|
|
CgroupDriver: "cgroupfs",
|
|
|
|
NEventsListener: 0,
|
|
|
|
KernelVersion: "4.4.0-87-generic",
|
|
|
|
OperatingSystem: "Ubuntu 16.04.3 LTS",
|
2019-07-30 13:10:03 -04:00
|
|
|
OSVersion: "",
|
2017-08-24 18:42:11 -04:00
|
|
|
OSType: "linux",
|
|
|
|
Architecture: "x86_64",
|
|
|
|
IndexServerAddress: "https://index.docker.io/v1/",
|
2022-03-04 08:38:45 -05:00
|
|
|
RegistryConfig: ®istrytypes.ServiceConfig{
|
2017-08-24 18:42:11 -04:00
|
|
|
AllowNondistributableArtifactsCIDRs: nil,
|
|
|
|
AllowNondistributableArtifactsHostnames: nil,
|
2022-03-04 08:38:45 -05:00
|
|
|
InsecureRegistryCIDRs: []*registrytypes.NetIPNet{
|
2017-08-24 18:42:11 -04:00
|
|
|
{
|
|
|
|
IP: net.ParseIP("127.0.0.0"),
|
|
|
|
Mask: net.IPv4Mask(255, 0, 0, 0),
|
|
|
|
},
|
|
|
|
},
|
2022-03-04 08:38:45 -05:00
|
|
|
IndexConfigs: map[string]*registrytypes.IndexInfo{
|
2017-08-24 18:42:11 -04:00
|
|
|
"docker.io": {
|
|
|
|
Name: "docker.io",
|
|
|
|
Mirrors: nil,
|
|
|
|
Secure: true,
|
|
|
|
Official: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Mirrors: nil,
|
|
|
|
},
|
|
|
|
NCPU: 2,
|
|
|
|
MemTotal: 2097356800,
|
|
|
|
DockerRootDir: "/var/lib/docker",
|
|
|
|
HTTPProxy: "",
|
|
|
|
HTTPSProxy: "",
|
|
|
|
NoProxy: "",
|
|
|
|
Name: "system-sample",
|
|
|
|
Labels: []string{"provider=digitalocean"},
|
|
|
|
ExperimentalBuild: false,
|
|
|
|
ServerVersion: "17.06.1-ce",
|
2023-07-14 17:42:40 -04:00
|
|
|
Runtimes: map[string]system.Runtime{
|
2017-08-24 18:42:11 -04:00
|
|
|
"runc": {
|
|
|
|
Path: "docker-runc",
|
|
|
|
Args: nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DefaultRuntime: "runc",
|
|
|
|
Swarm: swarm.Info{LocalNodeState: "inactive"},
|
|
|
|
LiveRestoreEnabled: false,
|
|
|
|
Isolation: "",
|
|
|
|
InitBinary: "docker-init",
|
2023-07-14 17:42:40 -04:00
|
|
|
ContainerdCommit: system.Commit{
|
2017-08-24 18:42:11 -04:00
|
|
|
ID: "6e23458c129b551d5c9871e5174f6b1b7f6d1170",
|
|
|
|
Expected: "6e23458c129b551d5c9871e5174f6b1b7f6d1170",
|
|
|
|
},
|
2023-07-14 17:42:40 -04:00
|
|
|
RuncCommit: system.Commit{
|
2017-08-24 18:42:11 -04:00
|
|
|
ID: "810190ceaa507aa2727d7ae6f4790c76ec150bd2",
|
|
|
|
Expected: "810190ceaa507aa2727d7ae6f4790c76ec150bd2",
|
|
|
|
},
|
2023-07-14 17:42:40 -04:00
|
|
|
InitCommit: system.Commit{
|
2017-08-24 18:42:11 -04:00
|
|
|
ID: "949e6fa",
|
|
|
|
Expected: "949e6fa",
|
|
|
|
},
|
|
|
|
SecurityOptions: []string{"name=apparmor", "name=seccomp,profile=default"},
|
2023-07-14 17:42:40 -04:00
|
|
|
DefaultAddressPools: []system.NetworkAddressPool{
|
2020-03-18 11:58:23 -04:00
|
|
|
{
|
|
|
|
Base: "10.123.0.0/16",
|
|
|
|
Size: 24,
|
|
|
|
},
|
|
|
|
},
|
2017-08-24 18:42:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
var sampleSwarmInfo = swarm.Info{
|
|
|
|
NodeID: "qo2dfdig9mmxqkawulggepdih",
|
|
|
|
NodeAddr: "165.227.107.89",
|
|
|
|
LocalNodeState: "active",
|
|
|
|
ControlAvailable: true,
|
|
|
|
Error: "",
|
|
|
|
RemoteManagers: []swarm.Peer{
|
|
|
|
{
|
|
|
|
NodeID: "qo2dfdig9mmxqkawulggepdih",
|
|
|
|
Addr: "165.227.107.89:2377",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Nodes: 1,
|
|
|
|
Managers: 1,
|
|
|
|
Cluster: &swarm.ClusterInfo{
|
|
|
|
ID: "9vs5ygs0gguyyec4iqf2314c0",
|
|
|
|
Meta: swarm.Meta{
|
|
|
|
Version: swarm.Version{Index: 11},
|
|
|
|
CreatedAt: time.Date(2017, 8, 24, 17, 34, 19, 278062352, time.UTC),
|
|
|
|
UpdatedAt: time.Date(2017, 8, 24, 17, 34, 42, 398815481, time.UTC),
|
|
|
|
},
|
|
|
|
Spec: swarm.Spec{
|
|
|
|
Annotations: swarm.Annotations{
|
|
|
|
Name: "default",
|
|
|
|
Labels: nil,
|
|
|
|
},
|
|
|
|
Orchestration: swarm.OrchestrationConfig{
|
|
|
|
TaskHistoryRetentionLimit: &[]int64{5}[0],
|
|
|
|
},
|
|
|
|
Raft: swarm.RaftConfig{
|
|
|
|
SnapshotInterval: 10000,
|
|
|
|
KeepOldSnapshots: &[]uint64{0}[0],
|
|
|
|
LogEntriesForSlowFollowers: 500,
|
|
|
|
ElectionTick: 3,
|
|
|
|
HeartbeatTick: 1,
|
|
|
|
},
|
|
|
|
Dispatcher: swarm.DispatcherConfig{
|
|
|
|
HeartbeatPeriod: 5000000000,
|
|
|
|
},
|
|
|
|
CAConfig: swarm.CAConfig{
|
|
|
|
NodeCertExpiry: 7776000000000000,
|
|
|
|
},
|
|
|
|
TaskDefaults: swarm.TaskDefaults{},
|
|
|
|
EncryptionConfig: swarm.EncryptionConfig{
|
|
|
|
AutoLockManagers: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
TLSInfo: swarm.TLSInfo{
|
|
|
|
TrustRoot: `
|
|
|
|
-----BEGIN CERTIFICATE-----
|
|
|
|
MIIBajCCARCgAwIBAgIUaFCW5xsq8eyiJ+Pmcv3MCflMLnMwCgYIKoZIzj0EAwIw
|
|
|
|
EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTcwODI0MTcyOTAwWhcNMzcwODE5MTcy
|
|
|
|
OTAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH
|
|
|
|
A0IABDy7NebyUJyUjWJDBUdnZoV6GBxEGKO4TZPNDwnxDxJcUdLVaB7WGa4/DLrW
|
|
|
|
UfsVgh1JGik2VTiLuTMA1tLlNPOjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
|
|
|
|
Af8EBTADAQH/MB0GA1UdDgQWBBQl16XFtaaXiUAwEuJptJlDjfKskDAKBggqhkjO
|
|
|
|
PQQDAgNIADBFAiEAo9fTQNM5DP9bHVcTJYfl2Cay1bFu1E+lnpmN+EYJfeACIGKH
|
|
|
|
1pCUkZ+D0IB6CiEZGWSHyLuXPM1rlP+I5KuS7sB8
|
|
|
|
-----END CERTIFICATE-----
|
|
|
|
`,
|
|
|
|
CertIssuerSubject: base64Decode("MBMxETAPBgNVBAMTCHN3YXJtLWNh"),
|
|
|
|
CertIssuerPublicKey: base64Decode(
|
|
|
|
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPLs15vJQnJSNYkMFR2dmhXoYHEQYo7hNk80PCfEPElxR0tVoHtYZrj8MutZR+xWCHUkaKTZVOIu5MwDW0uU08w=="),
|
|
|
|
},
|
|
|
|
RootRotationInProgress: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2018-12-19 09:49:20 -05:00
|
|
|
var samplePluginsInfo = []pluginmanager.Plugin{
|
|
|
|
{
|
|
|
|
Name: "goodplugin",
|
|
|
|
Path: "/path/to/docker-goodplugin",
|
|
|
|
Metadata: pluginmanager.Metadata{
|
|
|
|
SchemaVersion: "0.1.0",
|
|
|
|
ShortDescription: "unit test is good",
|
|
|
|
Vendor: "ACME Corp",
|
|
|
|
Version: "0.1.0",
|
|
|
|
},
|
|
|
|
},
|
2019-02-25 07:07:05 -05:00
|
|
|
{
|
|
|
|
Name: "unversionedplugin",
|
|
|
|
Path: "/path/to/docker-unversionedplugin",
|
|
|
|
Metadata: pluginmanager.Metadata{
|
|
|
|
SchemaVersion: "0.1.0",
|
|
|
|
ShortDescription: "this plugin has no version",
|
|
|
|
Vendor: "ACME Corp",
|
|
|
|
},
|
|
|
|
},
|
2018-12-19 09:49:20 -05:00
|
|
|
{
|
|
|
|
Name: "badplugin",
|
|
|
|
Path: "/path/to/docker-badplugin",
|
|
|
|
Err: pluginmanager.NewPluginError("something wrong"),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2017-08-24 18:42:11 -04:00
|
|
|
func TestPrettyPrintInfo(t *testing.T) {
|
|
|
|
infoWithSwarm := sampleInfoNoSwarm
|
|
|
|
infoWithSwarm.Swarm = sampleSwarmInfo
|
|
|
|
|
|
|
|
infoWithWarningsLinux := sampleInfoNoSwarm
|
|
|
|
infoWithWarningsLinux.MemoryLimit = false
|
|
|
|
infoWithWarningsLinux.SwapLimit = false
|
|
|
|
infoWithWarningsLinux.KernelMemory = false
|
|
|
|
infoWithWarningsLinux.OomKillDisable = false
|
|
|
|
infoWithWarningsLinux.CPUCfsQuota = false
|
|
|
|
infoWithWarningsLinux.CPUCfsPeriod = false
|
|
|
|
infoWithWarningsLinux.CPUShares = false
|
|
|
|
infoWithWarningsLinux.CPUSet = false
|
|
|
|
infoWithWarningsLinux.IPv4Forwarding = false
|
|
|
|
infoWithWarningsLinux.BridgeNfIptables = false
|
|
|
|
infoWithWarningsLinux.BridgeNfIP6tables = false
|
|
|
|
|
2018-07-19 13:45:04 -04:00
|
|
|
sampleInfoDaemonWarnings := sampleInfoNoSwarm
|
|
|
|
sampleInfoDaemonWarnings.Warnings = []string{
|
|
|
|
"WARNING: No memory limit support",
|
|
|
|
"WARNING: No swap limit support",
|
|
|
|
"WARNING: No oom kill disable support",
|
|
|
|
"WARNING: No cpu cfs quota support",
|
|
|
|
"WARNING: No cpu cfs period support",
|
|
|
|
"WARNING: No cpu shares support",
|
|
|
|
"WARNING: No cpuset support",
|
|
|
|
"WARNING: IPv4 forwarding is disabled",
|
|
|
|
"WARNING: bridge-nf-call-iptables is disabled",
|
|
|
|
"WARNING: bridge-nf-call-ip6tables is disabled",
|
|
|
|
}
|
|
|
|
|
2019-01-24 09:22:55 -05:00
|
|
|
sampleInfoBadSecurity := sampleInfoNoSwarm
|
|
|
|
sampleInfoBadSecurity.SecurityOptions = []string{"foo="}
|
|
|
|
|
2022-06-05 08:44:08 -04:00
|
|
|
sampleInfoLabelsNil := sampleInfoNoSwarm
|
|
|
|
sampleInfoLabelsNil.Labels = nil
|
|
|
|
sampleInfoLabelsEmpty := sampleInfoNoSwarm
|
|
|
|
sampleInfoLabelsEmpty.Labels = []string{}
|
|
|
|
|
2017-08-24 18:42:11 -04:00
|
|
|
for _, tc := range []struct {
|
2018-12-19 09:49:20 -05:00
|
|
|
doc string
|
|
|
|
dockerInfo info
|
|
|
|
|
2019-01-24 07:29:06 -05:00
|
|
|
prettyGolden string
|
2017-08-24 18:42:11 -04:00
|
|
|
warningsGolden string
|
2019-01-24 07:29:06 -05:00
|
|
|
jsonGolden string
|
2019-01-23 08:34:43 -05:00
|
|
|
expectedError string
|
2017-08-24 18:42:11 -04:00
|
|
|
}{
|
|
|
|
{
|
2019-01-23 08:34:43 -05:00
|
|
|
doc: "info without swarm",
|
|
|
|
dockerInfo: info{
|
2020-05-07 07:28:37 -04:00
|
|
|
Info: &sampleInfoNoSwarm,
|
|
|
|
ClientInfo: &clientInfo{
|
2023-04-10 09:25:31 -04:00
|
|
|
clientVersion: clientVersion{
|
|
|
|
Platform: &platformInfo{Name: "Docker Engine - Community"},
|
|
|
|
Version: "24.0.0",
|
|
|
|
Context: "default",
|
|
|
|
},
|
|
|
|
Debug: true,
|
2020-05-07 07:28:37 -04:00
|
|
|
},
|
2019-01-23 08:34:43 -05:00
|
|
|
},
|
2019-01-24 07:29:06 -05:00
|
|
|
prettyGolden: "docker-info-no-swarm",
|
|
|
|
jsonGolden: "docker-info-no-swarm",
|
2017-08-24 18:42:11 -04:00
|
|
|
},
|
|
|
|
{
|
2018-12-19 09:49:20 -05:00
|
|
|
doc: "info with plugins",
|
|
|
|
dockerInfo: info{
|
|
|
|
Info: &sampleInfoNoSwarm,
|
|
|
|
ClientInfo: &clientInfo{
|
2023-04-10 09:25:31 -04:00
|
|
|
clientVersion: clientVersion{Context: "default"},
|
|
|
|
Plugins: samplePluginsInfo,
|
2018-12-19 09:49:20 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
prettyGolden: "docker-info-plugins",
|
|
|
|
jsonGolden: "docker-info-plugins",
|
|
|
|
warningsGolden: "docker-info-plugins-warnings",
|
|
|
|
},
|
2022-06-05 08:44:08 -04:00
|
|
|
{
|
|
|
|
doc: "info with nil labels",
|
|
|
|
dockerInfo: info{
|
|
|
|
Info: &sampleInfoLabelsNil,
|
2023-04-10 09:25:31 -04:00
|
|
|
ClientInfo: &clientInfo{clientVersion: clientVersion{Context: "default"}},
|
2022-06-05 08:44:08 -04:00
|
|
|
},
|
|
|
|
prettyGolden: "docker-info-with-labels-nil",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "info with empty labels",
|
|
|
|
dockerInfo: info{
|
|
|
|
Info: &sampleInfoLabelsEmpty,
|
2023-04-10 09:25:31 -04:00
|
|
|
ClientInfo: &clientInfo{clientVersion: clientVersion{Context: "default"}},
|
2022-06-05 08:44:08 -04:00
|
|
|
},
|
|
|
|
prettyGolden: "docker-info-with-labels-empty",
|
|
|
|
},
|
2018-12-19 09:49:20 -05:00
|
|
|
{
|
2019-01-23 08:34:43 -05:00
|
|
|
doc: "info with swarm",
|
|
|
|
dockerInfo: info{
|
2020-05-07 07:28:37 -04:00
|
|
|
Info: &infoWithSwarm,
|
|
|
|
ClientInfo: &clientInfo{
|
2023-04-10 09:25:31 -04:00
|
|
|
clientVersion: clientVersion{Context: "default"},
|
|
|
|
Debug: false,
|
2020-05-07 07:28:37 -04:00
|
|
|
},
|
2019-01-23 08:34:43 -05:00
|
|
|
},
|
2019-01-24 07:29:06 -05:00
|
|
|
prettyGolden: "docker-info-with-swarm",
|
|
|
|
jsonGolden: "docker-info-with-swarm",
|
2017-08-24 18:42:11 -04:00
|
|
|
},
|
|
|
|
{
|
2019-01-23 08:34:43 -05:00
|
|
|
doc: "info with legacy warnings",
|
|
|
|
dockerInfo: info{
|
2020-05-07 07:28:37 -04:00
|
|
|
Info: &infoWithWarningsLinux,
|
|
|
|
ClientInfo: &clientInfo{
|
2023-04-10 09:25:31 -04:00
|
|
|
clientVersion: clientVersion{
|
|
|
|
Platform: &platformInfo{Name: "Docker Engine - Community"},
|
|
|
|
Version: "24.0.0",
|
|
|
|
Context: "default",
|
|
|
|
},
|
|
|
|
Debug: true,
|
2020-05-07 07:28:37 -04:00
|
|
|
},
|
2019-01-23 08:34:43 -05:00
|
|
|
},
|
2019-01-24 07:29:06 -05:00
|
|
|
prettyGolden: "docker-info-no-swarm",
|
2017-08-24 18:42:11 -04:00
|
|
|
warningsGolden: "docker-info-warnings",
|
2019-01-24 07:29:06 -05:00
|
|
|
jsonGolden: "docker-info-legacy-warnings",
|
2017-08-24 18:42:11 -04:00
|
|
|
},
|
2018-07-19 13:45:04 -04:00
|
|
|
{
|
2019-01-23 08:34:43 -05:00
|
|
|
doc: "info with daemon warnings",
|
|
|
|
dockerInfo: info{
|
2020-05-07 07:28:37 -04:00
|
|
|
Info: &sampleInfoDaemonWarnings,
|
|
|
|
ClientInfo: &clientInfo{
|
2023-04-10 09:25:31 -04:00
|
|
|
clientVersion: clientVersion{
|
|
|
|
Platform: &platformInfo{Name: "Docker Engine - Community"},
|
|
|
|
Version: "24.0.0",
|
|
|
|
Context: "default",
|
|
|
|
},
|
|
|
|
Debug: true,
|
2020-05-07 07:28:37 -04:00
|
|
|
},
|
2019-01-23 08:34:43 -05:00
|
|
|
},
|
2019-01-24 07:29:06 -05:00
|
|
|
prettyGolden: "docker-info-no-swarm",
|
2018-07-19 13:45:04 -04:00
|
|
|
warningsGolden: "docker-info-warnings",
|
2019-01-24 07:29:06 -05:00
|
|
|
jsonGolden: "docker-info-daemon-warnings",
|
2018-07-19 13:45:04 -04:00
|
|
|
},
|
2019-01-23 08:34:43 -05:00
|
|
|
{
|
|
|
|
doc: "errors for both",
|
|
|
|
dockerInfo: info{
|
|
|
|
ServerErrors: []string{"a server error occurred"},
|
|
|
|
ClientErrors: []string{"a client error occurred"},
|
|
|
|
},
|
2021-04-08 19:46:13 -04:00
|
|
|
prettyGolden: "docker-info-errors",
|
|
|
|
jsonGolden: "docker-info-errors",
|
|
|
|
warningsGolden: "docker-info-errors-stderr",
|
|
|
|
expectedError: "errors pretty printing info",
|
2019-01-23 08:34:43 -05:00
|
|
|
},
|
2019-01-24 09:22:55 -05:00
|
|
|
{
|
|
|
|
doc: "bad security info",
|
|
|
|
dockerInfo: info{
|
|
|
|
Info: &sampleInfoBadSecurity,
|
2021-04-08 19:46:13 -04:00
|
|
|
ServerErrors: []string{"a server error occurred"},
|
2019-01-24 09:22:55 -05:00
|
|
|
ClientInfo: &clientInfo{Debug: false},
|
|
|
|
},
|
2021-04-08 19:46:13 -04:00
|
|
|
prettyGolden: "docker-info-badsec",
|
|
|
|
jsonGolden: "docker-info-badsec",
|
|
|
|
warningsGolden: "docker-info-badsec-stderr",
|
|
|
|
expectedError: "errors pretty printing info",
|
2019-01-24 09:22:55 -05:00
|
|
|
},
|
2017-08-24 18:42:11 -04:00
|
|
|
} {
|
2023-04-10 09:25:31 -04:00
|
|
|
tc := tc
|
2018-07-19 13:45:04 -04:00
|
|
|
t.Run(tc.doc, func(t *testing.T) {
|
|
|
|
cli := test.NewFakeCli(&fakeClient{})
|
2019-01-23 08:34:43 -05:00
|
|
|
err := prettyPrintInfo(cli, tc.dockerInfo)
|
|
|
|
if tc.expectedError == "" {
|
|
|
|
assert.NilError(t, err)
|
|
|
|
} else {
|
|
|
|
assert.Error(t, err, tc.expectedError)
|
|
|
|
}
|
2019-01-24 07:29:06 -05:00
|
|
|
golden.Assert(t, cli.OutBuffer().String(), tc.prettyGolden+".golden")
|
2018-07-19 13:45:04 -04:00
|
|
|
if tc.warningsGolden != "" {
|
|
|
|
golden.Assert(t, cli.ErrBuffer().String(), tc.warningsGolden+".golden")
|
|
|
|
} else {
|
|
|
|
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
|
|
|
}
|
2019-01-24 07:29:06 -05:00
|
|
|
|
2022-06-05 08:44:08 -04:00
|
|
|
if tc.jsonGolden != "" {
|
|
|
|
cli = test.NewFakeCli(&fakeClient{})
|
2023-04-10 10:48:22 -04:00
|
|
|
assert.NilError(t, formatInfo(cli.Out(), tc.dockerInfo, "{{json .}}"))
|
2022-06-05 08:44:08 -04:00
|
|
|
golden.Assert(t, cli.OutBuffer().String(), tc.jsonGolden+".json.golden")
|
|
|
|
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
2023-04-09 07:11:19 -04:00
|
|
|
|
|
|
|
cli = test.NewFakeCli(&fakeClient{})
|
2023-04-10 10:48:22 -04:00
|
|
|
assert.NilError(t, formatInfo(cli.Out(), tc.dockerInfo, "json"))
|
2023-04-09 07:11:19 -04:00
|
|
|
golden.Assert(t, cli.OutBuffer().String(), tc.jsonGolden+".json.golden")
|
|
|
|
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
2022-06-05 08:44:08 -04:00
|
|
|
}
|
2018-07-19 13:45:04 -04:00
|
|
|
})
|
2017-08-24 18:42:11 -04:00
|
|
|
}
|
|
|
|
}
|
2019-01-23 09:26:12 -05:00
|
|
|
|
2023-04-10 10:35:08 -04:00
|
|
|
func BenchmarkPrettyPrintInfo(b *testing.B) {
|
|
|
|
infoWithSwarm := sampleInfoNoSwarm
|
|
|
|
infoWithSwarm.Swarm = sampleSwarmInfo
|
|
|
|
|
|
|
|
dockerInfo := info{
|
|
|
|
Info: &infoWithSwarm,
|
|
|
|
ClientInfo: &clientInfo{
|
|
|
|
clientVersion: clientVersion{
|
|
|
|
Platform: &platformInfo{Name: "Docker Engine - Community"},
|
|
|
|
Version: "24.0.0",
|
|
|
|
Context: "default",
|
|
|
|
},
|
|
|
|
Debug: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
cli := test.NewFakeCli(&fakeClient{})
|
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
_ = prettyPrintInfo(cli, dockerInfo)
|
|
|
|
cli.ResetOutputBuffers()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-23 09:26:12 -05:00
|
|
|
func TestFormatInfo(t *testing.T) {
|
|
|
|
for _, tc := range []struct {
|
|
|
|
doc string
|
|
|
|
template string
|
|
|
|
expectedError string
|
|
|
|
expectedOut string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
doc: "basic",
|
|
|
|
template: "{{.ID}}",
|
|
|
|
expectedOut: sampleID + "\n",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "syntax",
|
|
|
|
template: "{{}",
|
linting: fix incorrectly formatted errors (revive)
cli/compose/interpolation/interpolation.go:102:4: error-strings: error strings should not be capitalized or end with punctuation or a newline (revive)
"invalid interpolation format for %s: %#v. You may need to escape any $ with another $.",
^
cli/command/stack/loader/loader.go:30:30: error-strings: error strings should not be capitalized or end with punctuation or a newline (revive)
return nil, errors.Errorf("Compose file contains unsupported options:\n\n%s\n",
^
cli/command/formatter/formatter.go:76:30: error-strings: error strings should not be capitalized or end with punctuation or a newline (revive)
return tmpl, errors.Errorf("Template parsing error: %v\n", err)
^
cli/command/formatter/formatter.go:97:24: error-strings: error strings should not be capitalized or end with punctuation or a newline (revive)
return errors.Errorf("Template parsing error: %v\n", err)
^
cli/command/image/build.go:257:25: error-strings: error strings should not be capitalized or end with punctuation or a newline (revive)
return errors.Errorf("error checking context: '%s'.", err)
^
cli/command/volume/create.go:35:27: error-strings: error strings should not be capitalized or end with punctuation or a newline (revive)
return errors.Errorf("Conflicting options: either specify --name or provide positional arg, not both\n")
^
cli/command/container/create.go:160:24: error-strings: error strings should not be capitalized or end with punctuation or a newline (revive)
return errors.Errorf("failed to remove the CID file '%s': %s \n", cid.path, err)
^
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-03-27 15:13:03 -04:00
|
|
|
expectedError: `Status: template parsing error: template: :1: unexpected "}" in command, Code: 64`,
|
2019-01-23 09:26:12 -05:00
|
|
|
},
|
2019-10-18 12:04:45 -04:00
|
|
|
{
|
|
|
|
doc: "syntax",
|
|
|
|
template: "{{.badString}}",
|
|
|
|
expectedError: `template: :1:2: executing "" at <.badString>: can't evaluate field badString in type system.info`,
|
|
|
|
},
|
2019-01-23 09:26:12 -05:00
|
|
|
} {
|
2023-04-10 09:25:31 -04:00
|
|
|
tc := tc
|
2019-01-23 09:26:12 -05:00
|
|
|
t.Run(tc.doc, func(t *testing.T) {
|
|
|
|
cli := test.NewFakeCli(&fakeClient{})
|
2019-01-23 08:34:43 -05:00
|
|
|
info := info{
|
|
|
|
Info: &sampleInfoNoSwarm,
|
|
|
|
ClientInfo: &clientInfo{Debug: true},
|
|
|
|
}
|
2023-04-10 10:48:22 -04:00
|
|
|
err := formatInfo(cli.Out(), info, tc.template)
|
2019-01-23 09:26:12 -05:00
|
|
|
if tc.expectedOut != "" {
|
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Equal(t, cli.OutBuffer().String(), tc.expectedOut)
|
|
|
|
} else if tc.expectedError != "" {
|
|
|
|
assert.Error(t, err, tc.expectedError)
|
|
|
|
} else {
|
|
|
|
t.Fatal("test expected to neither pass nor fail")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
docker info: skip API connection if possible
The docker info output contains both "local" and "remote" (daemon-side) information.
The API endpoint to collect daemon information (`/info`) is known to be "heavy",
and (depending on what information is needed) not needed.
This patch checks if the template (`--format`) used requires information from the
daemon, and if not, omits making an API request.
This will improve performance if (for example), the current "context" is requested
from `docker info` or if only plugin information is requested.
Before:
time docker info --format '{{range .ClientInfo.Plugins}}Plugin: {{.Name}}, {{end}}'
Plugin: buildx, Plugin: compose, Plugin: scan,
________________________________________________________
Executed in 301.91 millis fish external
usr time 168.64 millis 82.00 micros 168.56 millis
sys time 113.72 millis 811.00 micros 112.91 millis
time docker info --format '{{json .ClientInfo.Plugins}}'
time docker info --format '{{.ClientInfo.Context}}'
default
________________________________________________________
Executed in 334.38 millis fish external
usr time 177.23 millis 93.00 micros 177.13 millis
sys time 124.90 millis 927.00 micros 123.97 millis
docker context use remote-ssh-daemon
time docker info --format '{{.ClientInfo.Context}}'
remote-ssh-daemon
________________________________________________________
Executed in 1.22 secs fish external
usr time 116.93 millis 110.00 micros 116.82 millis
sys time 144.36 millis 887.00 micros 143.47 millis
And daemon logs:
Jul 06 12:42:12 remote-ssh-daemon dockerd[14377]: time="2021-07-06T12:42:12.139529947Z" level=debug msg="Calling HEAD /_ping"
Jul 06 12:42:12 remote-ssh-daemon dockerd[14377]: time="2021-07-06T12:42:12.140772052Z" level=debug msg="Calling HEAD /_ping"
Jul 06 12:42:12 remote-ssh-daemon dockerd[14377]: time="2021-07-06T12:42:12.163832016Z" level=debug msg="Calling GET /v1.41/info"
After:
time ./build/docker info --format '{{range .ClientInfo.Plugins}}Plugin: {{.Name}}, {{end}}'
Plugin: buildx, Plugin: compose, Plugin: scan,
________________________________________________________
Executed in 139.84 millis fish external
usr time 76.53 millis 62.00 micros 76.46 millis
sys time 69.25 millis 723.00 micros 68.53 millis
time ./build/docker info --format '{{.ClientInfo.Context}}'
default
________________________________________________________
Executed in 136.94 millis fish external
usr time 74.61 millis 74.00 micros 74.54 millis
sys time 65.77 millis 858.00 micros 64.91 millis
docker context use remote-ssh-daemon
time ./build/docker info --format '{{.ClientInfo.Context}}'
remote-ssh-daemon
________________________________________________________
Executed in 1.02 secs fish external
usr time 74.25 millis 76.00 micros 74.17 millis
sys time 65.09 millis 643.00 micros 64.44 millis
And daemon logs:
Jul 06 12:42:55 remote-ssh-daemon dockerd[14377]: time="2021-07-06T12:42:55.313654687Z" level=debug msg="Calling HEAD /_ping"
Jul 06 12:42:55 remote-ssh-daemon dockerd[14377]: time="2021-07-06T12:42:55.314811624Z" level=debug msg="Calling HEAD /_ping"
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-07-06 08:43:42 -04:00
|
|
|
|
|
|
|
func TestNeedsServerInfo(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
doc string
|
|
|
|
template string
|
|
|
|
expected bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
doc: "no template",
|
|
|
|
template: "",
|
|
|
|
expected: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "JSON",
|
|
|
|
template: "json",
|
|
|
|
expected: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "JSON (all fields)",
|
|
|
|
template: "{{json .}}",
|
|
|
|
expected: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "JSON (Server ID)",
|
|
|
|
template: "{{json .ID}}",
|
|
|
|
expected: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "ClientInfo",
|
|
|
|
template: "{{json .ClientInfo}}",
|
|
|
|
expected: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "JSON ClientInfo",
|
|
|
|
template: "{{json .ClientInfo}}",
|
|
|
|
expected: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "JSON (Active context)",
|
|
|
|
template: "{{json .ClientInfo.Context}}",
|
|
|
|
expected: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
inf := info{ClientInfo: &clientInfo{}}
|
|
|
|
for _, tc := range tests {
|
|
|
|
tc := tc
|
|
|
|
t.Run(tc.doc, func(t *testing.T) {
|
|
|
|
assert.Equal(t, needsServerInfo(tc.template, inf), tc.expected)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|