2014-02-11 23:04:39 -05:00
|
|
|
package runconfig
|
|
|
|
|
|
|
|
import (
|
2015-04-10 20:05:21 -04:00
|
|
|
"encoding/json"
|
|
|
|
"io"
|
2015-05-05 16:00:20 -04:00
|
|
|
"strings"
|
2015-04-10 20:05:21 -04:00
|
|
|
|
2014-07-24 18:19:50 -04:00
|
|
|
"github.com/docker/docker/nat"
|
2014-02-11 23:04:39 -05:00
|
|
|
)
|
|
|
|
|
2015-04-10 20:05:21 -04:00
|
|
|
// Entrypoint encapsulates the container entrypoint.
|
|
|
|
// It might be represented as a string or an array of strings.
|
|
|
|
// We need to override the json decoder to accept both options.
|
|
|
|
// The JSON decoder will fail if the api sends an string and
|
|
|
|
// we try to decode it into an array of string.
|
|
|
|
type Entrypoint struct {
|
|
|
|
parts []string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Entrypoint) MarshalJSON() ([]byte, error) {
|
|
|
|
if e == nil {
|
|
|
|
return []byte{}, nil
|
|
|
|
}
|
|
|
|
return json.Marshal(e.Slice())
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON decoded the entrypoint whether it's a string or an array of strings.
|
|
|
|
func (e *Entrypoint) UnmarshalJSON(b []byte) error {
|
|
|
|
if len(b) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
p := make([]string, 0, 1)
|
|
|
|
if err := json.Unmarshal(b, &p); err != nil {
|
2015-06-26 01:15:57 -04:00
|
|
|
var s string
|
|
|
|
if err := json.Unmarshal(b, &s); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p = append(p, s)
|
2015-04-10 20:05:21 -04:00
|
|
|
}
|
|
|
|
e.parts = p
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Entrypoint) Len() int {
|
|
|
|
if e == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return len(e.parts)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Entrypoint) Slice() []string {
|
|
|
|
if e == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return e.parts
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewEntrypoint(parts ...string) *Entrypoint {
|
|
|
|
return &Entrypoint{parts}
|
|
|
|
}
|
|
|
|
|
|
|
|
type Command struct {
|
|
|
|
parts []string
|
|
|
|
}
|
|
|
|
|
2015-05-05 16:00:20 -04:00
|
|
|
func (e *Command) ToString() string {
|
|
|
|
return strings.Join(e.parts, " ")
|
|
|
|
}
|
|
|
|
|
2015-04-10 20:05:21 -04:00
|
|
|
func (e *Command) MarshalJSON() ([]byte, error) {
|
|
|
|
if e == nil {
|
|
|
|
return []byte{}, nil
|
|
|
|
}
|
|
|
|
return json.Marshal(e.Slice())
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON decoded the entrypoint whether it's a string or an array of strings.
|
|
|
|
func (e *Command) UnmarshalJSON(b []byte) error {
|
|
|
|
if len(b) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
p := make([]string, 0, 1)
|
|
|
|
if err := json.Unmarshal(b, &p); err != nil {
|
2015-06-26 01:15:57 -04:00
|
|
|
var s string
|
|
|
|
if err := json.Unmarshal(b, &s); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p = append(p, s)
|
2015-04-10 20:05:21 -04:00
|
|
|
}
|
|
|
|
e.parts = p
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Command) Len() int {
|
|
|
|
if e == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return len(e.parts)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Command) Slice() []string {
|
|
|
|
if e == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return e.parts
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewCommand(parts ...string) *Command {
|
|
|
|
return &Command{parts}
|
|
|
|
}
|
|
|
|
|
2014-02-11 23:04:39 -05:00
|
|
|
// Note: the Config structure should hold only portable information about the container.
|
|
|
|
// Here, "portable" means "independent from the host we are running on".
|
|
|
|
// Non-portable information *should* appear in HostConfig.
|
|
|
|
type Config struct {
|
|
|
|
Hostname string
|
|
|
|
Domainname string
|
|
|
|
User string
|
|
|
|
AttachStdin bool
|
|
|
|
AttachStdout bool
|
|
|
|
AttachStderr bool
|
|
|
|
ExposedPorts map[nat.Port]struct{}
|
2015-06-15 01:31:09 -04:00
|
|
|
PublishService string
|
2014-02-11 23:04:39 -05:00
|
|
|
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
|
|
|
OpenStdin bool // Open stdin
|
|
|
|
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
|
|
|
Env []string
|
2015-04-10 20:05:21 -04:00
|
|
|
Cmd *Command
|
2014-02-11 23:04:39 -05:00
|
|
|
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
|
|
|
|
Volumes map[string]struct{}
|
2015-05-19 16:05:25 -04:00
|
|
|
VolumeDriver string
|
2014-02-11 23:04:39 -05:00
|
|
|
WorkingDir string
|
2015-04-10 20:05:21 -04:00
|
|
|
Entrypoint *Entrypoint
|
2014-02-11 23:04:39 -05:00
|
|
|
NetworkDisabled bool
|
2014-10-03 17:02:17 -04:00
|
|
|
MacAddress string
|
2014-02-11 23:04:39 -05:00
|
|
|
OnBuild []string
|
2015-02-17 10:20:06 -05:00
|
|
|
Labels map[string]string
|
2014-02-11 23:04:39 -05:00
|
|
|
}
|
|
|
|
|
2015-04-10 20:05:21 -04:00
|
|
|
type ContainerConfigWrapper struct {
|
|
|
|
*Config
|
2015-05-14 10:39:44 -04:00
|
|
|
InnerHostConfig *HostConfig `json:"HostConfig,omitempty"`
|
|
|
|
Cpuset string `json:",omitempty"` // Deprecated. Exported for backwards compatibility.
|
|
|
|
*HostConfig // Deprecated. Exported to read attrubutes from json that are not in the inner host config structure.
|
|
|
|
|
2015-04-10 20:05:21 -04:00
|
|
|
}
|
|
|
|
|
2015-05-14 10:39:44 -04:00
|
|
|
func (w *ContainerConfigWrapper) GetHostConfig() *HostConfig {
|
|
|
|
hc := w.HostConfig
|
|
|
|
|
|
|
|
if hc == nil && w.InnerHostConfig != nil {
|
|
|
|
hc = w.InnerHostConfig
|
|
|
|
} else if w.InnerHostConfig != nil {
|
|
|
|
if hc.Memory != 0 && w.InnerHostConfig.Memory == 0 {
|
|
|
|
w.InnerHostConfig.Memory = hc.Memory
|
|
|
|
}
|
|
|
|
if hc.MemorySwap != 0 && w.InnerHostConfig.MemorySwap == 0 {
|
|
|
|
w.InnerHostConfig.MemorySwap = hc.MemorySwap
|
|
|
|
}
|
|
|
|
if hc.CpuShares != 0 && w.InnerHostConfig.CpuShares == 0 {
|
|
|
|
w.InnerHostConfig.CpuShares = hc.CpuShares
|
|
|
|
}
|
|
|
|
|
|
|
|
hc = w.InnerHostConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
if hc != nil && w.Cpuset != "" && hc.CpusetCpus == "" {
|
|
|
|
hc.CpusetCpus = w.Cpuset
|
2014-02-11 23:04:39 -05:00
|
|
|
}
|
2015-02-17 10:20:06 -05:00
|
|
|
|
2015-05-14 10:39:44 -04:00
|
|
|
return hc
|
2015-04-10 20:05:21 -04:00
|
|
|
}
|
2015-02-17 10:20:06 -05:00
|
|
|
|
2015-06-06 12:41:42 -04:00
|
|
|
// DecodeContainerConfig decodes a json encoded config into a ContainerConfigWrapper
|
|
|
|
// struct and returns both a Config and an HostConfig struct
|
|
|
|
// Be aware this function is not checking whether the resulted structs are nil,
|
|
|
|
// it's your business to do so
|
2015-04-10 20:05:21 -04:00
|
|
|
func DecodeContainerConfig(src io.Reader) (*Config, *HostConfig, error) {
|
|
|
|
decoder := json.NewDecoder(src)
|
|
|
|
|
|
|
|
var w ContainerConfigWrapper
|
|
|
|
if err := decoder.Decode(&w); err != nil {
|
|
|
|
return nil, nil, err
|
2014-02-11 23:04:39 -05:00
|
|
|
}
|
2015-04-10 20:05:21 -04:00
|
|
|
|
2015-05-14 10:39:44 -04:00
|
|
|
return w.Config, w.GetHostConfig(), nil
|
2014-02-11 23:04:39 -05:00
|
|
|
}
|