// Ensure there is a docker binary in the path, // and printing an error if its version is below the minimal requirement. func checkDockerClient() { output, err := commandOutput("docker", []string{"--version"}) if err != nil { panic(StatusError{errors.New("Error when probing Docker's client version. Is docker installed and within the $PATH?"), 69}) } re := regexp.MustCompile("([0-9]+)\\.([0-9]+)\\.?([0-9]+)?") rawVersions := re.FindStringSubmatch(string(output)) var versions []int for _, rawVersion := range rawVersions[1:] { version, err := strconv.Atoi(rawVersion) if err != nil { print.Errorf("Error when parsing Docker's version %v: %v", rawVersion, err) break } versions = append(versions, version) } for i, expectedVersion := range requiredDockerVersion { if versions[i] > expectedVersion { break } if versions[i] < expectedVersion { print.Errorf("Unsupported client version! Please upgrade to Docker %v or later.\n", intJoin(requiredDockerVersion, ".")) } } }
// Remove container func (c *container) Rm(force bool) { if c.Exists() { containerIsRunning := c.Running() if !force && containerIsRunning { print.Errorf("Container %s is running and cannot be removed. Use --force to remove anyway.\n", c.Name()) } else { args := []string{"rm"} if force && containerIsRunning { executeHook(c.Hooks().PreStop()) args = append(args, "--force") } if c.RmParams.Volumes { fmt.Printf("Removing container %s and its volumes ... ", c.Name()) args = append(args, "--volumes") } else { fmt.Printf("Removing container %s ... ", c.Name()) } args = append(args, c.Name()) executeCommand("docker", args) if force && containerIsRunning { executeHook(c.Hooks().PostStop()) } c.id = "" } } }
// dumps the dependency graph as a DOT to the writer func (graph DependencyGraph) DOT(writer io.Writer, targetedContainers Containers) { const dotTemplate = `{{ $targetedContainers := .TargetedContainers }}digraph { {{ range $name, $dependencies := .Graph }}{{ with $dependencies }} "{{ $name }}" [style=bold{{ range $targetedContainers }}{{ if eq $name .Name }},color=red{{ end }}{{ end }}] {{ range .Link }} "{{ $name }}"->"{{ . }}" {{ end }}{{ range .VolumesFrom }} "{{ $name }}"->"{{ . }}" [style=dashed] {{ end }}{{ if ne .Net "" }} "{{ $name }}"->"{{ .Net }}" [style=dotted] {{ end }}{{ end }}{{ end }}} ` template, err := template.New("dot").Parse(dotTemplate) if err != nil { print.Errorf("ERROR: %s\n", err) return } err = template.Execute(writer, dotInput{graph, targetedContainers}) if err != nil { print.Errorf("ERROR: %s\n", err) } }
// Start container func (container Container) start() { if container.exists() { if !container.running() { fmt.Printf("Starting container %s ... ", container.Name()) args := []string{"start", container.Name()} executeCommand("docker", args) } } else { print.Errorf("Container %s does not exist.\n", container.Name()) } }
// Stats about containers. func (containers Containers) stats() { args := []string{"stats"} for _, container := range containers { if container.Running() { args = append(args, container.Name()) } } if len(args) > 1 { executeCommand("docker", args) } else { print.Errorf("None of the targeted container is running.\n") } }
// returns a function to be set as a cobra command run, wrapping a command meant to be run according to the config func configCommand(wrapped func(config Config), forceOrder bool) func(cmd *cobra.Command, args []string) { return func(cmd *cobra.Command, args []string) { for _, value := range []string{options.cascadeDependencies, options.cascadeAffected, options.ignoreMissing} { if value != "none" && value != "all" && value != "link" && value != "volumesFrom" && value != "net" { print.Errorf("Error: invalid dependency type value: %v", value) cmd.Usage() panic(StatusError{status: 64}) } } // Set target from args options.target = args cfg = NewConfig(options, forceOrder) if containers := cfg.TargetedContainers(); len(containers) == 0 { print.Errorf("ERROR: Command cannot be applied to any container.") } else { if isVerbose() { print.Infof("Command will be applied to: %v\n\n", strings.Join(containers.names(), ", ")) } wrapped(cfg) } } }
func (r *RunParameters) Cmd() []string { var cmd []string if r.RawCmd != nil { switch rawCmd := r.RawCmd.(type) { case string: if len(rawCmd) > 0 { cmds, err := shlex.Split(os.ExpandEnv(rawCmd)) if err != nil { print.Errorf("Error when parsing cmd `%v`: %v. Proceeding with %q.", rawCmd, err, cmds) } cmd = append(cmd, cmds...) } case []interface{}: cmds := make([]string, len(rawCmd)) for i, v := range rawCmd { cmds[i] = os.ExpandEnv(v.(string)) } cmd = append(cmd, cmds...) default: print.Errorf("cmd is of unknown type!") } } return cmd }
// Remove container func (container Container) rm() { if container.exists() { if container.running() { print.Errorf("Container %s is running and cannot be removed.\n", container.Name()) } else { args := []string{"rm"} if container.Rm.Volumes { fmt.Printf("Removing container %s and its volumes ... ", container.Name()) args = append(args, "--volumes") } else { fmt.Printf("Removing container %s ... ", container.Name()) } args = append(args, container.Name()) executeCommand("docker", args) } } }
// Start container func (c *container) Start() { if c.Exists() { if !c.Running() { fmt.Printf("Starting container %s ... ", c.Name()) args := []string{"start"} if c.StartParams.Attach { args = append(args, "--attach") } if c.StartParams.Interactive { args = append(args, "--interactive") } args = append(args, c.Name()) executeCommand("docker", args) } } else { print.Errorf("Container %s does not exist.\n", c.Name()) } }
func (r *RunParameters) Label() []string { var label []string if r.RawLabel != nil { switch rawLabel := r.RawLabel.(type) { case []interface{}: for _, v := range rawLabel { label = append(label, os.ExpandEnv(v.(string))) } case map[interface{}]interface{}: for k, v := range rawLabel { label = append(label, os.ExpandEnv(k.(string))+"="+os.ExpandEnv(v.(string))) } default: print.Errorf("label is of unknown type!") } } return label }
func (r *RunParameters) Env() []string { var env []string if r.RawEnv != nil { switch rawEnv := r.RawEnv.(type) { case []interface{}: for _, v := range rawEnv { env = append(env, os.ExpandEnv(v.(string))) } case map[interface{}]interface{}: for k, v := range rawEnv { env = append(env, os.ExpandEnv(k.(string))+"="+os.ExpandEnv(v.(string))) } default: print.Errorf("env is of unknown type!") } } return env }
func (r *RunParameters) Cmd() []string { var cmd []string if r.RawCmd != nil { switch rawCmd := r.RawCmd.(type) { case string: if len(rawCmd) > 0 { cmd = append(cmd, os.ExpandEnv(rawCmd)) } case []interface{}: cmds := make([]string, len(rawCmd)) for i, v := range rawCmd { cmds[i] = os.ExpandEnv(v.(string)) } cmd = append(cmd, cmds...) default: print.Errorf("cmd is of unknown type!") } } return cmd }
func RealMain() { // On panic, recover the error, display it and return the given status code if any defer func() { var statusError StatusError switch err := recover().(type) { case StatusError: statusError = err case error: statusError = StatusError{err, 1} case string: statusError = StatusError{errors.New(err), 1} default: statusError = StatusError{} } if statusError.error != nil { print.Errorf("ERROR: %s\n", statusError.error) } os.Exit(statusError.status) }() handleCmd() }