add support some run options

Signed-off-by: Xian Chaobo <xianchaobo@huawei.com>
This commit is contained in:
Xian Chaobo 2016-03-03 19:53:47 +08:00
parent 204a51c805
commit ba4ad74de3
8 changed files with 193 additions and 41 deletions

2
Godeps/Godeps.json generated
View File

@ -171,7 +171,7 @@
},
{
"ImportPath": "github.com/samalba/dockerclient",
"Rev": "b5aaea9adc8168fe8ce00731d3025ffbfb389c87"
"Rev": "5747eb30667cf7088aea1de37b93856b5cd2f010"
},
{
"ImportPath": "github.com/samuel/go-zookeeper/zk",

View File

@ -16,7 +16,16 @@ import (
"time"
)
var _ Client = (*DockerClient)(nil)
const (
// APIVersion is currently hardcoded to v1.15
// TODO: bump the API version or allow users to choose which API version to
// use the client with. The current value does not make sense for many
// methods, such as ContainerStats, StartMonitorStats, and StopAllMonitorStats
// (v1.17) and
// ListVolumes, {Remove,Create}Volume, ListNetworks,
// {Inspect,Create,Connect,Disconnect,Remove}Network (v1.21)
APIVersion = "v1.15"
)
@ -256,6 +265,36 @@ func (client *DockerClient) ContainerChanges(id string) ([]*ContainerChanges, er
return changes, nil
}
func (client *DockerClient) ContainerStats(id string, stopChan <-chan struct{}) (<-chan StatsOrError, error) {
uri := fmt.Sprintf("/%s/containers/%s/stats", APIVersion, id)
resp, err := client.HTTPClient.Get(client.URL.String() + uri)
if err != nil {
return nil, err
}
decode := func(decoder *json.Decoder) decodingResult {
var containerStats Stats
if err := decoder.Decode(&containerStats); err != nil {
return decodingResult{err: err}
} else {
return decodingResult{result: containerStats}
}
}
decodingResultChan := client.readJSONStream(resp.Body, decode, stopChan)
statsOrErrorChan := make(chan StatsOrError)
go func() {
for decodingResult := range decodingResultChan {
stats, _ := decodingResult.result.(Stats)
statsOrErrorChan <- StatsOrError{
Stats: stats,
Error: decodingResult.err,
}
}
close(statsOrErrorChan)
}()
return statsOrErrorChan, nil
}
func (client *DockerClient) readJSONStream(stream io.ReadCloser, decode func(*json.Decoder) decodingResult, stopChan <-chan struct{}) <-chan decodingResult {
resultChan := make(chan decodingResult)
@ -719,6 +758,31 @@ func (client *DockerClient) RemoveImage(name string, force bool) ([]*ImageDelete
return imageDelete, nil
}
func (client *DockerClient) SearchImages(query, registry string, auth *AuthConfig) ([]ImageSearch, error) {
term := query
if registry != "" {
term = registry + "/" + term
}
uri := fmt.Sprintf("/%s/images/search?term=%s", APIVersion, term)
headers := map[string]string{}
if auth != nil {
if encodedAuth, err := auth.encode(); err != nil {
return nil, err
} else {
headers["X-Registry-Auth"] = encodedAuth
}
}
data, err := client.doRequest("GET", uri, nil, headers)
if err != nil {
return nil, err
}
var imageSearches []ImageSearch
if err := json.Unmarshal(data, &imageSearches); err != nil {
return nil, err
}
return imageSearches, nil
}
func (client *DockerClient) PauseContainer(id string) error {
uri := fmt.Sprintf("/%s/containers/%s/pause", APIVersion, id)
_, err := client.doRequest("POST", uri, nil, nil)

View File

@ -10,4 +10,6 @@ var haproxyPullOutput = `{"status":"The image you are pulling has been verified"
{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"ecb4b23ca7ce"}{"status":"Already exists","progressDetail":{},"id":"f453e940c177"}{"status":"Already exists","progressDetail":{},"id":"fc5ea1bc05ab"}{"status":"Already exists","progressDetail":{},"id":"380557f8f7b3"}{"status":"Status: Image is up to date for haproxy"}
`
var statsResp = `{"read":"2015-02-02T17:06:08.187833376-05:00","network":{"rx_bytes":99988,"rx_packets":928,"rx_errors":0,"rx_dropped":0,"tx_bytes":1786548,"tx_packets":877,"tx_errors":0,"tx_dropped":0},"cpu_stats":{"cpu_usage":{"total_usage":170018598,"percpu_usage":[170018598],"usage_in_kernelmode":30000000,"usage_in_usermode":70000000},"system_cpu_usage":9020930000000,"throttling_data":{"periods":0,"throttled_periods":0,"throttled_time":0}},"memory_stats":{"usage":18022400,"max_usage":20541440,"stats":{"active_anon":6213632,"active_file":176128,"cache":11808768,"hierarchical_memory_limit":9223372036854775807,"hierarchical_memsw_limit":9223372036854775807,"inactive_anon":0,"inactive_file":11632640,"mapped_file":5165056,"pgfault":2535,"pgmajfault":13,"pgpgin":4293,"pgpgout":1937,"rss":6213632,"rss_huge":2097152,"swap":0,"total_active_anon":6213632,"total_active_file":176128,"total_cache":11808768,"total_inactive_anon":0,"total_inactive_file":11632640,"total_mapped_file":5165056,"total_pgfault":2535,"total_pgmajfault":13,"total_pgpgin":4293,"total_pgpgout":1937,"total_rss":6213632,"total_rss_huge":2097152,"total_swap":0,"total_unevictable":0,"unevictable":0},"failcnt":0,"limit":1041051648},"blkio_stats":{"io_service_bytes_recursive":[{"major":7,"minor":0,"op":"Read","value":28672},{"major":7,"minor":0,"op":"Write","value":0},{"major":7,"minor":0,"op":"Sync","value":0},{"major":7,"minor":0,"op":"Async","value":28672},{"major":7,"minor":0,"op":"Total","value":28672},{"major":253,"minor":0,"op":"Read","value":28672},{"major":253,"minor":0,"op":"Write","value":0},{"major":253,"minor":0,"op":"Sync","value":0},{"major":253,"minor":0,"op":"Async","value":28672},{"major":253,"minor":0,"op":"Total","value":28672},{"major":253,"minor":7,"op":"Read","value":11718656},{"major":253,"minor":7,"op":"Write","value":0},{"major":253,"minor":7,"op":"Sync","value":0},{"major":253,"minor":7,"op":"Async","value":11718656},{"major":253,"minor":7,"op":"Total","value":11718656},{"major":202,"minor":0,"op":"Read","value":0},{"major":202,"minor":0,"op":"Write","value":0},{"major":202,"minor":0,"op":"Sync","value":0},{"major":202,"minor":0,"op":"Async","value":0},{"major":202,"minor":0,"op":"Total","value":0}],"io_serviced_recursive":[{"major":7,"minor":0,"op":"Read","value":7},{"major":7,"minor":0,"op":"Write","value":0},{"major":7,"minor":0,"op":"Sync","value":0},{"major":7,"minor":0,"op":"Async","value":7},{"major":7,"minor":0,"op":"Total","value":7},{"major":253,"minor":0,"op":"Read","value":7},{"major":253,"minor":0,"op":"Write","value":0},{"major":253,"minor":0,"op":"Sync","value":0},{"major":253,"minor":0,"op":"Async","value":7},{"major":253,"minor":0,"op":"Total","value":7},{"major":253,"minor":7,"op":"Read","value":312},{"major":253,"minor":7,"op":"Write","value":0},{"major":253,"minor":7,"op":"Sync","value":0},{"major":253,"minor":7,"op":"Async","value":312},{"major":253,"minor":7,"op":"Total","value":312},{"major":202,"minor":0,"op":"Read","value":0},{"major":202,"minor":0,"op":"Write","value":0},{"major":202,"minor":0,"op":"Sync","value":0},{"major":202,"minor":0,"op":"Async","value":0},{"major":202,"minor":0,"op":"Total","value":0}],"io_queue_recursive":[],"io_service_time_recursive":[],"io_wait_time_recursive":[],"io_merged_recursive":[],"io_time_recursive":[],"sectors_recursive":[]}}`
var eventsResp = `{"status":"pull","id":"nginx:latest","time":1428620433}{"status":"create","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620433}{"status":"start","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620433}{"status":"die","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620442}{"status":"create","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"start","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"die","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"pull","id":"debian:latest","time":1428620453}{"status":"create","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"start","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"die","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"create","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620458}{"status":"start","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620458}{"status":"pause","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620462}{"status":"unpause","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620466}{"status":"die","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620469}`

View File

@ -16,6 +16,12 @@ type Client interface {
CreateContainer(config *ContainerConfig, name string, authConfig *AuthConfig) (string, error)
ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error)
ContainerChanges(id string) ([]*ContainerChanges, error)
// ContainerStats takes a container ID and an optional stop channel and
// returns a StatsOrError channel. If an error is ever sent, then no
// more stats will be sent on that channel. If a stop channel is
// provided, events will stop being monitored after the stop channel is
// closed.
ContainerStats(id string, stopChan <-chan struct{}) (<-chan StatsOrError, error)
ExecCreate(config *ExecConfig) (string, error)
ExecStart(id string, config *ExecConfig) error
ExecResize(id string, width, height int) error
@ -42,6 +48,7 @@ type Client interface {
RemoveContainer(id string, force, volumes bool) error
ListImages(all bool) ([]*Image, error)
RemoveImage(name string, force bool) ([]*ImageDelete, error)
SearchImages(query, registry string, auth *AuthConfig) ([]ImageSearch, error)
PauseContainer(name string) error
UnpauseContainer(name string) error
RenameContainer(oldName string, newName string) error

View File

@ -50,6 +50,11 @@ func (client *MockClient) ContainerChanges(id string) ([]*dockerclient.Container
return args.Get(0).([]*dockerclient.ContainerChanges), args.Error(1)
}
func (client *MockClient) ContainerStats(id string, stopChan <-chan struct{}) (<-chan dockerclient.StatsOrError, error) {
args := client.Mock.Called(id, stopChan)
return args.Get(0).(<-chan dockerclient.StatsOrError), args.Error(1)
}
func (client *MockClient) AttachContainer(id string, options *dockerclient.AttachOptions) (io.ReadCloser, error) {
args := client.Mock.Called(id, options)
return args.Get(0).(io.ReadCloser), args.Error(1)
@ -141,6 +146,11 @@ func (client *MockClient) RemoveImage(name string, force bool) ([]*dockerclient.
return args.Get(0).([]*dockerclient.ImageDelete), args.Error(1)
}
func (client *MockClient) SearchImages(query, registry string, authConfig *dockerclient.AuthConfig) ([]dockerclient.ImageSearch, error) {
args := client.Mock.Called(query, registry, authConfig)
return args.Get(0).([]dockerclient.ImageSearch), args.Error(1)
}
func (client *MockClient) PauseContainer(name string) error {
args := client.Mock.Called(name)
return args.Error(0)

View File

@ -46,6 +46,10 @@ func (client *NopClient) ContainerChanges(id string) ([]*dockerclient.ContainerC
return nil, ErrNoEngine
}
func (client *NopClient) ContainerStats(id string, stopChan <-chan struct{}) (<-chan dockerclient.StatsOrError, error) {
return nil, ErrNoEngine
}
func (client *NopClient) AttachContainer(id string, options *dockerclient.AttachOptions) (io.ReadCloser, error) {
return nil, ErrNoEngine
}
@ -122,6 +126,10 @@ func (client *NopClient) RemoveImage(name string, force bool) ([]*dockerclient.I
return nil, ErrNoEngine
}
func (client *NopClient) SearchImages(query, registry string, authConfig *dockerclient.AuthConfig) ([]dockerclient.ImageSearch, error) {
return nil, ErrNoEngine
}
func (client *NopClient) PauseContainer(name string) error {
return ErrNoEngine
}

View File

@ -89,6 +89,24 @@ type HostConfig struct {
CgroupParent string
ConsoleSize [2]int
VolumeDriver string
OomScoreAdj int
Tmpfs map[string]string
ShmSize int64
BlkioWeightDevice []WeightDevice
BlkioDeviceReadBps []ThrottleDevice
BlkioDeviceWriteBps []ThrottleDevice
BlkioDeviceReadIOps []ThrottleDevice
BlkioDeviceWriteIOps []ThrottleDevice
}
type WeightDevice struct {
Path string
Weight uint16
}
type ThrottleDevice struct {
Path string
Rate uint64
}
type DeviceMapping struct {
@ -220,6 +238,14 @@ type ImageInfo struct {
VirtualSize int64
}
type ImageSearch struct {
Description string `json:"description,omitempty" yaml:"description,omitempty"`
IsOfficial bool `json:"is_official,omitempty" yaml:"is_official,omitempty"`
IsAutomated bool `json:"is_automated,omitempty" yaml:"is_automated,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
StarCount int `json:"star_count,omitempty" yaml:"star_count,omitempty"`
}
type ContainerInfo struct {
Id string
Created string
@ -381,6 +407,11 @@ type ImageDelete struct {
Untagged string
}
type StatsOrError struct {
Stats
Error error
}
type EventOrError struct {
Event
Error error
@ -406,6 +437,7 @@ type ThrottlingData struct {
ThrottledTime uint64 `json:"throttled_time"`
}
// All CPU stats are aggregated since container inception.
type CpuUsage struct {
// Total CPU time consumed.
// Units: nanoseconds.

View File

@ -99,6 +99,35 @@ function teardown() {
[[ "${output}" == *"someDnsOption"* ]]
# stop-signal
[[ "${output}" == *"\"StopSignal\": \"SIGKILL\""* ]]
# following options are introduced in docker 1.10, skip older version
run docker --version
if [[ "${output}" == "Docker version 1.9"* ]]; then
skip
fi
docker_swarm run -d --name test_container2 \
--oom-score-adj=350 \
--tmpfs=/tempfs:rw \
--device-read-iops=/dev/null:351 \
--device-write-iops=/dev/null:352 \
--device-read-bps=/dev/null:1mb \
--device-write-bps=/dev/null:2mb \
busybox sleep 1000
run docker_swarm inspect test_container2
# oom-score-adj
[[ "${output}" == *"\"OomScoreAdj\": 350"* ]]
# tmpfs
[[ "${output}" == *"\"/tempfs\": \"rw\""* ]]
# device-read-iops
[[ "${output}" == *"351"* ]]
# device-write-iops
[[ "${output}" == *"352"* ]]
# device-read-bps
[[ "${output}" == *"1048576"* ]]
# device-write-bps
[[ "${output}" == *"2097152"* ]]
}
@test "docker run --ip" {