2013-03-14 05:26:46 -04:00
package docker
2013-02-13 20:10:00 -05:00
import (
2013-02-13 20:28:13 -05:00
"bytes"
"encoding/json"
2013-04-22 12:17:47 -04:00
"flag"
2013-02-13 20:10:00 -05:00
"fmt"
2013-03-14 20:43:59 -04:00
"github.com/dotcloud/docker/auth"
2013-04-29 09:12:18 -04:00
"github.com/dotcloud/docker/term"
2013-05-14 18:37:35 -04:00
"github.com/dotcloud/docker/utils"
2013-02-13 20:28:13 -05:00
"io"
2013-04-22 12:17:47 -04:00
"io/ioutil"
2013-05-22 23:07:26 -04:00
"mime/multipart"
2013-04-23 12:20:53 -04:00
"net"
2013-03-13 14:33:48 -04:00
"net/http"
2013-04-23 12:20:53 -04:00
"net/http/httputil"
2013-03-13 21:37:00 -04:00
"net/url"
2013-05-08 18:26:44 -04:00
"os"
2013-05-24 14:07:32 -04:00
"os/signal"
2013-05-29 13:51:47 -04:00
"path"
2013-04-05 21:00:10 -04:00
"path/filepath"
2013-05-13 05:48:27 -04:00
"reflect"
2013-05-21 08:53:05 -04:00
"regexp"
2013-02-28 14:52:22 -05:00
"strconv"
2013-02-13 20:28:13 -05:00
"strings"
2013-05-24 14:07:32 -04:00
"syscall"
2013-02-13 20:28:13 -05:00
"text/tabwriter"
"time"
2013-03-28 15:11:47 -04:00
"unicode"
2013-02-13 20:10:00 -05:00
)
2013-06-17 22:50:31 -04:00
const VERSION = "0.4.2"
2013-02-13 20:10:00 -05:00
2013-04-11 15:58:23 -04:00
var (
2013-06-04 14:00:22 -04:00
GITCOMMIT string
2013-04-11 15:58:23 -04:00
)
2013-04-01 14:12:56 -04:00
2013-05-23 12:32:39 -04:00
func ( cli * DockerCli ) getMethod ( name string ) ( reflect . Method , bool ) {
methodName := "Cmd" + strings . ToUpper ( name [ : 1 ] ) + strings . ToLower ( name [ 1 : ] )
return reflect . TypeOf ( cli ) . MethodByName ( methodName )
}
2013-05-23 12:09:28 -04:00
func ParseCommands ( addr string , port int , args ... string ) error {
2013-05-24 14:56:21 -04:00
cli := NewDockerCli ( addr , port )
2013-04-22 12:17:47 -04:00
if len ( args ) > 0 {
2013-05-23 12:32:39 -04:00
method , exists := cli . getMethod ( args [ 0 ] )
2013-04-22 12:17:47 -04:00
if ! exists {
2013-04-23 12:20:53 -04:00
fmt . Println ( "Error: Command not found:" , args [ 0 ] )
2013-05-23 12:32:39 -04:00
return cli . CmdHelp ( args [ 1 : ] ... )
2013-04-22 12:17:47 -04:00
}
2013-05-13 05:48:27 -04:00
ret := method . Func . CallSlice ( [ ] reflect . Value {
reflect . ValueOf ( cli ) ,
2013-05-15 10:16:46 -04:00
reflect . ValueOf ( args [ 1 : ] ) ,
2013-05-13 05:48:27 -04:00
} ) [ 0 ] . Interface ( )
if ret == nil {
return nil
2013-04-22 12:17:47 -04:00
}
2013-05-13 05:48:27 -04:00
return ret . ( error )
2013-04-22 12:17:47 -04:00
}
2013-05-13 05:48:27 -04:00
return cli . CmdHelp ( args ... )
2013-02-13 20:10:00 -05:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdHelp ( args ... string ) error {
2013-05-23 12:32:39 -04:00
if len ( args ) > 0 {
method , exists := cli . getMethod ( args [ 0 ] )
if ! exists {
fmt . Println ( "Error: Command not found:" , args [ 0 ] )
} else {
method . Func . CallSlice ( [ ] reflect . Value {
reflect . ValueOf ( cli ) ,
reflect . ValueOf ( [ ] string { "--help" } ) ,
} ) [ 0 ] . Interface ( )
return nil
}
}
2013-05-24 17:48:13 -04:00
help := fmt . Sprintf ( "Usage: docker [OPTIONS] COMMAND [arg...]\n -H=\"%s:%d\": Host:port to bind/connect to\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n" , cli . host , cli . port )
2013-05-30 10:08:26 -04:00
for _ , command := range [ ] [ 2 ] string {
{ "attach" , "Attach to a running container" } ,
{ "build" , "Build a container from a Dockerfile" } ,
{ "commit" , "Create a new image from a container's changes" } ,
{ "diff" , "Inspect changes on a container's filesystem" } ,
{ "export" , "Stream the contents of a container as a tar archive" } ,
{ "history" , "Show the history of an image" } ,
{ "images" , "List images" } ,
{ "import" , "Create a new filesystem image from the contents of a tarball" } ,
{ "info" , "Display system-wide information" } ,
{ "insert" , "Insert a file in an image" } ,
{ "inspect" , "Return low-level information on a container" } ,
{ "kill" , "Kill a running container" } ,
{ "login" , "Register or Login to the docker registry server" } ,
{ "logs" , "Fetch the logs of a container" } ,
{ "port" , "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT" } ,
{ "ps" , "List containers" } ,
{ "pull" , "Pull an image or a repository from the docker registry server" } ,
{ "push" , "Push an image or a repository to the docker registry server" } ,
{ "restart" , "Restart a running container" } ,
{ "rm" , "Remove a container" } ,
{ "rmi" , "Remove an image" } ,
{ "run" , "Run a command in a new container" } ,
{ "search" , "Search for an image in the docker index" } ,
{ "start" , "Start a stopped container" } ,
{ "stop" , "Stop a running container" } ,
{ "tag" , "Tag an image into a repository" } ,
{ "version" , "Show the docker version information" } ,
2013-06-02 17:40:56 -04:00
{ "wait" , "Block until a container stops, then print its exit code" } ,
2013-02-13 20:10:00 -05:00
} {
2013-05-30 10:08:26 -04:00
help += fmt . Sprintf ( " %-10.10s%s\n" , command [ 0 ] , command [ 1 ] )
2013-02-13 20:10:00 -05:00
}
2013-04-22 12:17:47 -04:00
fmt . Println ( help )
return nil
2013-02-13 20:10:00 -05:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdInsert ( args ... string ) error {
2013-05-07 13:23:50 -04:00
cmd := Subcmd ( "insert" , "IMAGE URL PATH" , "Insert a file from URL in the IMAGE at PATH" )
2013-04-24 16:37:00 -04:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) != 3 {
cmd . Usage ( )
return nil
}
2013-05-07 13:23:50 -04:00
v := url . Values { }
v . Set ( "url" , cmd . Arg ( 1 ) )
v . Set ( "path" , cmd . Arg ( 2 ) )
2013-04-24 18:14:10 -04:00
2013-05-22 23:07:26 -04:00
if err := cli . stream ( "POST" , "/images/" + cmd . Arg ( 0 ) + "/insert?" + v . Encode ( ) , nil , os . Stdout ) ; err != nil {
2013-04-24 16:37:00 -04:00
return err
}
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdBuild ( args ... string ) error {
2013-05-30 15:35:19 -04:00
cmd := Subcmd ( "build" , "[OPTIONS] PATH | -" , "Build a new container image from the source code at PATH" )
tag := cmd . String ( "t" , "" , "Tag to be applied to the resulting image in case of success" )
2013-04-24 14:03:01 -04:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-05-29 21:18:57 -04:00
if cmd . NArg ( ) != 1 {
cmd . Usage ( )
return nil
}
2013-05-22 23:07:26 -04:00
2013-05-19 13:46:24 -04:00
var (
2013-05-23 21:32:56 -04:00
multipartBody io . Reader
2013-05-29 14:43:29 -04:00
file io . ReadCloser
contextPath string
2013-05-19 13:46:24 -04:00
)
2013-05-07 13:23:50 -04:00
2013-05-23 21:32:56 -04:00
// Init the needed component for the Multipart
buff := bytes . NewBuffer ( [ ] byte { } )
multipartBody = buff
2013-05-22 23:07:26 -04:00
w := multipart . NewWriter ( buff )
2013-05-23 21:32:56 -04:00
boundary := strings . NewReader ( "\r\n--" + w . Boundary ( ) + "--\r\n" )
2013-05-22 23:07:26 -04:00
2013-05-29 21:18:57 -04:00
compression := Bzip2
2013-05-29 13:51:47 -04:00
2013-05-29 21:18:57 -04:00
if cmd . Arg ( 0 ) == "-" {
2013-05-23 21:32:56 -04:00
file = os . Stdin
} else {
2013-05-29 21:18:57 -04:00
// Send Dockerfile from arg/Dockerfile (deprecate later)
2013-06-04 09:51:12 -04:00
f , err := os . Open ( path . Join ( cmd . Arg ( 0 ) , "Dockerfile" ) )
2013-05-19 13:46:24 -04:00
if err != nil {
return err
}
2013-06-04 09:51:12 -04:00
file = f
2013-05-29 21:18:57 -04:00
// Send context from arg
// Create a FormFile multipart for the context if needed
2013-05-23 21:32:56 -04:00
// FIXME: Use NewTempArchive in order to have the size and avoid too much memory usage?
2013-05-28 16:38:40 -04:00
context , err := Tar ( cmd . Arg ( 0 ) , compression )
2013-05-23 21:32:56 -04:00
if err != nil {
return err
}
2013-05-28 18:22:34 -04:00
// NOTE: Do this in case '.' or '..' is input
absPath , err := filepath . Abs ( cmd . Arg ( 0 ) )
if err != nil {
return err
}
2013-06-04 09:51:12 -04:00
wField , err := w . CreateFormFile ( "Context" , filepath . Base ( absPath ) + "." + compression . Extension ( ) )
if err != nil {
2013-05-23 21:32:56 -04:00
return err
}
2013-06-04 09:51:12 -04:00
// FIXME: Find a way to have a progressbar for the upload too
sf := utils . NewStreamFormatter ( false )
io . Copy ( wField , utils . ProgressReader ( ioutil . NopCloser ( context ) , - 1 , os . Stdout , sf . FormatProgress ( "Caching Context" , "%v/%v (%v)" ) , sf ) )
2013-05-28 18:22:34 -04:00
multipartBody = io . MultiReader ( multipartBody , boundary )
2013-05-23 21:32:56 -04:00
}
2013-05-29 21:18:57 -04:00
// Create a FormFile multipart for the Dockerfile
2013-06-04 09:51:12 -04:00
wField , err := w . CreateFormFile ( "Dockerfile" , "Dockerfile" )
if err != nil {
2013-05-29 21:18:57 -04:00
return err
}
2013-06-04 09:51:12 -04:00
io . Copy ( wField , file )
2013-05-29 21:18:57 -04:00
multipartBody = io . MultiReader ( multipartBody , boundary )
2013-05-23 21:32:56 -04:00
2013-05-30 15:08:21 -04:00
v := & url . Values { }
v . Set ( "t" , * tag )
2013-05-23 21:32:56 -04:00
// Send the multipart request with correct content-type
2013-05-30 15:08:21 -04:00
req , err := http . NewRequest ( "POST" , fmt . Sprintf ( "http://%s:%d%s?%s" , cli . host , cli . port , "/build" , v . Encode ( ) ) , multipartBody )
2013-05-23 21:32:56 -04:00
if err != nil {
2013-05-22 23:07:26 -04:00
return err
}
2013-05-23 21:32:56 -04:00
req . Header . Set ( "Content-Type" , w . FormDataContentType ( ) )
2013-05-29 14:43:29 -04:00
if contextPath != "" {
2013-05-28 16:38:40 -04:00
req . Header . Set ( "X-Docker-Context-Compression" , compression . Flag ( ) )
2013-05-28 18:22:34 -04:00
fmt . Println ( "Uploading Context..." )
2013-05-28 16:38:40 -04:00
}
2013-05-22 23:07:26 -04:00
2013-05-23 21:32:56 -04:00
resp , err := http . DefaultClient . Do ( req )
2013-05-22 23:07:26 -04:00
if err != nil {
return err
}
defer resp . Body . Close ( )
2013-05-23 21:32:56 -04:00
// Check for errors
2013-05-22 23:07:26 -04:00
if resp . StatusCode < 200 || resp . StatusCode >= 400 {
body , err := ioutil . ReadAll ( resp . Body )
2013-05-19 13:46:24 -04:00
if err != nil {
return err
}
2013-06-10 11:06:52 -04:00
if len ( body ) == 0 {
return fmt . Errorf ( "Error: %s" , http . StatusText ( resp . StatusCode ) )
}
return fmt . Errorf ( "Error: %s" , body )
2013-04-25 14:20:45 -04:00
}
2013-05-22 23:07:26 -04:00
2013-05-23 21:32:56 -04:00
// Output the result
2013-05-22 23:07:26 -04:00
if _ , err := io . Copy ( os . Stdout , resp . Body ) ; err != nil {
2013-04-25 14:20:45 -04:00
return err
}
2013-05-22 23:07:26 -04:00
2013-04-25 14:20:45 -04:00
return nil
2013-04-24 14:03:01 -04:00
}
2013-03-14 20:43:59 -04:00
// 'docker login': login / register a user to registry service.
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdLogin ( args ... string ) error {
2013-04-04 23:19:06 -04:00
var readStringOnRawTerminal = func ( stdin io . Reader , stdout io . Writer , echo bool ) string {
2013-03-28 15:11:47 -04:00
char := make ( [ ] byte , 1 )
buffer := make ( [ ] byte , 64 )
var i = 0
for i < len ( buffer ) {
n , err := stdin . Read ( char )
if n > 0 {
if char [ 0 ] == '\r' || char [ 0 ] == '\n' {
2013-04-10 22:08:46 -04:00
stdout . Write ( [ ] byte { '\r' , '\n' } )
2013-03-28 15:11:47 -04:00
break
} else if char [ 0 ] == 127 || char [ 0 ] == '\b' {
if i > 0 {
if echo {
stdout . Write ( [ ] byte { '\b' , ' ' , '\b' } )
}
i --
}
} else if ! unicode . IsSpace ( rune ( char [ 0 ] ) ) &&
! unicode . IsControl ( rune ( char [ 0 ] ) ) {
if echo {
stdout . Write ( char )
}
buffer [ i ] = char [ 0 ]
i ++
}
}
if err != nil {
if err != io . EOF {
2013-04-10 22:08:46 -04:00
fmt . Fprintf ( stdout , "Read error: %v\r\n" , err )
2013-03-28 15:11:47 -04:00
}
break
}
}
return string ( buffer [ : i ] )
}
2013-04-04 23:19:06 -04:00
var readAndEchoString = func ( stdin io . Reader , stdout io . Writer ) string {
2013-03-28 15:11:47 -04:00
return readStringOnRawTerminal ( stdin , stdout , true )
}
2013-04-04 23:19:06 -04:00
var readString = func ( stdin io . Reader , stdout io . Writer ) string {
2013-03-28 15:11:47 -04:00
return readStringOnRawTerminal ( stdin , stdout , false )
}
2013-05-14 18:37:35 -04:00
oldState , err := term . SetRawTerminal ( )
2013-05-06 07:34:31 -04:00
if err != nil {
return err
}
2013-06-04 09:51:12 -04:00
defer term . RestoreTerminal ( oldState )
2013-04-03 15:25:19 -04:00
2013-05-06 07:34:31 -04:00
cmd := Subcmd ( "login" , "" , "Register or Login to the docker registry server" )
2013-03-15 10:49:27 -04:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-03-28 15:11:47 -04:00
2013-03-14 20:43:59 -04:00
var username string
var password string
var email string
2013-05-30 11:39:43 -04:00
fmt . Print ( "Username (" , cli . authConfig . Username , "): " )
2013-05-06 07:34:31 -04:00
username = readAndEchoString ( os . Stdin , os . Stdout )
2013-03-14 20:43:59 -04:00
if username == "" {
2013-05-30 11:39:43 -04:00
username = cli . authConfig . Username
2013-03-14 20:43:59 -04:00
}
2013-05-30 11:39:43 -04:00
if username != cli . authConfig . Username {
2013-05-06 07:34:31 -04:00
fmt . Print ( "Password: " )
password = readString ( os . Stdin , os . Stdout )
2013-03-14 20:43:59 -04:00
2013-03-15 10:49:27 -04:00
if password == "" {
2013-03-29 11:19:42 -04:00
return fmt . Errorf ( "Error : Password Required" )
2013-03-15 10:49:27 -04:00
}
2013-05-30 11:39:43 -04:00
fmt . Print ( "Email (" , cli . authConfig . Email , "): " )
2013-05-06 07:34:31 -04:00
email = readAndEchoString ( os . Stdin , os . Stdout )
2013-03-14 20:43:59 -04:00
if email == "" {
2013-05-30 11:39:43 -04:00
email = cli . authConfig . Email
2013-03-14 20:43:59 -04:00
}
} else {
2013-05-30 11:39:43 -04:00
email = cli . authConfig . Email
2013-03-14 20:43:59 -04:00
}
2013-05-30 11:39:43 -04:00
term . RestoreTerminal ( oldState )
2013-05-06 07:34:31 -04:00
2013-05-30 11:39:43 -04:00
cli . authConfig . Username = username
cli . authConfig . Password = password
cli . authConfig . Email = email
2013-05-06 07:34:31 -04:00
2013-05-30 11:39:43 -04:00
body , _ , err := cli . call ( "POST" , "/auth" , cli . authConfig )
2013-03-14 20:43:59 -04:00
if err != nil {
2013-05-06 07:34:31 -04:00
return err
}
2013-06-04 14:00:22 -04:00
var out2 APIAuth
2013-05-08 17:57:14 -04:00
err = json . Unmarshal ( body , & out2 )
2013-05-06 07:34:31 -04:00
if err != nil {
2013-05-30 11:39:43 -04:00
auth . LoadConfig ( os . Getenv ( "HOME" ) )
2013-05-06 07:34:31 -04:00
return err
2013-03-14 20:43:59 -04:00
}
2013-05-30 11:39:43 -04:00
auth . SaveConfig ( cli . authConfig )
2013-05-06 07:34:31 -04:00
if out2 . Status != "" {
fmt . Print ( out2 . Status )
2013-03-14 23:21:03 -04:00
}
2013-03-14 20:43:59 -04:00
return nil
}
2013-02-26 14:43:54 -05:00
// 'docker wait': block until a container stops
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdWait ( args ... string ) error {
2013-04-24 08:01:40 -04:00
cmd := Subcmd ( "wait" , "CONTAINER [CONTAINER...]" , "Block until a container stops, then print its exit code." )
2013-02-26 14:43:54 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
for _ , name := range cmd . Args ( ) {
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "POST" , "/containers/" + name + "/wait" , nil )
2013-04-24 08:01:40 -04:00
if err != nil {
fmt . Printf ( "%s" , err )
2013-02-26 14:43:54 -05:00
} else {
2013-06-04 14:00:22 -04:00
var out APIWait
2013-04-24 08:01:40 -04:00
err = json . Unmarshal ( body , & out )
if err != nil {
return err
}
fmt . Println ( out . StatusCode )
2013-02-26 14:43:54 -05:00
}
}
return nil
}
2013-03-12 20:34:15 -04:00
// 'docker version': show version information
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdVersion ( args ... string ) error {
2013-04-22 12:17:47 -04:00
cmd := Subcmd ( "version" , "" , "Show the docker version information." )
if err := cmd . Parse ( args ) ; err != nil {
return nil
2013-04-19 00:08:33 -04:00
}
2013-05-15 10:16:46 -04:00
2013-04-22 12:17:47 -04:00
if cmd . NArg ( ) > 0 {
cmd . Usage ( )
return nil
}
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "GET" , "/version" , nil )
2013-04-22 12:17:47 -04:00
if err != nil {
return err
2013-04-11 15:58:23 -04:00
}
2013-04-22 12:17:47 -04:00
2013-06-04 14:00:22 -04:00
var out APIVersion
2013-04-22 12:17:47 -04:00
err = json . Unmarshal ( body , & out )
if err != nil {
2013-05-14 18:37:35 -04:00
utils . Debugf ( "Error unmarshal: body: %s, err: %s\n" , body , err )
2013-04-22 12:17:47 -04:00
return err
}
2013-05-31 18:53:57 -04:00
fmt . Println ( "Client version:" , VERSION )
fmt . Println ( "Server version:" , out . Version )
if out . GitCommit != "" {
fmt . Println ( "Git commit:" , out . GitCommit )
2013-05-02 12:36:23 -04:00
}
2013-05-31 18:53:57 -04:00
if out . GoVersion != "" {
fmt . Println ( "Go version:" , out . GoVersion )
2013-04-11 15:58:23 -04:00
}
2013-03-12 20:34:15 -04:00
return nil
}
2013-02-13 20:10:00 -05:00
// 'docker info': display system-wide information.
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdInfo ( args ... string ) error {
2013-04-22 12:17:47 -04:00
cmd := Subcmd ( "info" , "" , "Display system-wide information" )
2013-03-11 19:11:46 -04:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-03-12 11:59:32 -04:00
if cmd . NArg ( ) > 0 {
2013-03-11 19:11:46 -04:00
cmd . Usage ( )
return nil
2013-03-12 07:24:26 -04:00
}
2013-03-30 13:33:10 -04:00
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "GET" , "/info" , nil )
2013-04-22 12:17:47 -04:00
if err != nil {
return err
2013-03-30 13:33:10 -04:00
}
2013-05-08 19:40:48 -04:00
2013-06-04 14:00:22 -04:00
var out APIInfo
2013-05-31 18:53:57 -04:00
if err := json . Unmarshal ( body , & out ) ; err != nil {
2013-04-22 12:17:47 -04:00
return err
}
2013-05-31 18:53:57 -04:00
fmt . Printf ( "Containers: %d\n" , out . Containers )
fmt . Printf ( "Images: %d\n" , out . Images )
if out . Debug || os . Getenv ( "DEBUG" ) != "" {
fmt . Printf ( "Debug mode (server): %v\n" , out . Debug )
fmt . Printf ( "Debug mode (client): %v\n" , os . Getenv ( "DEBUG" ) != "" )
fmt . Printf ( "Fds: %d\n" , out . NFd )
fmt . Printf ( "Goroutines: %d\n" , out . NGoroutines )
}
if ! out . MemoryLimit {
fmt . Println ( "WARNING: No memory limit support" )
}
if ! out . SwapLimit {
fmt . Println ( "WARNING: No swap limit support" )
2013-03-30 13:33:10 -04:00
}
2013-02-13 20:10:00 -05:00
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdStop ( args ... string ) error {
2013-05-02 12:36:23 -04:00
cmd := Subcmd ( "stop" , "[OPTIONS] CONTAINER [CONTAINER...]" , "Stop a running container" )
2013-04-16 12:43:44 -04:00
nSeconds := cmd . Int ( "t" , 10 , "wait t seconds before killing the container" )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
2013-04-22 12:17:47 -04:00
2013-05-02 12:36:23 -04:00
v := url . Values { }
v . Set ( "t" , strconv . Itoa ( * nSeconds ) )
2013-02-13 20:10:00 -05:00
for _ , name := range cmd . Args ( ) {
2013-05-13 05:48:27 -04:00
_ , _ , err := cli . call ( "POST" , "/containers/" + name + "/stop?" + v . Encode ( ) , nil )
2013-04-22 12:17:47 -04:00
if err != nil {
2013-06-06 11:45:08 -04:00
fmt . Fprintf ( os . Stderr , "%s" , err )
2013-02-13 20:10:00 -05:00
} else {
2013-04-22 12:17:47 -04:00
fmt . Println ( name )
2013-02-14 16:49:05 -05:00
}
}
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdRestart ( args ... string ) error {
2013-05-02 12:36:23 -04:00
cmd := Subcmd ( "restart" , "[OPTIONS] CONTAINER [CONTAINER...]" , "Restart a running container" )
2013-04-16 12:43:44 -04:00
nSeconds := cmd . Int ( "t" , 10 , "wait t seconds before killing the container" )
2013-02-14 16:49:05 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
2013-04-22 12:17:47 -04:00
2013-05-02 12:36:23 -04:00
v := url . Values { }
v . Set ( "t" , strconv . Itoa ( * nSeconds ) )
2013-02-14 16:49:05 -05:00
for _ , name := range cmd . Args ( ) {
2013-05-13 05:48:27 -04:00
_ , _ , err := cli . call ( "POST" , "/containers/" + name + "/restart?" + v . Encode ( ) , nil )
2013-04-22 12:17:47 -04:00
if err != nil {
2013-06-06 11:45:08 -04:00
fmt . Fprintf ( os . Stderr , "%s" , err )
2013-02-14 16:49:05 -05:00
} else {
2013-04-22 12:17:47 -04:00
fmt . Println ( name )
2013-02-14 16:49:05 -05:00
}
}
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdStart ( args ... string ) error {
2013-04-22 12:17:47 -04:00
cmd := Subcmd ( "start" , "CONTAINER [CONTAINER...]" , "Restart a stopped container" )
2013-02-14 16:49:05 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
2013-04-22 12:17:47 -04:00
for _ , name := range args {
2013-05-13 05:48:27 -04:00
_ , _ , err := cli . call ( "POST" , "/containers/" + name + "/start" , nil )
2013-04-22 12:17:47 -04:00
if err != nil {
2013-06-06 11:45:08 -04:00
fmt . Fprintf ( os . Stderr , "%s" , err )
2013-02-14 16:49:05 -05:00
} else {
2013-04-22 12:17:47 -04:00
fmt . Println ( name )
2013-02-13 20:10:00 -05:00
}
}
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdInspect ( args ... string ) error {
2013-06-06 11:22:54 -04:00
cmd := Subcmd ( "inspect" , "CONTAINER|IMAGE [CONTAINER|IMAGE...]" , "Return low-level information on a container/image" )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-06-06 11:22:54 -04:00
if cmd . NArg ( ) < 1 {
2013-02-13 20:10:00 -05:00
cmd . Usage ( )
return nil
}
2013-06-06 11:45:08 -04:00
fmt . Printf ( "[" )
for i , name := range args {
if i > 0 {
fmt . Printf ( "," )
}
2013-06-06 11:22:54 -04:00
obj , _ , err := cli . call ( "GET" , "/containers/" + name + "/json" , nil )
2013-04-24 08:01:40 -04:00
if err != nil {
2013-06-06 11:22:54 -04:00
obj , _ , err = cli . call ( "GET" , "/images/" + name + "/json" , nil )
if err != nil {
2013-06-06 11:45:08 -04:00
fmt . Fprintf ( os . Stderr , "%s" , err )
2013-06-06 11:22:54 -04:00
continue
}
2013-04-24 08:01:40 -04:00
}
2013-05-08 21:46:39 -04:00
2013-06-06 11:22:54 -04:00
indented := new ( bytes . Buffer )
if err = json . Indent ( indented , obj , "" , " " ) ; err != nil {
2013-06-06 11:45:08 -04:00
fmt . Fprintf ( os . Stderr , "%s" , err )
2013-06-06 11:22:54 -04:00
continue
}
if _ , err := io . Copy ( os . Stdout , indented ) ; err != nil {
2013-06-06 11:45:08 -04:00
fmt . Fprintf ( os . Stderr , "%s" , err )
2013-06-06 11:22:54 -04:00
}
2013-02-13 20:10:00 -05:00
}
2013-06-06 11:45:08 -04:00
fmt . Printf ( "]" )
2013-02-13 20:10:00 -05:00
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdPort ( args ... string ) error {
2013-04-23 12:20:53 -04:00
cmd := Subcmd ( "port" , "CONTAINER PRIVATE_PORT" , "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT" )
2013-03-06 03:39:03 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) != 2 {
cmd . Usage ( )
return nil
}
2013-05-08 12:06:43 -04:00
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "GET" , "/containers/" + cmd . Arg ( 0 ) + "/json" , nil )
2013-04-23 12:20:53 -04:00
if err != nil {
return err
}
2013-05-08 12:06:43 -04:00
var out Container
2013-04-23 12:20:53 -04:00
err = json . Unmarshal ( body , & out )
if err != nil {
return err
2013-03-06 03:39:03 -05:00
}
2013-05-08 12:06:43 -04:00
if frontend , exists := out . NetworkSettings . PortMapping [ cmd . Arg ( 1 ) ] ; exists {
fmt . Println ( frontend )
2013-03-06 03:39:03 -05:00
} else {
2013-06-10 11:06:52 -04:00
return fmt . Errorf ( "Error: No private port '%s' allocated on %s" , cmd . Arg ( 1 ) , cmd . Arg ( 0 ) )
2013-03-06 03:39:03 -05:00
}
return nil
}
2013-04-11 12:46:47 -04:00
// 'docker rmi IMAGE' removes all images with the name IMAGE
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdRmi ( args ... string ) error {
2013-04-22 12:17:47 -04:00
cmd := Subcmd ( "rmi" , "IMAGE [IMAGE...]" , "Remove an image" )
2013-03-25 21:35:31 -04:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
2013-03-13 14:14:37 -04:00
cmd . Usage ( )
return nil
}
2013-04-22 12:17:47 -04:00
2013-03-13 14:14:37 -04:00
for _ , name := range cmd . Args ( ) {
2013-05-31 10:37:02 -04:00
body , _ , err := cli . call ( "DELETE" , "/images/" + name , nil )
2013-04-10 20:23:42 -04:00
if err != nil {
2013-05-31 10:37:02 -04:00
fmt . Fprintf ( os . Stderr , "%s" , err )
2013-04-22 12:17:47 -04:00
} else {
2013-06-10 17:05:54 -04:00
var outs [ ] APIRmi
2013-05-31 10:37:02 -04:00
err = json . Unmarshal ( body , & outs )
if err != nil {
return err
}
for _ , out := range outs {
if out . Deleted != "" {
fmt . Println ( "Deleted:" , out . Deleted )
} else {
fmt . Println ( "Untagged:" , out . Untagged )
}
}
2013-03-13 14:14:37 -04:00
}
}
return nil
}
2013-02-13 20:10:00 -05:00
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdHistory ( args ... string ) error {
2013-04-22 12:17:47 -04:00
cmd := Subcmd ( "history" , "IMAGE" , "Show the history of an image" )
2013-03-25 21:33:56 -04:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) != 1 {
2013-03-22 00:42:18 -04:00
cmd . Usage ( )
return nil
}
2013-04-22 12:17:47 -04:00
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "GET" , "/images/" + cmd . Arg ( 0 ) + "/history" , nil )
2013-03-22 00:42:18 -04:00
if err != nil {
return err
}
2013-04-22 12:17:47 -04:00
2013-06-04 14:00:22 -04:00
var outs [ ] APIHistory
2013-04-22 12:17:47 -04:00
err = json . Unmarshal ( body , & outs )
2013-03-22 00:42:18 -04:00
if err != nil {
return err
}
2013-04-22 12:17:47 -04:00
w := tabwriter . NewWriter ( os . Stdout , 20 , 1 , 3 , ' ' , 0 )
2013-03-30 03:23:12 -04:00
fmt . Fprintln ( w , "ID\tCREATED\tCREATED BY" )
2013-04-22 12:17:47 -04:00
for _ , out := range outs {
2013-06-18 13:31:07 -04:00
if out . Tags != nil {
out . ID = out . Tags [ 0 ]
}
fmt . Fprintf ( w , "%s \t%s ago\t%s\n" , out . ID , utils . HumanDuration ( time . Now ( ) . Sub ( time . Unix ( out . Created , 0 ) ) ) , out . CreatedBy )
2013-04-22 12:17:47 -04:00
}
w . Flush ( )
return nil
2013-03-22 00:42:18 -04:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdRm ( args ... string ) error {
2013-05-06 05:52:15 -04:00
cmd := Subcmd ( "rm" , "[OPTIONS] CONTAINER [CONTAINER...]" , "Remove a container" )
2013-04-12 12:23:57 -04:00
v := cmd . Bool ( "v" , false , "Remove the volumes associated to the container" )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-11 10:27:01 -04:00
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
2013-05-06 05:52:15 -04:00
val := url . Values { }
2013-04-12 12:23:57 -04:00
if * v {
2013-05-06 05:52:15 -04:00
val . Set ( "v" , "1" )
}
for _ , name := range cmd . Args ( ) {
2013-05-13 05:48:27 -04:00
_ , _ , err := cli . call ( "DELETE" , "/containers/" + name + "?" + val . Encode ( ) , nil )
2013-04-22 12:17:47 -04:00
if err != nil {
fmt . Printf ( "%s" , err )
} else {
fmt . Println ( name )
2013-04-12 12:23:57 -04:00
}
}
2013-02-13 20:10:00 -05:00
return nil
}
// 'docker kill NAME' kills a running container
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdKill ( args ... string ) error {
2013-04-22 12:17:47 -04:00
cmd := Subcmd ( "kill" , "CONTAINER [CONTAINER...]" , "Kill a running container" )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-12 06:26:31 -04:00
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
2013-04-22 12:17:47 -04:00
for _ , name := range args {
2013-05-13 05:48:27 -04:00
_ , _ , err := cli . call ( "POST" , "/containers/" + name + "/kill" , nil )
2013-04-22 12:17:47 -04:00
if err != nil {
fmt . Printf ( "%s" , err )
} else {
fmt . Println ( name )
2013-02-13 20:10:00 -05:00
}
}
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdImport ( args ... string ) error {
2013-04-30 11:04:31 -04:00
cmd := Subcmd ( "import" , "URL|- [REPOSITORY [TAG]]" , "Create a new filesystem image from the contents of a tarball" )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-12 06:26:31 -04:00
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
2013-04-30 11:04:31 -04:00
src , repository , tag := cmd . Arg ( 0 ) , cmd . Arg ( 1 ) , cmd . Arg ( 2 )
v := url . Values { }
v . Set ( "repo" , repository )
v . Set ( "tag" , tag )
2013-05-06 05:31:22 -04:00
v . Set ( "fromSrc" , src )
2013-04-30 11:04:31 -04:00
2013-05-16 15:09:06 -04:00
err := cli . stream ( "POST" , "/images/create?" + v . Encode ( ) , os . Stdin , os . Stdout )
2013-02-13 20:10:00 -05:00
if err != nil {
return err
}
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdPush ( args ... string ) error {
2013-05-07 13:23:50 -04:00
cmd := Subcmd ( "push" , "[OPTION] NAME" , "Push an image or a repository to the registry" )
2013-04-23 15:02:16 -04:00
registry := cmd . String ( "registry" , "" , "Registry host to push the image to" )
2013-03-21 06:53:27 -04:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-05-06 07:34:31 -04:00
name := cmd . Arg ( 0 )
2013-03-22 09:38:54 -04:00
2013-05-06 07:34:31 -04:00
if name == "" {
2013-03-21 06:53:27 -04:00
cmd . Usage ( )
return nil
}
2013-05-30 11:39:43 -04:00
if err := cli . checkIfLogged ( * registry == "" , "push" ) ; err != nil {
2013-05-06 07:34:31 -04:00
return err
}
if len ( strings . SplitN ( name , "/" , 2 ) ) == 1 {
2013-05-30 11:39:43 -04:00
return fmt . Errorf ( "Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)" , cli . authConfig . Username , name )
2013-03-22 09:38:54 -04:00
}
2013-06-03 13:51:52 -04:00
buf , err := json . Marshal ( cli . authConfig )
if err != nil {
return err
2013-03-22 09:38:54 -04:00
}
2013-06-03 10:23:57 -04:00
nameParts := strings . SplitN ( name , "/" , 2 )
validNamespace := regexp . MustCompile ( ` ^([a-z0-9_] { 4,30})$ ` )
if ! validNamespace . MatchString ( nameParts [ 0 ] ) {
return fmt . Errorf ( "Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30" , nameParts [ 0 ] )
}
validRepo := regexp . MustCompile ( ` ^([a-zA-Z0-9-_.]+)$ ` )
if ! validRepo . MatchString ( nameParts [ 1 ] ) {
return fmt . Errorf ( "Invalid repository name (%s), only [a-zA-Z0-9-_.] are allowed" , nameParts [ 1 ] )
2013-05-21 08:53:05 -04:00
}
2013-03-22 09:38:54 -04:00
2013-05-07 13:23:50 -04:00
v := url . Values { }
v . Set ( "registry" , * registry )
2013-06-03 13:51:52 -04:00
if err := cli . stream ( "POST" , "/images/" + name + "/push?" + v . Encode ( ) , bytes . NewBuffer ( buf ) , os . Stdout ) ; err != nil {
2013-03-22 06:10:09 -04:00
return err
}
return nil
2013-03-21 06:53:27 -04:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdPull ( args ... string ) error {
2013-04-23 12:20:53 -04:00
cmd := Subcmd ( "pull" , "NAME" , "Pull an image or a repository from the registry" )
2013-04-15 14:17:03 -04:00
tag := cmd . String ( "t" , "" , "Download tagged image in repository" )
registry := cmd . String ( "registry" , "" , "Registry to download from. Necessary if image is pulled by ID" )
2013-03-21 06:53:27 -04:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-23 12:20:53 -04:00
if cmd . NArg ( ) != 1 {
2013-03-21 06:53:27 -04:00
cmd . Usage ( )
return nil
}
2013-03-22 04:25:27 -04:00
2013-05-07 13:23:50 -04:00
remote := cmd . Arg ( 0 )
2013-04-30 09:55:24 -04:00
if strings . Contains ( remote , ":" ) {
remoteParts := strings . Split ( remote , ":" )
tag = & remoteParts [ 1 ]
remote = remoteParts [ 0 ]
}
2013-05-06 05:31:22 -04:00
v := url . Values { }
2013-05-07 13:23:50 -04:00
v . Set ( "fromImage" , remote )
v . Set ( "tag" , * tag )
v . Set ( "registry" , * registry )
2013-03-22 04:25:27 -04:00
2013-05-16 15:09:06 -04:00
if err := cli . stream ( "POST" , "/images/create?" + v . Encode ( ) , nil , os . Stdout ) ; err != nil {
2013-03-22 06:10:09 -04:00
return err
}
2013-04-23 12:20:53 -04:00
2013-03-22 06:10:09 -04:00
return nil
2013-03-21 06:53:27 -04:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdImages ( args ... string ) error {
2013-04-22 12:17:47 -04:00
cmd := Subcmd ( "images" , "[OPTIONS] [NAME]" , "List images" )
2013-02-13 20:10:00 -05:00
quiet := cmd . Bool ( "q" , false , "only show numeric IDs" )
2013-04-22 12:17:47 -04:00
all := cmd . Bool ( "a" , false , "show all images" )
2013-05-13 06:26:18 -04:00
noTrunc := cmd . Bool ( "notrunc" , false , "Don't truncate output" )
2013-05-01 01:39:48 -04:00
flViz := cmd . Bool ( "viz" , false , "output graph in graphviz format" )
2013-04-23 12:20:53 -04:00
2013-03-11 18:08:22 -04:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-02-13 20:10:00 -05:00
if cmd . NArg ( ) > 1 {
cmd . Usage ( )
return nil
}
2013-05-01 01:39:48 -04:00
if * flViz {
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "GET" , "/images/viz" , false )
2013-05-09 17:10:26 -04:00
if err != nil {
2013-05-07 13:23:50 -04:00
return err
2013-05-01 01:39:48 -04:00
}
2013-05-09 17:10:26 -04:00
fmt . Printf ( "%s" , body )
2013-05-01 01:39:48 -04:00
} else {
2013-05-07 13:23:50 -04:00
v := url . Values { }
2013-05-01 01:39:48 -04:00
if cmd . NArg ( ) == 1 {
2013-05-07 13:23:50 -04:00
v . Set ( "filter" , cmd . Arg ( 0 ) )
2013-05-01 01:39:48 -04:00
}
2013-05-07 13:23:50 -04:00
if * all {
v . Set ( "all" , "1" )
2013-05-01 01:39:48 -04:00
}
2013-04-22 12:17:47 -04:00
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "GET" , "/images/json?" + v . Encode ( ) , nil )
2013-05-01 01:39:48 -04:00
if err != nil {
return err
}
2013-04-22 12:17:47 -04:00
2013-06-04 14:00:22 -04:00
var outs [ ] APIImages
2013-05-07 13:23:50 -04:00
err = json . Unmarshal ( body , & outs )
if err != nil {
return err
2013-02-13 20:10:00 -05:00
}
2013-05-07 13:23:50 -04:00
w := tabwriter . NewWriter ( os . Stdout , 20 , 1 , 3 , ' ' , 0 )
2013-04-22 12:17:47 -04:00
if ! * quiet {
2013-05-13 09:10:26 -04:00
fmt . Fprintln ( w , "REPOSITORY\tTAG\tID\tCREATED\tSIZE" )
2013-03-21 20:35:49 -04:00
}
2013-04-22 12:17:47 -04:00
2013-05-07 13:23:50 -04:00
for _ , out := range outs {
2013-05-13 06:18:55 -04:00
if out . Repository == "" {
out . Repository = "<none>"
}
if out . Tag == "" {
out . Tag = "<none>"
}
2013-05-07 13:23:50 -04:00
if ! * quiet {
2013-05-13 06:26:18 -04:00
fmt . Fprintf ( w , "%s\t%s\t" , out . Repository , out . Tag )
if * noTrunc {
2013-06-04 14:00:22 -04:00
fmt . Fprintf ( w , "%s\t" , out . ID )
2013-05-13 06:26:18 -04:00
} else {
2013-06-04 14:00:22 -04:00
fmt . Fprintf ( w , "%s\t" , utils . TruncateID ( out . ID ) )
2013-05-13 06:26:18 -04:00
}
2013-05-22 09:41:29 -04:00
fmt . Fprintf ( w , "%s ago\t" , utils . HumanDuration ( time . Now ( ) . Sub ( time . Unix ( out . Created , 0 ) ) ) )
2013-06-14 06:05:01 -04:00
if out . VirtualSize > 0 {
fmt . Fprintf ( w , "%s (virtual %s)\n" , utils . HumanSize ( out . Size ) , utils . HumanSize ( out . VirtualSize ) )
2013-05-22 09:41:29 -04:00
} else {
fmt . Fprintf ( w , "%s\n" , utils . HumanSize ( out . Size ) )
}
2013-05-07 13:23:50 -04:00
} else {
2013-05-13 06:26:18 -04:00
if * noTrunc {
2013-06-04 14:00:22 -04:00
fmt . Fprintln ( w , out . ID )
2013-05-13 06:26:18 -04:00
} else {
2013-06-04 14:00:22 -04:00
fmt . Fprintln ( w , utils . TruncateID ( out . ID ) )
2013-05-13 06:26:18 -04:00
}
2013-03-21 20:35:49 -04:00
}
}
2013-05-07 13:23:50 -04:00
2013-05-01 01:39:48 -04:00
if ! * quiet {
w . Flush ( )
}
2013-02-13 20:10:00 -05:00
}
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdPs ( args ... string ) error {
2013-04-22 12:17:47 -04:00
cmd := Subcmd ( "ps" , "[OPTIONS]" , "List containers" )
2013-02-13 20:10:00 -05:00
quiet := cmd . Bool ( "q" , false , "Only display numeric IDs" )
2013-04-22 12:17:47 -04:00
all := cmd . Bool ( "a" , false , "Show all containers. Only running containers are shown by default." )
noTrunc := cmd . Bool ( "notrunc" , false , "Don't truncate output" )
nLatest := cmd . Bool ( "l" , false , "Show only the latest created container, include non-running ones." )
2013-05-08 12:28:11 -04:00
since := cmd . String ( "sinceId" , "" , "Show only containers created since Id, include non-running ones." )
before := cmd . String ( "beforeId" , "" , "Show only container created before Id, include non-running ones." )
2013-04-22 12:17:47 -04:00
last := cmd . Int ( "n" , - 1 , "Show n last created containers, include non-running ones." )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-22 12:17:47 -04:00
v := url . Values { }
if * last == - 1 && * nLatest {
* last = 1
}
if * all {
2013-04-26 09:08:33 -04:00
v . Set ( "all" , "1" )
2013-04-22 12:17:47 -04:00
}
if * last != - 1 {
2013-05-08 11:35:50 -04:00
v . Set ( "limit" , strconv . Itoa ( * last ) )
2013-04-22 12:17:47 -04:00
}
2013-05-08 12:28:11 -04:00
if * since != "" {
v . Set ( "since" , * since )
}
if * before != "" {
v . Set ( "before" , * before )
}
2013-04-23 12:20:53 -04:00
2013-05-28 12:08:05 -04:00
body , _ , err := cli . call ( "GET" , "/containers/json?" + v . Encode ( ) , nil )
2013-04-22 12:17:47 -04:00
if err != nil {
return err
}
2013-06-04 14:00:22 -04:00
var outs [ ] APIContainers
2013-04-22 12:17:47 -04:00
err = json . Unmarshal ( body , & outs )
if err != nil {
return err
2013-04-10 13:30:57 -04:00
}
2013-04-22 12:17:47 -04:00
w := tabwriter . NewWriter ( os . Stdout , 20 , 1 , 3 , ' ' , 0 )
2013-02-13 20:28:13 -05:00
if ! * quiet {
2013-05-13 09:10:26 -04:00
fmt . Fprintln ( w , "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tSIZE" )
2013-02-13 20:10:00 -05:00
}
2013-04-22 12:17:47 -04:00
for _ , out := range outs {
2013-02-13 20:10:00 -05:00
if ! * quiet {
2013-05-13 06:18:55 -04:00
if * noTrunc {
2013-06-05 12:01:36 -04:00
fmt . Fprintf ( w , "%s\t%s\t%s\t%s ago\t%s\t%s\t" , out . ID , out . Image , out . Command , utils . HumanDuration ( time . Now ( ) . Sub ( time . Unix ( out . Created , 0 ) ) ) , out . Status , out . Ports )
2013-05-22 09:41:29 -04:00
} else {
2013-06-05 12:01:36 -04:00
fmt . Fprintf ( w , "%s\t%s\t%s\t%s ago\t%s\t%s\t" , utils . TruncateID ( out . ID ) , out . Image , utils . Trunc ( out . Command , 20 ) , utils . HumanDuration ( time . Now ( ) . Sub ( time . Unix ( out . Created , 0 ) ) ) , out . Status , out . Ports )
2013-05-22 09:41:29 -04:00
}
2013-05-13 09:10:26 -04:00
if out . SizeRootFs > 0 {
2013-05-22 09:41:29 -04:00
fmt . Fprintf ( w , "%s (virtual %s)\n" , utils . HumanSize ( out . SizeRw ) , utils . HumanSize ( out . SizeRootFs ) )
2013-05-13 09:10:26 -04:00
} else {
2013-05-22 09:41:29 -04:00
fmt . Fprintf ( w , "%s\n" , utils . HumanSize ( out . SizeRw ) )
2013-05-13 09:10:26 -04:00
}
2013-02-13 20:10:00 -05:00
} else {
2013-05-13 06:18:55 -04:00
if * noTrunc {
2013-06-04 14:00:22 -04:00
fmt . Fprintln ( w , out . ID )
2013-05-13 06:18:55 -04:00
} else {
2013-06-04 14:00:22 -04:00
fmt . Fprintln ( w , utils . TruncateID ( out . ID ) )
2013-05-13 06:18:55 -04:00
}
2013-02-13 20:10:00 -05:00
}
}
2013-04-22 12:17:47 -04:00
2013-02-13 20:28:13 -05:00
if ! * quiet {
2013-02-13 20:10:00 -05:00
w . Flush ( )
}
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdCommit ( args ... string ) error {
2013-04-24 10:06:03 -04:00
cmd := Subcmd ( "commit" , "[OPTIONS] CONTAINER [REPOSITORY [TAG]]" , "Create a new image from a container's changes" )
2013-03-28 20:12:23 -04:00
flComment := cmd . String ( "m" , "" , "Commit message" )
2013-04-17 23:13:11 -04:00
flAuthor := cmd . String ( "author" , "" , "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"" )
2013-05-01 15:45:45 -04:00
flConfig := cmd . String ( "run" , "" , "Config automatically applied when the image is run. " + ` (ex: { "Cmd": ["cat", "/world"], "PortSpecs": ["22"]}') ` )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-24 10:06:03 -04:00
name , repository , tag := cmd . Arg ( 0 ) , cmd . Arg ( 1 ) , cmd . Arg ( 2 )
if name == "" {
2013-02-13 20:10:00 -05:00
cmd . Usage ( )
return nil
}
2013-04-25 19:48:31 -04:00
2013-04-24 10:06:03 -04:00
v := url . Values { }
2013-05-07 11:19:41 -04:00
v . Set ( "container" , name )
2013-04-24 10:06:03 -04:00
v . Set ( "repo" , repository )
v . Set ( "tag" , tag )
v . Set ( "comment" , * flComment )
2013-05-02 12:36:23 -04:00
v . Set ( "author" , * flAuthor )
2013-05-01 18:19:55 -04:00
var config * Config
2013-04-25 19:48:31 -04:00
if * flConfig != "" {
2013-05-01 18:19:55 -04:00
config = & Config { }
2013-04-26 13:48:33 -04:00
if err := json . Unmarshal ( [ ] byte ( * flConfig ) , config ) ; err != nil {
return err
}
2013-04-25 19:48:31 -04:00
}
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "POST" , "/commit?" + v . Encode ( ) , config )
2013-03-21 23:07:37 -04:00
if err != nil {
return err
2013-04-24 18:24:14 -04:00
}
2013-06-04 14:00:22 -04:00
apiID := & APIID { }
err = json . Unmarshal ( body , apiID )
2013-03-21 23:07:37 -04:00
if err != nil {
return err
2013-02-13 20:10:00 -05:00
}
2013-04-24 10:06:03 -04:00
2013-06-04 14:00:22 -04:00
fmt . Println ( apiID . ID )
2013-03-21 23:07:37 -04:00
return nil
2013-02-13 20:10:00 -05:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdExport ( args ... string ) error {
2013-04-24 10:32:51 -04:00
cmd := Subcmd ( "export" , "CONTAINER" , "Export the contents of a filesystem as a tar archive" )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-24 10:32:51 -04:00
if cmd . NArg ( ) != 1 {
cmd . Usage ( )
2013-02-13 20:10:00 -05:00
return nil
}
2013-04-24 10:32:51 -04:00
2013-05-16 15:09:06 -04:00
if err := cli . stream ( "GET" , "/containers/" + cmd . Arg ( 0 ) + "/export" , nil , os . Stdout ) ; err != nil {
2013-04-24 10:32:51 -04:00
return err
}
return nil
2013-02-13 20:10:00 -05:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdDiff ( args ... string ) error {
2013-04-24 08:01:40 -04:00
cmd := Subcmd ( "diff" , "CONTAINER" , "Inspect changes on a container's filesystem" )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-24 08:01:40 -04:00
if cmd . NArg ( ) != 1 {
2013-04-12 06:26:31 -04:00
cmd . Usage ( )
return nil
2013-02-13 20:10:00 -05:00
}
2013-04-24 08:01:40 -04:00
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "GET" , "/containers/" + cmd . Arg ( 0 ) + "/changes" , nil )
2013-04-24 08:01:40 -04:00
if err != nil {
return err
}
2013-05-10 00:53:28 -04:00
changes := [ ] Change { }
2013-04-24 08:01:40 -04:00
err = json . Unmarshal ( body , & changes )
if err != nil {
return err
}
for _ , change := range changes {
2013-05-08 11:35:50 -04:00
fmt . Println ( change . String ( ) )
2013-02-13 20:10:00 -05:00
}
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdLogs ( args ... string ) error {
2013-04-22 12:17:47 -04:00
cmd := Subcmd ( "logs" , "CONTAINER" , "Fetch the logs of a container" )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) != 1 {
cmd . Usage ( )
return nil
}
2013-04-22 12:17:47 -04:00
2013-05-27 12:07:05 -04:00
if err := cli . stream ( "POST" , "/containers/" + cmd . Arg ( 0 ) + "/attach?logs=1&stdout=1" , nil , os . Stdout ) ; err != nil {
return err
}
if err := cli . stream ( "POST" , "/containers/" + cmd . Arg ( 0 ) + "/attach?logs=1&stderr=1" , nil , os . Stderr ) ; err != nil {
2013-04-22 12:17:47 -04:00
return err
2013-02-13 20:10:00 -05:00
}
2013-04-22 12:17:47 -04:00
return nil
2013-02-13 20:10:00 -05:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdAttach ( args ... string ) error {
2013-04-26 09:08:33 -04:00
cmd := Subcmd ( "attach" , "CONTAINER" , "Attach to a running container" )
2013-02-13 20:10:00 -05:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) != 1 {
cmd . Usage ( )
return nil
}
2013-04-02 15:18:20 -04:00
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "GET" , "/containers/" + cmd . Arg ( 0 ) + "/json" , nil )
2013-04-29 11:46:41 -04:00
if err != nil {
return err
2013-02-13 20:10:00 -05:00
}
2013-04-02 15:18:20 -04:00
2013-05-10 00:53:28 -04:00
container := & Container { }
err = json . Unmarshal ( body , container )
2013-04-29 11:46:41 -04:00
if err != nil {
return err
2013-04-19 17:18:03 -04:00
}
2013-05-29 10:14:51 -04:00
splitStderr := container . Config . Tty
2013-05-29 07:40:54 -04:00
connections := 1
2013-05-29 10:14:51 -04:00
if splitStderr {
2013-05-29 07:40:54 -04:00
connections += 1
}
2013-05-29 10:14:51 -04:00
chErrors := make ( chan error , connections )
2013-06-13 15:57:35 -04:00
if container . Config . Tty {
cli . monitorTtySize ( cmd . Arg ( 0 ) )
}
2013-05-29 10:14:51 -04:00
if splitStderr {
2013-05-29 07:40:54 -04:00
go func ( ) {
2013-05-29 10:14:51 -04:00
chErrors <- cli . hijack ( "POST" , "/containers/" + cmd . Arg ( 0 ) + "/attach?stream=1&stderr=1" , false , nil , os . Stderr )
2013-05-29 07:40:54 -04:00
} ( )
}
2013-05-01 23:07:06 -04:00
v := url . Values { }
v . Set ( "stream" , "1" )
v . Set ( "stdin" , "1" )
2013-05-29 07:40:54 -04:00
v . Set ( "stdout" , "1" )
2013-05-29 10:14:51 -04:00
if ! splitStderr {
2013-05-29 07:40:54 -04:00
v . Set ( "stderr" , "1" )
}
go func ( ) {
2013-05-29 10:14:51 -04:00
chErrors <- cli . hijack ( "POST" , "/containers/" + cmd . Arg ( 0 ) + "/attach?" + v . Encode ( ) , container . Config . Tty , os . Stdin , os . Stdout )
2013-05-29 07:40:54 -04:00
} ( )
for connections > 0 {
2013-05-29 10:14:51 -04:00
err := <- chErrors
2013-05-29 07:40:54 -04:00
if err != nil {
return err
}
connections -= 1
2013-04-05 00:51:40 -04:00
}
2013-04-26 09:08:33 -04:00
return nil
2013-02-13 20:10:00 -05:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdSearch ( args ... string ) error {
2013-05-07 14:37:35 -04:00
cmd := Subcmd ( "search" , "NAME" , "Search the docker index for images" )
2013-05-07 06:49:08 -04:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) != 1 {
cmd . Usage ( )
return nil
}
2013-05-07 14:59:04 -04:00
2013-05-07 14:37:35 -04:00
v := url . Values { }
2013-05-07 14:59:04 -04:00
v . Set ( "term" , cmd . Arg ( 0 ) )
2013-05-13 05:48:27 -04:00
body , _ , err := cli . call ( "GET" , "/images/search?" + v . Encode ( ) , nil )
2013-05-07 14:59:04 -04:00
if err != nil {
return err
}
2013-06-04 14:00:22 -04:00
outs := [ ] APISearch { }
2013-05-07 14:59:04 -04:00
err = json . Unmarshal ( body , & outs )
2013-05-07 06:49:08 -04:00
if err != nil {
return err
}
2013-05-07 14:37:35 -04:00
fmt . Printf ( "Found %d results matching your query (\"%s\")\n" , len ( outs ) , cmd . Arg ( 0 ) )
w := tabwriter . NewWriter ( os . Stdout , 20 , 1 , 3 , ' ' , 0 )
2013-05-07 06:49:08 -04:00
fmt . Fprintf ( w , "NAME\tDESCRIPTION\n" )
2013-05-07 14:37:35 -04:00
for _ , out := range outs {
2013-06-07 09:09:24 -04:00
desc := strings . Replace ( out . Description , "\n" , " " , - 1 )
desc = strings . Replace ( desc , "\r" , " " , - 1 )
if len ( desc ) > 45 {
desc = utils . Trunc ( desc , 42 ) + "..."
}
fmt . Fprintf ( w , "%s\t%s\n" , out . Name , desc )
2013-05-07 06:49:08 -04:00
}
w . Flush ( )
return nil
}
2013-02-28 14:52:22 -05:00
// Ports type - Used to parse multiple -p flags
type ports [ ] int
2013-03-22 23:36:34 -04:00
// ListOpts type
type ListOpts [ ] string
func ( opts * ListOpts ) String ( ) string {
return fmt . Sprint ( * opts )
}
func ( opts * ListOpts ) Set ( value string ) error {
* opts = append ( * opts , value )
return nil
}
2013-04-02 21:07:16 -04:00
// AttachOpts stores arguments to 'docker run -a', eg. which streams to attach to
type AttachOpts map [ string ] bool
2013-04-03 10:06:35 -04:00
func NewAttachOpts ( ) AttachOpts {
return make ( AttachOpts )
2013-04-02 21:07:16 -04:00
}
2013-04-03 10:06:35 -04:00
func ( opts AttachOpts ) String ( ) string {
// Cast to underlying map type to avoid infinite recursion
return fmt . Sprintf ( "%v" , map [ string ] bool ( opts ) )
2013-04-02 21:07:16 -04:00
}
2013-04-03 10:06:35 -04:00
func ( opts AttachOpts ) Set ( val string ) error {
2013-04-02 21:07:16 -04:00
if val != "stdin" && val != "stdout" && val != "stderr" {
return fmt . Errorf ( "Unsupported stream name: %s" , val )
}
2013-04-03 10:06:35 -04:00
opts [ val ] = true
2013-04-02 21:07:16 -04:00
return nil
}
2013-04-03 10:06:35 -04:00
func ( opts AttachOpts ) Get ( val string ) bool {
if res , exists := opts [ val ] ; exists {
2013-04-02 21:07:16 -04:00
return res
}
return false
}
2013-04-05 21:00:10 -04:00
// PathOpts stores a unique set of absolute paths
2013-04-10 19:09:34 -04:00
type PathOpts map [ string ] struct { }
2013-04-05 21:00:10 -04:00
func NewPathOpts ( ) PathOpts {
return make ( PathOpts )
}
func ( opts PathOpts ) String ( ) string {
2013-04-10 19:09:34 -04:00
return fmt . Sprintf ( "%v" , map [ string ] struct { } ( opts ) )
2013-04-05 21:00:10 -04:00
}
func ( opts PathOpts ) Set ( val string ) error {
if ! filepath . IsAbs ( val ) {
return fmt . Errorf ( "%s is not an absolute path" , val )
}
2013-04-10 19:09:34 -04:00
opts [ filepath . Clean ( val ) ] = struct { } { }
2013-04-05 21:00:10 -04:00
return nil
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdTag ( args ... string ) error {
2013-04-23 12:20:53 -04:00
cmd := Subcmd ( "tag" , "[OPTIONS] IMAGE REPOSITORY [TAG]" , "Tag an image into a repository" )
2013-03-22 21:27:18 -04:00
force := cmd . Bool ( "f" , false , "Force" )
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-23 12:20:53 -04:00
if cmd . NArg ( ) != 2 && cmd . NArg ( ) != 3 {
2013-03-22 21:27:18 -04:00
cmd . Usage ( )
return nil
}
2013-04-23 12:20:53 -04:00
v := url . Values { }
v . Set ( "repo" , cmd . Arg ( 1 ) )
if cmd . NArg ( ) == 3 {
v . Set ( "tag" , cmd . Arg ( 2 ) )
}
if * force {
2013-04-26 09:08:33 -04:00
v . Set ( "force" , "1" )
2013-04-23 12:20:53 -04:00
}
2013-05-13 05:48:27 -04:00
if _ , _ , err := cli . call ( "POST" , "/images/" + cmd . Arg ( 0 ) + "/tag?" + v . Encode ( ) , nil ) ; err != nil {
2013-04-23 12:20:53 -04:00
return err
}
return nil
2013-03-22 21:27:18 -04:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) CmdRun ( args ... string ) error {
2013-05-07 13:23:50 -04:00
config , cmd , err := ParseRun ( args , nil )
2013-03-23 15:16:58 -04:00
if err != nil {
return err
2013-02-13 20:10:00 -05:00
}
2013-03-23 15:39:09 -04:00
if config . Image == "" {
2013-04-23 12:20:53 -04:00
cmd . Usage ( )
return nil
2013-03-23 15:16:58 -04:00
}
2013-04-05 22:48:49 -04:00
2013-05-01 23:07:06 -04:00
//create the container
2013-05-13 05:48:27 -04:00
body , statusCode , err := cli . call ( "POST" , "/containers/create" , config )
2013-05-01 23:07:06 -04:00
//if image not found try to pull it
if statusCode == 404 {
2013-05-06 05:31:22 -04:00
v := url . Values { }
v . Set ( "fromImage" , config . Image )
2013-05-16 15:09:06 -04:00
err = cli . stream ( "POST" , "/images/create?" + v . Encode ( ) , nil , os . Stderr )
2013-05-01 23:07:06 -04:00
if err != nil {
return err
}
2013-05-13 05:48:27 -04:00
body , _ , err = cli . call ( "POST" , "/containers/create" , config )
2013-05-06 05:31:22 -04:00
if err != nil {
return err
}
2013-05-01 23:07:06 -04:00
}
if err != nil {
2013-04-02 02:52:20 -04:00
return err
2013-04-05 00:51:40 -04:00
}
2013-04-24 18:14:10 -04:00
2013-06-04 14:00:22 -04:00
out := & APIRun { }
2013-05-10 00:53:28 -04:00
err = json . Unmarshal ( body , out )
2013-02-13 20:10:00 -05:00
if err != nil {
2013-05-01 23:07:06 -04:00
return err
2013-02-13 20:10:00 -05:00
}
2013-05-01 23:07:06 -04:00
2013-05-02 12:36:23 -04:00
for _ , warning := range out . Warnings {
fmt . Fprintln ( os . Stderr , "WARNING: " , warning )
}
2013-05-29 10:14:51 -04:00
splitStderr := ! config . Tty
2013-05-01 23:07:06 -04:00
2013-05-29 07:40:54 -04:00
connections := 0
2013-05-29 10:14:51 -04:00
if config . AttachStdin || config . AttachStdout || ( ! splitStderr && config . AttachStderr ) {
2013-05-29 07:40:54 -04:00
connections += 1
2013-02-13 20:10:00 -05:00
}
2013-05-29 10:14:51 -04:00
if splitStderr && config . AttachStderr {
2013-05-29 07:40:54 -04:00
connections += 1
2013-04-02 02:52:20 -04:00
}
2013-04-02 15:18:20 -04:00
2013-05-01 23:07:06 -04:00
//start the container
2013-06-04 14:00:22 -04:00
_ , _ , err = cli . call ( "POST" , "/containers/" + out . ID + "/start" , nil )
2013-04-22 12:17:47 -04:00
if err != nil {
2013-04-02 02:52:20 -04:00
return err
2013-02-13 20:10:00 -05:00
}
2013-05-07 16:15:21 -04:00
2013-06-04 18:24:25 -04:00
if ! config . AttachStdout && ! config . AttachStderr {
fmt . Println ( out . ID )
}
2013-05-29 07:40:54 -04:00
if connections > 0 {
2013-05-29 10:14:51 -04:00
chErrors := make ( chan error , connections )
2013-06-13 15:57:35 -04:00
if config . Tty {
cli . monitorTtySize ( out . ID )
}
2013-05-29 07:40:54 -04:00
2013-05-29 10:14:51 -04:00
if splitStderr && config . AttachStderr {
2013-05-29 07:40:54 -04:00
go func ( ) {
2013-06-04 14:00:22 -04:00
chErrors <- cli . hijack ( "POST" , "/containers/" + out . ID + "/attach?logs=1&stream=1&stderr=1" , config . Tty , nil , os . Stderr )
2013-05-29 07:40:54 -04:00
} ( )
}
v := url . Values { }
v . Set ( "logs" , "1" )
v . Set ( "stream" , "1" )
if config . AttachStdin {
v . Set ( "stdin" , "1" )
}
if config . AttachStdout {
v . Set ( "stdout" , "1" )
}
2013-05-29 10:14:51 -04:00
if ! splitStderr && config . AttachStderr {
2013-05-29 07:40:54 -04:00
v . Set ( "stderr" , "1" )
}
go func ( ) {
2013-06-04 14:00:22 -04:00
chErrors <- cli . hijack ( "POST" , "/containers/" + out . ID + "/attach?" + v . Encode ( ) , config . Tty , os . Stdin , os . Stdout )
2013-05-29 07:40:54 -04:00
} ( )
for connections > 0 {
2013-05-29 10:14:51 -04:00
err := <- chErrors
2013-05-29 07:40:54 -04:00
if err != nil {
2013-06-13 15:57:35 -04:00
utils . Debugf ( "Error hijack: %s" , err )
2013-05-29 07:40:54 -04:00
return err
}
connections -= 1
2013-05-01 23:07:06 -04:00
}
2013-05-07 15:36:24 -04:00
}
2013-05-01 23:07:06 -04:00
return nil
2013-02-13 20:10:00 -05:00
}
2013-04-23 12:20:53 -04:00
2013-05-30 11:39:43 -04:00
func ( cli * DockerCli ) checkIfLogged ( condition bool , action string ) error {
2013-05-24 08:43:24 -04:00
// If condition AND the login failed
2013-05-30 11:39:43 -04:00
if condition && cli . authConfig . Username == "" {
2013-05-24 08:43:24 -04:00
if err := cli . CmdLogin ( "" ) ; err != nil {
2013-05-30 11:39:43 -04:00
return err
2013-05-17 09:23:12 -04:00
}
2013-05-30 11:39:43 -04:00
if cli . authConfig . Username == "" {
return fmt . Errorf ( "Please login prior to %s. ('docker login')" , action )
2013-05-17 09:23:12 -04:00
}
}
2013-05-30 11:39:43 -04:00
return nil
2013-05-17 09:23:12 -04:00
}
2013-05-15 10:16:46 -04:00
func ( cli * DockerCli ) call ( method , path string , data interface { } ) ( [ ] byte , int , error ) {
2013-05-01 23:07:06 -04:00
var params io . Reader
2013-04-23 12:20:53 -04:00
if data != nil {
buf , err := json . Marshal ( data )
if err != nil {
2013-05-01 23:07:06 -04:00
return nil , - 1 , err
2013-04-23 12:20:53 -04:00
}
2013-05-01 23:07:06 -04:00
params = bytes . NewBuffer ( buf )
2013-04-22 12:17:47 -04:00
}
2013-05-07 11:19:41 -04:00
2013-06-04 14:00:22 -04:00
req , err := http . NewRequest ( method , fmt . Sprintf ( "http://%s:%d/v%g%s" , cli . host , cli . port , APIVERSION , path ) , params )
2013-04-22 12:17:47 -04:00
if err != nil {
2013-05-01 23:07:06 -04:00
return nil , - 1 , err
2013-04-22 12:17:47 -04:00
}
2013-05-09 14:24:49 -04:00
req . Header . Set ( "User-Agent" , "Docker-Client/" + VERSION )
2013-04-23 12:20:53 -04:00
if data != nil {
req . Header . Set ( "Content-Type" , "application/json" )
2013-05-01 23:07:06 -04:00
} else if method == "POST" {
req . Header . Set ( "Content-Type" , "plain/text" )
2013-04-22 12:17:47 -04:00
}
2013-05-01 23:07:06 -04:00
resp , err := http . DefaultClient . Do ( req )
if err != nil {
2013-05-09 14:24:49 -04:00
if strings . Contains ( err . Error ( ) , "connection refused" ) {
return nil , - 1 , fmt . Errorf ( "Can't connect to docker daemon. Is 'docker -d' running on this host?" )
}
2013-05-01 23:07:06 -04:00
return nil , - 1 , err
}
defer resp . Body . Close ( )
body , err := ioutil . ReadAll ( resp . Body )
if err != nil {
return nil , - 1 , err
}
2013-05-09 15:42:29 -04:00
if resp . StatusCode < 200 || resp . StatusCode >= 400 {
2013-06-10 11:06:52 -04:00
if len ( body ) == 0 {
return nil , resp . StatusCode , fmt . Errorf ( "Error: %s" , http . StatusText ( resp . StatusCode ) )
}
return nil , resp . StatusCode , fmt . Errorf ( "Error: %s" , body )
2013-02-13 20:10:00 -05:00
}
2013-05-01 23:07:06 -04:00
return body , resp . StatusCode , nil
}
2013-04-22 14:16:32 -04:00
2013-05-16 15:09:06 -04:00
func ( cli * DockerCli ) stream ( method , path string , in io . Reader , out io . Writer ) error {
if ( method == "POST" || method == "PUT" ) && in == nil {
in = bytes . NewReader ( [ ] byte { } )
}
2013-06-04 14:00:22 -04:00
req , err := http . NewRequest ( method , fmt . Sprintf ( "http://%s:%d/v%g%s" , cli . host , cli . port , APIVERSION , path ) , in )
2013-05-09 17:28:03 -04:00
if err != nil {
return err
}
req . Header . Set ( "User-Agent" , "Docker-Client/" + VERSION )
if method == "POST" {
req . Header . Set ( "Content-Type" , "plain/text" )
}
resp , err := http . DefaultClient . Do ( req )
if err != nil {
if strings . Contains ( err . Error ( ) , "connection refused" ) {
return fmt . Errorf ( "Can't connect to docker daemon. Is 'docker -d' running on this host?" )
}
return err
}
defer resp . Body . Close ( )
2013-05-13 05:38:13 -04:00
if resp . StatusCode < 200 || resp . StatusCode >= 400 {
body , err := ioutil . ReadAll ( resp . Body )
if err != nil {
return err
}
2013-06-10 11:06:52 -04:00
if len ( body ) == 0 {
return fmt . Errorf ( "Error :%s" , http . StatusText ( resp . StatusCode ) )
}
return fmt . Errorf ( "Error: %s" , body )
2013-05-13 05:38:13 -04:00
}
2013-05-23 11:16:35 -04:00
if resp . Header . Get ( "Content-Type" ) == "application/json" {
dec := json . NewDecoder ( resp . Body )
for {
2013-06-04 14:00:22 -04:00
var m utils . JSONMessage
2013-05-23 11:16:35 -04:00
if err := dec . Decode ( & m ) ; err == io . EOF {
break
} else if err != nil {
return err
}
2013-05-24 10:43:52 -04:00
if m . Progress != "" {
2013-06-04 12:09:08 -04:00
fmt . Fprintf ( out , "%s %s\r" , m . Status , m . Progress )
2013-05-25 10:12:02 -04:00
} else if m . Error != "" {
return fmt . Errorf ( m . Error )
2013-05-24 10:43:52 -04:00
} else {
2013-05-23 11:16:35 -04:00
fmt . Fprintf ( out , "%s\n" , m . Status )
}
}
} else {
if _ , err := io . Copy ( out , resp . Body ) ; err != nil {
return err
}
2013-04-22 14:16:32 -04:00
}
2013-04-02 15:21:35 -04:00
return nil
2013-02-13 20:10:00 -05:00
}
2013-05-29 07:40:54 -04:00
func ( cli * DockerCli ) hijack ( method , path string , setRawTerminal bool , in * os . File , out io . Writer ) error {
2013-06-04 14:00:22 -04:00
req , err := http . NewRequest ( method , fmt . Sprintf ( "/v%g%s" , APIVERSION , path ) , nil )
2013-05-01 23:07:06 -04:00
if err != nil {
return err
2013-03-21 05:04:10 -04:00
}
2013-05-07 13:23:50 -04:00
req . Header . Set ( "Content-Type" , "plain/text" )
2013-05-13 14:34:09 -04:00
dial , err := net . Dial ( "tcp" , fmt . Sprintf ( "%s:%d" , cli . host , cli . port ) )
2013-02-13 20:10:00 -05:00
if err != nil {
2013-04-23 12:20:53 -04:00
return err
2013-04-22 12:17:47 -04:00
}
2013-04-23 12:20:53 -04:00
clientconn := httputil . NewClientConn ( dial , nil )
2013-04-24 12:50:26 -04:00
clientconn . Do ( req )
2013-04-23 12:20:53 -04:00
defer clientconn . Close ( )
2013-05-06 05:31:22 -04:00
rwc , br := clientconn . Hijack ( )
2013-04-23 12:20:53 -04:00
defer rwc . Close ( )
2013-05-14 18:37:35 -04:00
receiveStdout := utils . Go ( func ( ) error {
2013-05-29 07:40:54 -04:00
_ , err := io . Copy ( out , br )
2013-05-06 05:31:22 -04:00
return err
} )
2013-06-01 18:55:05 -04:00
if in != nil && setRawTerminal && term . IsTerminal ( in . Fd ( ) ) && os . Getenv ( "NORAW" ) == "" {
2013-06-04 09:51:12 -04:00
oldState , err := term . SetRawTerminal ( )
if err != nil {
2013-04-29 09:12:18 -04:00
return err
}
2013-06-04 09:51:12 -04:00
defer term . RestoreTerminal ( oldState )
2013-02-13 20:10:00 -05:00
}
2013-05-14 18:37:35 -04:00
sendStdin := utils . Go ( func ( ) error {
2013-06-13 15:57:35 -04:00
io . Copy ( rwc , in )
2013-05-07 16:15:21 -04:00
if err := rwc . ( * net . TCPConn ) . CloseWrite ( ) ; err != nil {
2013-06-13 15:57:35 -04:00
utils . Debugf ( "Couldn't send EOF: %s\n" , err )
2013-05-07 16:15:21 -04:00
}
2013-06-13 15:57:35 -04:00
// Discard errors due to pipe interruption
return nil
2013-04-23 12:20:53 -04:00
} )
if err := <- receiveStdout ; err != nil {
2013-06-13 15:57:35 -04:00
utils . Debugf ( "Error receiveStdout: %s" , err )
2013-04-23 12:20:53 -04:00
return err
2013-02-13 20:10:00 -05:00
}
2013-05-10 01:28:52 -04:00
2013-06-12 08:54:37 -04:00
if ! term . IsTerminal ( in . Fd ( ) ) {
2013-04-23 12:20:53 -04:00
if err := <- sendStdin ; err != nil {
2013-06-13 15:57:35 -04:00
utils . Debugf ( "Error sendStdin: %s" , err )
2013-04-23 12:20:53 -04:00
return err
}
}
return nil
2013-02-13 20:10:00 -05:00
}
2013-05-24 17:44:16 -04:00
func ( cli * DockerCli ) resizeTty ( id string ) {
ws , err := term . GetWinsize ( os . Stdin . Fd ( ) )
if err != nil {
utils . Debugf ( "Error getting size: %s" , err )
}
v := url . Values { }
v . Set ( "h" , strconv . Itoa ( int ( ws . Height ) ) )
v . Set ( "w" , strconv . Itoa ( int ( ws . Width ) ) )
if _ , _ , err := cli . call ( "POST" , "/containers/" + id + "/resize?" + v . Encode ( ) , nil ) ; err != nil {
utils . Debugf ( "Error resize: %s" , err )
}
}
func ( cli * DockerCli ) monitorTtySize ( id string ) {
cli . resizeTty ( id )
c := make ( chan os . Signal , 1 )
signal . Notify ( c , syscall . SIGWINCH )
go func ( ) {
for sig := range c {
if sig == syscall . SIGWINCH {
cli . resizeTty ( id )
}
}
} ( )
}
2013-04-22 12:17:47 -04:00
func Subcmd ( name , signature , description string ) * flag . FlagSet {
flags := flag . NewFlagSet ( name , flag . ContinueOnError )
flags . Usage = func ( ) {
fmt . Printf ( "\nUsage: docker %s %s\n\n%s\n\n" , name , signature , description )
flags . PrintDefaults ( )
}
return flags
2013-02-13 20:10:00 -05:00
}
2013-05-13 05:48:27 -04:00
2013-05-23 12:09:28 -04:00
func NewDockerCli ( addr string , port int ) * DockerCli {
2013-05-30 11:39:43 -04:00
authConfig , _ := auth . LoadConfig ( os . Getenv ( "HOME" ) )
return & DockerCli { addr , port , authConfig }
2013-05-13 05:48:27 -04:00
}
2013-05-15 10:16:46 -04:00
type DockerCli struct {
2013-05-30 11:39:43 -04:00
host string
port int
authConfig * auth . AuthConfig
2013-05-13 05:48:27 -04:00
}