2013-03-14 09:26:46 +00:00
package docker
2013-02-14 01:10:00 +00:00
import (
2013-02-14 01:28:13 +00:00
"bytes"
"encoding/json"
2013-02-14 01:10:00 +00:00
"fmt"
2013-03-15 00:43:59 +00:00
"github.com/dotcloud/docker/auth"
2013-03-12 18:59:27 +00:00
"github.com/dotcloud/docker/rcli"
2013-02-14 01:28:13 +00:00
"io"
2013-03-21 09:04:10 +00:00
"log"
2013-03-13 18:33:48 +00:00
"net/http"
2013-03-14 01:37:00 +00:00
"net/url"
2013-03-21 09:04:10 +00:00
"runtime"
2013-02-28 19:52:22 +00:00
"strconv"
2013-02-14 01:28:13 +00:00
"strings"
"text/tabwriter"
"time"
2013-03-28 19:11:47 +00:00
"unicode"
2013-02-14 01:10:00 +00:00
)
2013-04-24 06:15:09 +00:00
const VERSION = "0.2.0"
2013-02-14 01:10:00 +00:00
2013-04-11 19:58:23 +00:00
var (
2013-04-19 04:08:20 +00:00
GIT_COMMIT string
2013-04-11 19:58:23 +00:00
)
2013-04-01 18:12:56 +00:00
2013-02-14 01:10:00 +00:00
func ( srv * Server ) Name ( ) string {
return "docker"
}
2013-03-11 23:11:46 +00:00
// FIXME: Stop violating DRY by repeating usage here and in Subcmd declarations
2013-02-14 01:10:00 +00:00
func ( srv * Server ) Help ( ) string {
help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n"
2013-03-30 07:36:27 +00:00
for _ , cmd := range [ ] [ ] string {
2013-03-11 23:11:46 +00:00
{ "attach" , "Attach to a running container" } ,
{ "commit" , "Create a new image from a container's changes" } ,
2013-02-14 01:10:00 +00:00
{ "diff" , "Inspect changes on a container's filesystem" } ,
2013-03-23 01:15:44 +00:00
{ "export" , "Stream the contents of a container as a tar archive" } ,
{ "history" , "Show the history of an image" } ,
2013-02-14 01:10:00 +00:00
{ "images" , "List images" } ,
2013-03-23 01:15:44 +00:00
{ "import" , "Create a new filesystem image from the contents of a tarball" } ,
2013-02-14 01:10:00 +00:00
{ "info" , "Display system-wide information" } ,
2013-03-11 22:08:22 +00:00
{ "inspect" , "Return low-level information on a container" } ,
2013-03-11 23:11:46 +00:00
{ "kill" , "Kill a running container" } ,
2013-03-15 00:43:59 +00:00
{ "login" , "Register or Login to the docker registry server" } ,
2013-03-11 23:11:46 +00:00
{ "logs" , "Fetch the logs of a container" } ,
{ "port" , "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT" } ,
{ "ps" , "List containers" } ,
2013-03-27 13:02:11 +00:00
{ "pull" , "Pull an image or a repository from the docker registry server" } ,
2013-03-22 10:24:37 +00:00
{ "push" , "Push an image or a repository to the docker registry server" } ,
2013-03-11 23:11:46 +00:00
{ "restart" , "Restart a running container" } ,
{ "rm" , "Remove a container" } ,
2013-03-15 07:47:02 +00:00
{ "rmi" , "Remove an image" } ,
2013-03-11 23:11:46 +00:00
{ "run" , "Run a command in a new container" } ,
{ "start" , "Start a stopped container" } ,
{ "stop" , "Stop a running container" } ,
2013-03-23 01:15:44 +00:00
{ "tag" , "Tag an image into a repository" } ,
2013-03-13 00:34:15 +00:00
{ "version" , "Show the docker version information" } ,
2013-03-11 23:11:46 +00:00
{ "wait" , "Block until a container stops, then print its exit code" } ,
2013-02-14 01:10:00 +00:00
} {
2013-03-21 05:42:50 +00:00
help += fmt . Sprintf ( " %-10.10s%s\n" , cmd [ 0 ] , cmd [ 1 ] )
2013-02-14 01:10:00 +00:00
}
return help
}
2013-03-15 00:43:59 +00:00
// 'docker login': login / register a user to registry service.
2013-04-03 19:25:19 +00:00
func ( srv * Server ) CmdLogin ( stdin io . ReadCloser , stdout rcli . DockerConn , args ... string ) error {
2013-03-28 19:11:47 +00:00
// Read a line on raw terminal with support for simple backspace
// sequences and echo.
//
2013-03-30 07:22:24 +00:00
// This function is necessary because the login command must be done in a
2013-03-28 19:11:47 +00:00
// raw terminal for two reasons:
// - we have to read a password (without echoing it);
// - the rcli "protocol" only supports cannonical and raw modes and you
// can't tune it once the command as been started.
2013-04-05 03:19:06 +00:00
var readStringOnRawTerminal = func ( stdin io . Reader , stdout io . Writer , echo bool ) string {
2013-03-28 19:11:47 +00: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-11 02:08:46 +00:00
stdout . Write ( [ ] byte { '\r' , '\n' } )
2013-03-28 19:11:47 +00: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-11 02:08:46 +00:00
fmt . Fprintf ( stdout , "Read error: %v\r\n" , err )
2013-03-28 19:11:47 +00:00
}
break
}
}
return string ( buffer [ : i ] )
}
2013-04-05 03:19:06 +00:00
var readAndEchoString = func ( stdin io . Reader , stdout io . Writer ) string {
2013-03-28 19:11:47 +00:00
return readStringOnRawTerminal ( stdin , stdout , true )
}
2013-04-05 03:19:06 +00:00
var readString = func ( stdin io . Reader , stdout io . Writer ) string {
2013-03-28 19:11:47 +00:00
return readStringOnRawTerminal ( stdin , stdout , false )
}
2013-04-03 19:25:19 +00:00
stdout . SetOptionRawTerminal ( )
2013-03-15 14:49:27 +00:00
cmd := rcli . Subcmd ( stdout , "login" , "" , "Register or Login to the docker registry server" )
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-03-28 19:11:47 +00:00
2013-03-15 00:43:59 +00:00
var username string
var password string
var email string
2013-03-22 09:19:39 +00:00
fmt . Fprint ( stdout , "Username (" , srv . runtime . authConfig . Username , "): " )
2013-03-28 19:11:47 +00:00
username = readAndEchoString ( stdin , stdout )
2013-03-15 00:43:59 +00:00
if username == "" {
2013-03-22 09:19:39 +00:00
username = srv . runtime . authConfig . Username
2013-03-15 00:43:59 +00:00
}
2013-03-22 09:19:39 +00:00
if username != srv . runtime . authConfig . Username {
2013-03-15 00:43:59 +00:00
fmt . Fprint ( stdout , "Password: " )
2013-03-28 19:11:47 +00:00
password = readString ( stdin , stdout )
2013-03-15 00:43:59 +00:00
2013-03-15 14:49:27 +00:00
if password == "" {
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "Error : Password Required" )
2013-03-15 14:49:27 +00:00
}
2013-03-22 09:19:39 +00:00
fmt . Fprint ( stdout , "Email (" , srv . runtime . authConfig . Email , "): " )
2013-03-28 19:11:47 +00:00
email = readAndEchoString ( stdin , stdout )
2013-03-15 00:43:59 +00:00
if email == "" {
2013-03-22 09:19:39 +00:00
email = srv . runtime . authConfig . Email
2013-03-15 00:43:59 +00:00
}
} else {
2013-03-22 09:19:39 +00:00
password = srv . runtime . authConfig . Password
email = srv . runtime . authConfig . Email
2013-03-15 00:43:59 +00:00
}
2013-03-22 12:52:13 +00:00
newAuthConfig := auth . NewAuthConfig ( username , password , email , srv . runtime . root )
2013-03-15 00:43:59 +00:00
status , err := auth . Login ( newAuthConfig )
if err != nil {
2013-04-11 02:08:46 +00:00
fmt . Fprintf ( stdout , "Error: %s\r\n" , err )
2013-03-23 01:37:53 +00:00
} else {
srv . runtime . authConfig = newAuthConfig
2013-03-15 00:43:59 +00:00
}
2013-03-15 03:21:03 +00:00
if status != "" {
2013-03-30 07:23:12 +00:00
fmt . Fprint ( stdout , status )
2013-03-15 03:21:03 +00:00
}
2013-03-15 00:43:59 +00:00
return nil
}
2013-02-26 19:43:54 +00:00
// 'docker wait': block until a container stops
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdWait ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "wait" , "CONTAINER [CONTAINER...]" , "Block until a container stops, then print its exit code." )
2013-02-26 19:43:54 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
for _ , name := range cmd . Args ( ) {
2013-03-21 07:41:15 +00:00
if container := srv . runtime . Get ( name ) ; container != nil {
2013-02-26 19:43:54 +00:00
fmt . Fprintln ( stdout , container . Wait ( ) )
} else {
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container: %s" , name )
2013-02-26 19:43:54 +00:00
}
}
return nil
}
2013-03-13 00:34:15 +00:00
// 'docker version': show version information
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdVersion ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-19 04:08:33 +00:00
fmt . Fprintf ( stdout , "Version: %s\n" , VERSION )
fmt . Fprintf ( stdout , "Git Commit: %s\n" , GIT_COMMIT )
fmt . Fprintf ( stdout , "Kernel: %s\n" , srv . runtime . kernelVersion )
if ! srv . runtime . capabilities . MemoryLimit {
fmt . Fprintf ( stdout , "WARNING: No memory limit support\n" )
}
if ! srv . runtime . capabilities . SwapLimit {
fmt . Fprintf ( stdout , "WARNING: No swap limit support\n" )
2013-04-11 19:58:23 +00:00
}
2013-03-13 00:34:15 +00:00
return nil
}
2013-02-14 01:10:00 +00:00
// 'docker info': display system-wide information.
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdInfo ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-03-21 07:41:15 +00:00
images , _ := srv . runtime . graph . All ( )
2013-03-12 15:59:32 +00:00
var imgcount int
if images == nil {
imgcount = 0
} else {
imgcount = len ( images )
}
2013-03-11 23:11:46 +00:00
cmd := rcli . Subcmd ( stdout , "info" , "" , "Display system-wide information." )
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-03-12 15:59:32 +00:00
if cmd . NArg ( ) > 0 {
2013-03-11 23:11:46 +00:00
cmd . Usage ( )
return nil
2013-03-12 11:24:26 +00:00
}
2013-02-14 01:10:00 +00:00
fmt . Fprintf ( stdout , "containers: %d\nversion: %s\nimages: %d\n" ,
2013-03-21 07:41:15 +00:00
len ( srv . runtime . List ( ) ) ,
2013-02-14 01:10:00 +00:00
VERSION ,
2013-03-12 15:59:32 +00:00
imgcount )
2013-03-30 17:33:10 +00:00
if ! rcli . DEBUG_FLAG {
return nil
}
2013-03-30 07:23:12 +00:00
fmt . Fprintln ( stdout , "debug mode enabled" )
2013-03-30 17:33:10 +00:00
fmt . Fprintf ( stdout , "fds: %d\ngoroutines: %d\n" , getTotalUsedFds ( ) , runtime . NumGoroutine ( ) )
2013-02-14 01:10:00 +00:00
return nil
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdStop ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-16 16:43:44 +00:00
cmd := rcli . Subcmd ( stdout , "stop" , "[OPTIONS] CONTAINER [CONTAINER...]" , "Stop a running container" )
nSeconds := cmd . Int ( "t" , 10 , "wait t seconds before killing the container" )
2013-02-14 01:10:00 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
for _ , name := range cmd . Args ( ) {
2013-03-21 07:41:15 +00:00
if container := srv . runtime . Get ( name ) ; container != nil {
2013-04-16 16:43:44 +00:00
if err := container . Stop ( * nSeconds ) ; err != nil {
2013-02-14 01:10:00 +00:00
return err
}
2013-03-31 09:02:01 +00:00
fmt . Fprintln ( stdout , container . ShortId ( ) )
2013-02-14 01:10:00 +00:00
} else {
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container: %s" , name )
2013-02-14 21:49:05 +00:00
}
}
return nil
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdRestart ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "restart" , "CONTAINER [CONTAINER...]" , "Restart a running container" )
2013-04-16 16:43:44 +00:00
nSeconds := cmd . Int ( "t" , 10 , "wait t seconds before killing the container" )
2013-02-14 21:49:05 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
for _ , name := range cmd . Args ( ) {
2013-03-21 07:41:15 +00:00
if container := srv . runtime . Get ( name ) ; container != nil {
2013-04-16 16:43:44 +00:00
if err := container . Restart ( * nSeconds ) ; err != nil {
2013-02-14 21:49:05 +00:00
return err
}
2013-03-31 09:02:01 +00:00
fmt . Fprintln ( stdout , container . ShortId ( ) )
2013-02-14 21:49:05 +00:00
} else {
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container: %s" , name )
2013-02-14 21:49:05 +00:00
}
}
return nil
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdStart ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "start" , "CONTAINER [CONTAINER...]" , "Start a stopped container" )
2013-02-14 21:49:05 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
for _ , name := range cmd . Args ( ) {
2013-03-21 07:41:15 +00:00
if container := srv . runtime . Get ( name ) ; container != nil {
2013-02-14 21:49:05 +00:00
if err := container . Start ( ) ; err != nil {
return err
}
2013-03-31 09:02:01 +00:00
fmt . Fprintln ( stdout , container . ShortId ( ) )
2013-02-14 21:49:05 +00:00
} else {
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container: %s" , name )
2013-02-14 01:10:00 +00:00
}
}
return nil
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdInspect ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "inspect" , "CONTAINER" , "Return low-level information on a container" )
2013-02-14 01:10:00 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
name := cmd . Arg ( 0 )
var obj interface { }
2013-03-21 07:41:15 +00:00
if container := srv . runtime . Get ( name ) ; container != nil {
2013-02-14 01:10:00 +00:00
obj = container
2013-03-23 21:18:35 +00:00
} else if image , err := srv . runtime . repositories . LookupImage ( name ) ; err == nil && image != nil {
2013-03-13 20:23:59 +00:00
obj = image
2013-02-14 01:10:00 +00:00
} else {
2013-03-13 20:48:00 +00:00
// No output means the object does not exist
// (easier to script since stdout and stderr are not differentiated atm)
return nil
2013-02-14 01:10:00 +00:00
}
data , err := json . Marshal ( obj )
if err != nil {
return err
}
indented := new ( bytes . Buffer )
if err = json . Indent ( indented , data , "" , " " ) ; err != nil {
return err
}
if _ , err := io . Copy ( stdout , indented ) ; err != nil {
return err
}
2013-03-13 20:48:00 +00:00
stdout . Write ( [ ] byte { '\n' } )
2013-02-14 01:10:00 +00:00
return nil
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdPort ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "port" , "CONTAINER PRIVATE_PORT" , "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT" )
2013-03-06 08:39:03 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) != 2 {
cmd . Usage ( )
return nil
}
name := cmd . Arg ( 0 )
privatePort := cmd . Arg ( 1 )
2013-03-21 07:41:15 +00:00
if container := srv . runtime . Get ( name ) ; container == nil {
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container: %s" , name )
2013-03-06 08:39:03 +00:00
} else {
if frontend , exists := container . NetworkSettings . PortMapping [ privatePort ] ; ! exists {
return fmt . Errorf ( "No private port '%s' allocated on %s" , privatePort , name )
} else {
fmt . Fprintln ( stdout , frontend )
}
}
return nil
}
2013-04-11 16:46:47 +00:00
// 'docker rmi IMAGE' removes all images with the name IMAGE
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdRmi ( stdin io . ReadCloser , stdout io . Writer , args ... string ) ( err error ) {
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "rmimage" , "IMAGE [IMAGE...]" , "Remove an image" )
2013-03-26 01:35:31 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
2013-03-13 18:14:37 +00:00
cmd . Usage ( )
return nil
}
for _ , name := range cmd . Args ( ) {
2013-04-11 00:23:42 +00:00
img , err := srv . runtime . repositories . LookupImage ( name )
if err != nil {
return err
}
if err := srv . runtime . graph . Delete ( img . Id ) ; err != nil {
2013-03-13 18:14:37 +00:00
return err
}
}
return nil
}
2013-02-14 01:10:00 +00:00
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdHistory ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "history" , "IMAGE" , "Show the history of an image" )
2013-03-26 01:33:56 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) != 1 {
2013-03-22 04:42:18 +00:00
cmd . Usage ( )
return nil
}
2013-03-22 23:07:13 +00:00
image , err := srv . runtime . repositories . LookupImage ( cmd . Arg ( 0 ) )
2013-03-22 04:42:18 +00:00
if err != nil {
return err
}
2013-03-23 00:22:32 +00:00
w := tabwriter . NewWriter ( stdout , 20 , 1 , 3 , ' ' , 0 )
defer w . Flush ( )
2013-03-30 07:23:12 +00:00
fmt . Fprintln ( w , "ID\tCREATED\tCREATED BY" )
2013-03-21 17:12:05 +00:00
return image . WalkHistory ( func ( img * Image ) error {
2013-03-23 00:22:32 +00:00
fmt . Fprintf ( w , "%s\t%s\t%s\n" ,
2013-04-01 05:11:55 +00:00
srv . runtime . repositories . ImageName ( img . ShortId ( ) ) ,
2013-03-23 00:22:32 +00:00
HumanDuration ( time . Now ( ) . Sub ( img . Created ) ) + " ago" ,
2013-03-23 21:48:16 +00:00
strings . Join ( img . ContainerConfig . Cmd , " " ) ,
2013-03-23 00:22:32 +00:00
)
2013-03-21 17:12:05 +00:00
return nil
2013-03-22 04:42:18 +00:00
} )
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdRm ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "rm" , "CONTAINER [CONTAINER...]" , "Remove a container" )
2013-02-14 01:10:00 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-11 14:27:01 +00:00
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
2013-02-14 01:10:00 +00:00
for _ , name := range cmd . Args ( ) {
2013-03-21 07:41:15 +00:00
container := srv . runtime . Get ( name )
2013-02-14 01:10:00 +00:00
if container == nil {
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container: %s" , name )
2013-02-14 01:10:00 +00:00
}
2013-03-21 07:41:15 +00:00
if err := srv . runtime . Destroy ( container ) ; err != nil {
2013-02-14 01:28:13 +00:00
fmt . Fprintln ( stdout , "Error destroying container " + name + ": " + err . Error ( ) )
2013-02-14 01:10:00 +00:00
}
}
return nil
}
// 'docker kill NAME' kills a running container
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdKill ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "kill" , "CONTAINER [CONTAINER...]" , "Kill a running container" )
2013-02-14 01:10:00 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-12 10:26:31 +00:00
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
2013-02-14 01:10:00 +00:00
for _ , name := range cmd . Args ( ) {
2013-03-21 07:41:15 +00:00
container := srv . runtime . Get ( name )
2013-02-14 01:10:00 +00:00
if container == nil {
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container: %s" , name )
2013-02-14 01:10:00 +00:00
}
if err := container . Kill ( ) ; err != nil {
2013-02-14 01:28:13 +00:00
fmt . Fprintln ( stdout , "Error killing container " + name + ": " + err . Error ( ) )
2013-02-14 01:10:00 +00:00
}
}
return nil
}
2013-04-09 17:02:57 +00:00
func ( srv * Server ) CmdImport ( stdin io . ReadCloser , stdout rcli . DockerConn , args ... string ) error {
stdout . Flush ( )
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "import" , "URL|- [REPOSITORY [TAG]]" , "Create a new filesystem image from the contents of a tarball" )
2013-03-13 18:33:48 +00:00
var archive io . Reader
var resp * http . Response
2013-02-14 01:10:00 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-12 10:26:31 +00:00
if cmd . NArg ( ) < 1 {
cmd . Usage ( )
return nil
}
2013-03-22 00:35:49 +00:00
src := cmd . Arg ( 0 )
2013-04-12 10:26:31 +00:00
if src == "-" {
2013-03-12 04:04:16 +00:00
archive = stdin
} else {
2013-03-22 00:35:49 +00:00
u , err := url . Parse ( src )
2013-03-12 04:04:16 +00:00
if err != nil {
2013-03-01 00:30:31 +00:00
return err
2013-03-12 04:04:16 +00:00
}
if u . Scheme == "" {
u . Scheme = "http"
2013-03-23 02:47:32 +00:00
u . Host = src
u . Path = ""
2013-03-12 04:04:16 +00:00
}
2013-03-30 07:23:12 +00:00
fmt . Fprintln ( stdout , "Downloading from" , u )
2013-03-12 04:04:16 +00:00
// Download with curl (pretty progress bar)
// If curl is not available, fallback to http.Get()
2013-03-21 07:54:54 +00:00
resp , err = Download ( u . String ( ) , stdout )
2013-03-12 04:04:16 +00:00
if err != nil {
2013-03-13 18:33:48 +00:00
return err
2013-03-01 00:30:31 +00:00
}
2013-04-21 22:29:26 +00:00
archive = ProgressReader ( resp . Body , int ( resp . ContentLength ) , stdout , "Importing %v/%v (%v)" )
2013-02-14 01:10:00 +00:00
}
2013-04-25 23:48:31 +00:00
img , err := srv . runtime . graph . Create ( archive , nil , "Imported from " + src , "" , nil )
2013-02-14 01:10:00 +00:00
if err != nil {
return err
}
2013-03-22 00:35:49 +00:00
// Optionally register the image at REPO/TAG
if repository := cmd . Arg ( 1 ) ; repository != "" {
tag := cmd . Arg ( 2 ) // Repository will handle an empty tag properly
2013-03-23 01:27:18 +00:00
if err := srv . runtime . repositories . Set ( repository , tag , img . Id , true ) ; err != nil {
2013-03-22 00:35:49 +00:00
return err
}
}
2013-04-01 05:11:55 +00:00
fmt . Fprintln ( stdout , img . ShortId ( ) )
2013-02-14 01:10:00 +00:00
return nil
}
2013-04-03 19:25:19 +00:00
func ( srv * Server ) CmdPush ( stdin io . ReadCloser , stdout rcli . DockerConn , args ... string ) error {
2013-03-23 01:17:49 +00:00
cmd := rcli . Subcmd ( stdout , "push" , "NAME" , "Push an image or a repository to the registry" )
2013-03-21 10:53:27 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-03-22 13:38:54 +00:00
local := cmd . Arg ( 0 )
if local == "" {
2013-03-21 10:53:27 +00:00
cmd . Usage ( )
return nil
}
2013-03-22 13:38:54 +00:00
// If the login failed, abort
2013-03-23 02:04:12 +00:00
if srv . runtime . authConfig == nil || srv . runtime . authConfig . Username == "" {
if err := srv . CmdLogin ( stdin , stdout , args ... ) ; err != nil {
return err
}
if srv . runtime . authConfig == nil || srv . runtime . authConfig . Username == "" {
return fmt . Errorf ( "Please login prior to push. ('docker login')" )
}
2013-03-22 10:43:57 +00:00
}
2013-03-22 14:10:52 +00:00
var remote string
tmp := strings . SplitN ( local , "/" , 2 )
if len ( tmp ) == 1 {
2013-03-23 00:58:00 +00:00
return fmt . Errorf (
"Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)" ,
srv . runtime . authConfig . Username , local )
2013-03-22 13:38:54 +00:00
} else {
2013-03-22 14:10:52 +00:00
remote = local
2013-03-22 13:38:54 +00:00
}
2013-03-22 20:10:17 +00:00
Debugf ( "Pushing [%s] to [%s]\n" , local , remote )
2013-03-22 08:25:27 +00:00
// Try to get the image
// FIXME: Handle lookup
// FIXME: Also push the tags in case of ./docker push myrepo:mytag
// img, err := srv.runtime.LookupImage(cmd.Arg(0))
2013-03-22 13:38:54 +00:00
img , err := srv . runtime . graph . Get ( local )
2013-03-21 10:53:27 +00:00
if err != nil {
2013-03-22 20:10:17 +00:00
Debugf ( "The push refers to a repository [%s] (len: %d)\n" , local , len ( srv . runtime . repositories . Repositories [ local ] ) )
2013-03-22 08:25:27 +00:00
// If it fails, try to get the repository
2013-03-22 13:38:54 +00:00
if localRepo , exists := srv . runtime . repositories . Repositories [ local ] ; exists {
2013-03-22 20:21:44 +00:00
if err := srv . runtime . graph . PushRepository ( stdout , remote , localRepo , srv . runtime . authConfig ) ; err != nil {
2013-03-22 08:25:27 +00:00
return err
}
2013-03-22 10:10:09 +00:00
return nil
2013-03-22 08:25:27 +00:00
}
2013-04-03 09:08:32 +00:00
return err
2013-03-21 10:53:27 +00:00
}
2013-03-22 20:21:44 +00:00
err = srv . runtime . graph . PushImage ( stdout , img , srv . runtime . authConfig )
2013-03-22 10:10:09 +00:00
if err != nil {
return err
}
return nil
2013-03-21 10:53:27 +00:00
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdPull ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-03-23 01:17:49 +00:00
cmd := rcli . Subcmd ( stdout , "pull" , "NAME" , "Pull an image or a repository from the registry" )
2013-03-21 10:53:27 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-03-22 14:56:44 +00:00
remote := cmd . Arg ( 0 )
if remote == "" {
2013-03-21 10:53:27 +00:00
cmd . Usage ( )
return nil
}
2013-03-22 08:25:27 +00:00
2013-04-02 06:52:20 +00:00
// FIXME: CmdPull should be a wrapper around Runtime.Pull()
2013-03-22 14:56:44 +00:00
if srv . runtime . graph . LookupRemoteImage ( remote , srv . runtime . authConfig ) {
2013-03-26 01:48:57 +00:00
if err := srv . runtime . graph . PullImage ( stdout , remote , srv . runtime . authConfig ) ; err != nil {
2013-03-22 10:10:09 +00:00
return err
}
return nil
2013-03-22 08:25:27 +00:00
}
// FIXME: Allow pull repo:tag
2013-03-22 20:21:44 +00:00
if err := srv . runtime . graph . PullRepository ( stdout , remote , "" , srv . runtime . repositories , srv . runtime . authConfig ) ; err != nil {
2013-03-22 10:10:09 +00:00
return err
}
return nil
2013-03-21 10:53:27 +00:00
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdImages ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-02-14 01:10:00 +00:00
cmd := rcli . Subcmd ( stdout , "images" , "[OPTIONS] [NAME]" , "List images" )
2013-03-21 07:25:00 +00:00
//limit := cmd.Int("l", 0, "Only show the N most recent versions of each image")
2013-02-14 01:10:00 +00:00
quiet := cmd . Bool ( "q" , false , "only show numeric IDs" )
2013-03-29 00:12:23 +00:00
flAll := cmd . Bool ( "a" , false , "show all images" )
2013-03-11 22:08:22 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-02-14 01:10:00 +00:00
if cmd . NArg ( ) > 1 {
cmd . Usage ( )
return nil
}
2013-03-22 00:35:49 +00:00
var nameFilter string
if cmd . NArg ( ) == 1 {
nameFilter = cmd . Arg ( 0 )
}
2013-02-14 01:10:00 +00:00
w := tabwriter . NewWriter ( stdout , 20 , 1 , 3 , ' ' , 0 )
2013-02-14 01:28:13 +00:00
if ! * quiet {
2013-04-11 19:11:41 +00:00
fmt . Fprintln ( w , "REPOSITORY\tTAG\tID\tCREATED" )
2013-02-14 01:10:00 +00:00
}
2013-03-24 00:03:30 +00:00
var allImages map [ string ] * Image
var err error
2013-03-29 00:12:23 +00:00
if * flAll {
2013-03-24 00:03:30 +00:00
allImages , err = srv . runtime . graph . Map ( )
} else {
allImages , err = srv . runtime . graph . Heads ( )
}
2013-03-22 00:35:49 +00:00
if err != nil {
return err
}
for name , repository := range srv . runtime . repositories . Repositories {
if nameFilter != "" && name != nameFilter {
continue
2013-03-08 18:48:22 +00:00
}
2013-03-22 00:35:49 +00:00
for tag , id := range repository {
image , err := srv . runtime . graph . Get ( id )
if err != nil {
log . Printf ( "Warning: couldn't load %s from %s/%s: %s" , id , name , tag , err )
continue
}
delete ( allImages , id )
if ! * quiet {
for idx , field := range [ ] string {
/* REPOSITORY */ name ,
/* TAG */ tag ,
2013-04-01 05:11:55 +00:00
/* ID */ TruncateId ( id ) ,
2013-03-22 00:35:49 +00:00
/* CREATED */ HumanDuration ( time . Now ( ) . Sub ( image . Created ) ) + " ago" ,
} {
if idx == 0 {
w . Write ( [ ] byte ( field ) )
} else {
w . Write ( [ ] byte ( "\t" + field ) )
}
}
w . Write ( [ ] byte { '\n' } )
} else {
2013-04-01 05:11:55 +00:00
stdout . Write ( [ ] byte ( image . ShortId ( ) + "\n" ) )
2013-03-22 00:35:49 +00:00
}
2013-02-14 01:10:00 +00:00
}
2013-03-22 00:35:49 +00:00
}
2013-03-21 13:33:29 +00:00
// Display images which aren't part of a
2013-03-22 01:59:12 +00:00
if nameFilter == "" {
2013-03-22 00:35:49 +00:00
for id , image := range allImages {
if ! * quiet {
for idx , field := range [ ] string {
2013-03-24 22:01:41 +00:00
/* REPOSITORY */ "<none>" ,
/* TAG */ "<none>" ,
2013-04-01 05:11:55 +00:00
/* ID */ TruncateId ( id ) ,
2013-03-22 00:35:49 +00:00
/* CREATED */ HumanDuration ( time . Now ( ) . Sub ( image . Created ) ) + " ago" ,
} {
if idx == 0 {
w . Write ( [ ] byte ( field ) )
} else {
w . Write ( [ ] byte ( "\t" + field ) )
}
}
2013-03-22 01:59:12 +00:00
w . Write ( [ ] byte { '\n' } )
2013-03-22 00:35:49 +00:00
} else {
2013-04-01 05:11:55 +00:00
stdout . Write ( [ ] byte ( image . ShortId ( ) + "\n" ) )
2013-03-22 00:35:49 +00:00
}
}
}
if ! * quiet {
w . Flush ( )
2013-02-14 01:10:00 +00:00
}
return nil
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdPs ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-02-14 01:10:00 +00:00
cmd := rcli . Subcmd ( stdout ,
"ps" , "[OPTIONS]" , "List containers" )
quiet := cmd . Bool ( "q" , false , "Only display numeric IDs" )
2013-03-29 00:12:23 +00:00
flAll := cmd . Bool ( "a" , false , "Show all containers. Only running containers are shown by default." )
flFull := cmd . Bool ( "notrunc" , false , "Don't truncate output" )
2013-04-10 17:30:57 +00:00
latest := cmd . Bool ( "l" , false , "Show only the latest created container, include non-running ones." )
2013-04-11 11:09:40 +00:00
nLast := cmd . Int ( "n" , - 1 , "Show n last created containers, include non-running ones." )
2013-02-14 01:10:00 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-04-11 11:09:40 +00:00
if * nLast == - 1 && * latest {
* nLast = 1
2013-04-10 17:30:57 +00:00
}
2013-02-14 01:10:00 +00:00
w := tabwriter . NewWriter ( stdout , 12 , 1 , 3 , ' ' , 0 )
2013-02-14 01:28:13 +00:00
if ! * quiet {
2013-04-20 02:29:13 +00:00
fmt . Fprintln ( w , "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tCOMMENT\tPORTS" )
2013-02-14 01:10:00 +00:00
}
2013-04-10 17:30:57 +00:00
for i , container := range srv . runtime . List ( ) {
2013-04-11 11:09:40 +00:00
if ! container . State . Running && ! * flAll && * nLast == - 1 {
2013-02-14 01:10:00 +00:00
continue
}
2013-04-11 11:09:40 +00:00
if i == * nLast {
2013-04-10 17:30:57 +00:00
break
}
2013-02-14 01:10:00 +00:00
if ! * quiet {
command := fmt . Sprintf ( "%s %s" , container . Path , strings . Join ( container . Args , " " ) )
2013-03-29 00:12:23 +00:00
if ! * flFull {
2013-03-14 09:26:46 +00:00
command = Trunc ( command , 20 )
2013-02-14 01:10:00 +00:00
}
2013-02-14 01:28:13 +00:00
for idx , field := range [ ] string {
2013-03-31 09:02:01 +00:00
/* ID */ container . ShortId ( ) ,
2013-03-23 02:22:06 +00:00
/* IMAGE */ srv . runtime . repositories . ImageName ( container . Image ) ,
2013-02-14 01:28:13 +00:00
/* COMMAND */ command ,
2013-03-21 07:52:43 +00:00
/* CREATED */ HumanDuration ( time . Now ( ) . Sub ( container . Created ) ) + " ago" ,
2013-02-14 01:28:13 +00:00
/* STATUS */ container . State . String ( ) ,
2013-03-21 07:25:00 +00:00
/* COMMENT */ "" ,
2013-04-20 02:29:13 +00:00
/* PORTS */ container . NetworkSettings . PortMappingHuman ( ) ,
2013-02-14 01:10:00 +00:00
} {
if idx == 0 {
w . Write ( [ ] byte ( field ) )
} else {
w . Write ( [ ] byte ( "\t" + field ) )
}
}
w . Write ( [ ] byte { '\n' } )
} else {
2013-03-31 09:02:01 +00:00
stdout . Write ( [ ] byte ( container . ShortId ( ) + "\n" ) )
2013-02-14 01:10:00 +00:00
}
}
2013-02-14 01:28:13 +00:00
if ! * quiet {
2013-02-14 01:10:00 +00:00
w . Flush ( )
}
return nil
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdCommit ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-02-14 01:10:00 +00:00
cmd := rcli . Subcmd ( stdout ,
2013-03-22 03:07:37 +00:00
"commit" , "[OPTIONS] CONTAINER [REPOSITORY [TAG]]" ,
2013-02-14 01:10:00 +00:00
"Create a new image from a container's changes" )
2013-03-29 00:12:23 +00:00
flComment := cmd . String ( "m" , "" , "Commit message" )
2013-04-18 03:13:11 +00:00
flAuthor := cmd . String ( "author" , "" , "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"" )
2013-04-26 17:48:33 +00:00
flConfig := cmd . String ( "config" , "" , "Config automatically applied when the image is run. " + ` (ex: -config ' { "Cmd": ["cat", "/world"], "PortSpecs": ["22"]}') ` )
2013-02-14 01:10:00 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
2013-03-22 03:07:37 +00:00
containerName , repository , tag := cmd . Arg ( 0 ) , cmd . Arg ( 1 ) , cmd . Arg ( 2 )
if containerName == "" {
2013-02-14 01:10:00 +00:00
cmd . Usage ( )
return nil
}
2013-04-25 23:48:31 +00:00
2013-04-26 17:48:33 +00:00
config := & Config { }
2013-04-25 23:48:31 +00:00
if * flConfig != "" {
2013-04-26 17:48:33 +00:00
if err := json . Unmarshal ( [ ] byte ( * flConfig ) , config ) ; err != nil {
return err
}
2013-04-25 23:48:31 +00:00
}
2013-04-26 17:48:33 +00:00
img , err := srv . runtime . Commit ( containerName , repository , tag , * flComment , * flAuthor , config )
2013-03-22 03:07:37 +00:00
if err != nil {
return err
2013-02-14 01:10:00 +00:00
}
2013-04-01 05:11:55 +00:00
fmt . Fprintln ( stdout , img . ShortId ( ) )
2013-03-22 03:07:37 +00:00
return nil
2013-02-14 01:10:00 +00:00
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdExport ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-02-14 01:10:00 +00:00
cmd := rcli . Subcmd ( stdout ,
2013-03-21 08:23:00 +00:00
"export" , "CONTAINER" ,
"Export the contents of a filesystem as a tar archive" )
2013-02-14 01:10:00 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
name := cmd . Arg ( 0 )
2013-03-21 07:41:15 +00:00
if container := srv . runtime . Get ( name ) ; container != nil {
2013-03-21 07:25:00 +00:00
data , err := container . Export ( )
2013-02-14 01:10:00 +00:00
if err != nil {
return err
}
// Stream the entire contents of the container (basically a volatile snapshot)
if _ , err := io . Copy ( stdout , data ) ; err != nil {
return err
}
return nil
}
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container: %s" , name )
2013-02-14 01:10:00 +00:00
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdDiff ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-02-14 01:10:00 +00:00
cmd := rcli . Subcmd ( stdout ,
2013-04-12 10:26:31 +00:00
"diff" , "CONTAINER" ,
2013-02-14 01:10:00 +00:00
"Inspect changes on a container's filesystem" )
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 1 {
2013-04-12 10:26:31 +00:00
cmd . Usage ( )
return nil
2013-02-14 01:10:00 +00:00
}
2013-03-21 07:41:15 +00:00
if container := srv . runtime . Get ( cmd . Arg ( 0 ) ) ; container == nil {
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container" )
2013-02-14 01:10:00 +00:00
} else {
2013-03-21 07:25:00 +00:00
changes , err := container . Changes ( )
2013-02-14 01:10:00 +00:00
if err != nil {
return err
}
for _ , change := range changes {
fmt . Fprintln ( stdout , change . String ( ) )
}
}
return nil
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdLogs ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-04-12 10:26:31 +00:00
cmd := rcli . Subcmd ( stdout , "logs" , "CONTAINER" , "Fetch the logs of a container" )
2013-02-14 01:10:00 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) != 1 {
cmd . Usage ( )
return nil
}
name := cmd . Arg ( 0 )
2013-03-21 07:41:15 +00:00
if container := srv . runtime . Get ( name ) ; container != nil {
2013-03-29 00:12:23 +00:00
logStdout , err := container . ReadLog ( "stdout" )
2013-03-21 07:25:00 +00:00
if err != nil {
2013-02-14 01:10:00 +00:00
return err
}
2013-03-29 00:12:23 +00:00
logStderr , err := container . ReadLog ( "stderr" )
2013-03-21 07:25:00 +00:00
if err != nil {
return err
}
// FIXME: Interpolate stdout and stderr instead of concatenating them
// FIXME: Differentiate stdout and stderr in the remote protocol
2013-03-29 00:12:23 +00:00
if _ , err := io . Copy ( stdout , logStdout ) ; err != nil {
2013-03-21 07:25:00 +00:00
return err
}
2013-03-29 00:12:23 +00:00
if _ , err := io . Copy ( stdout , logStderr ) ; err != nil {
2013-02-14 01:10:00 +00:00
return err
}
return nil
}
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container: %s" , cmd . Arg ( 0 ) )
2013-02-14 01:10:00 +00:00
}
2013-04-03 19:25:19 +00:00
func ( srv * Server ) CmdAttach ( stdin io . ReadCloser , stdout rcli . DockerConn , args ... string ) error {
2013-03-29 14:49:26 +00:00
cmd := rcli . Subcmd ( stdout , "attach" , "CONTAINER" , "Attach to a running container" )
2013-02-14 01:10:00 +00:00
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) != 1 {
cmd . Usage ( )
return nil
}
name := cmd . Arg ( 0 )
2013-03-21 07:41:15 +00:00
container := srv . runtime . Get ( name )
2013-02-14 01:10:00 +00:00
if container == nil {
2013-03-29 15:19:42 +00:00
return fmt . Errorf ( "No such container: %s" , name )
2013-02-14 01:10:00 +00:00
}
2013-04-02 19:18:20 +00:00
2013-04-19 21:18:03 +00:00
if container . State . Ghost {
return fmt . Errorf ( "Impossible to attach to a ghost container" )
}
2013-04-05 04:51:40 +00:00
if container . Config . Tty {
stdout . SetOptionRawTerminal ( )
}
2013-04-09 16:59:30 +00:00
// Flush the options to make sure the client sets the raw mode
stdout . Flush ( )
2013-04-02 19:18:20 +00:00
return <- container . Attach ( stdin , nil , stdout , stdout )
2013-02-14 01:10:00 +00:00
}
2013-02-28 19:52:22 +00:00
// Ports type - Used to parse multiple -p flags
type ports [ ] int
func ( p * ports ) String ( ) string {
return fmt . Sprint ( * p )
}
func ( p * ports ) Set ( value string ) error {
port , err := strconv . Atoi ( value )
if err != nil {
return fmt . Errorf ( "Invalid port: %v" , value )
}
* p = append ( * p , port )
return nil
}
2013-03-23 03:36:34 +00: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-03 01:07:16 +00:00
// AttachOpts stores arguments to 'docker run -a', eg. which streams to attach to
type AttachOpts map [ string ] bool
2013-04-03 14:06:35 +00:00
func NewAttachOpts ( ) AttachOpts {
return make ( AttachOpts )
2013-04-03 01:07:16 +00:00
}
2013-04-03 14:06:35 +00: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-03 01:07:16 +00:00
}
2013-04-03 14:06:35 +00:00
func ( opts AttachOpts ) Set ( val string ) error {
2013-04-03 01:07:16 +00:00
if val != "stdin" && val != "stdout" && val != "stderr" {
return fmt . Errorf ( "Unsupported stream name: %s" , val )
}
2013-04-03 14:06:35 +00:00
opts [ val ] = true
2013-04-03 01:07:16 +00:00
return nil
}
2013-04-03 14:06:35 +00:00
func ( opts AttachOpts ) Get ( val string ) bool {
if res , exists := opts [ val ] ; exists {
2013-04-03 01:07:16 +00:00
return res
}
return false
}
2013-04-05 03:19:06 +00:00
func ( srv * Server ) CmdTag ( stdin io . ReadCloser , stdout io . Writer , args ... string ) error {
2013-03-23 01:27:18 +00:00
cmd := rcli . Subcmd ( stdout , "tag" , "[OPTIONS] IMAGE REPOSITORY [TAG]" , "Tag an image into a repository" )
force := cmd . Bool ( "f" , false , "Force" )
if err := cmd . Parse ( args ) ; err != nil {
return nil
}
if cmd . NArg ( ) < 2 {
cmd . Usage ( )
return nil
}
return srv . runtime . repositories . Set ( cmd . Arg ( 1 ) , cmd . Arg ( 2 ) , cmd . Arg ( 0 ) , * force )
}
2013-04-03 19:25:19 +00:00
func ( srv * Server ) CmdRun ( stdin io . ReadCloser , stdout rcli . DockerConn , args ... string ) error {
2013-04-19 03:55:41 +00:00
config , err := ParseRun ( args , stdout , srv . runtime . capabilities )
2013-03-23 19:16:58 +00:00
if err != nil {
return err
2013-02-14 01:10:00 +00:00
}
2013-03-23 19:39:09 +00:00
if config . Image == "" {
2013-03-26 15:31:26 +00:00
fmt . Fprintln ( stdout , "Error: Image not specified" )
2013-03-23 19:16:58 +00:00
return fmt . Errorf ( "Image not specified" )
}
2013-04-06 02:48:49 +00:00
2013-04-05 04:51:40 +00:00
if config . Tty {
stdout . SetOptionRawTerminal ( )
}
2013-04-09 16:59:30 +00:00
// Flush the options to make sure the client sets the raw mode
// or tell the client there is no options
stdout . Flush ( )
2013-03-26 10:05:10 +00:00
2013-02-14 01:10:00 +00:00
// Create new container
2013-03-23 19:39:09 +00:00
container , err := srv . runtime . Create ( config )
2013-02-14 01:10:00 +00:00
if err != nil {
2013-03-26 10:05:10 +00:00
// If container not found, try to pull it
2013-03-26 12:28:17 +00:00
if srv . runtime . graph . IsNotExist ( err ) {
2013-04-13 22:03:24 +00:00
fmt . Fprintf ( stdout , "Image %s not found, trying to pull it from registry.\r\n" , config . Image )
2013-03-26 12:28:17 +00:00
if err = srv . CmdPull ( stdin , stdout , config . Image ) ; err != nil {
return err
}
if container , err = srv . runtime . Create ( config ) ; err != nil {
return err
}
} else {
2013-03-26 10:05:10 +00:00
return err
}
2013-02-14 01:10:00 +00:00
}
2013-04-03 01:07:16 +00:00
var (
2013-04-02 19:18:20 +00:00
cStdin io . ReadCloser
2013-04-03 01:07:16 +00:00
cStdout , cStderr io . Writer
)
if config . AttachStdin {
2013-04-02 19:18:20 +00:00
r , w := io . Pipe ( )
go func ( ) {
defer w . Close ( )
defer Debugf ( "Closing buffered stdin pipe" )
io . Copy ( w , stdin )
} ( )
cStdin = r
2013-02-14 01:10:00 +00:00
}
2013-04-03 01:07:16 +00:00
if config . AttachStdout {
cStdout = stdout
}
if config . AttachStderr {
cStderr = stdout // FIXME: rcli can't differentiate stdout from stderr
2013-04-02 06:52:20 +00:00
}
2013-04-02 19:18:20 +00:00
attachErr := container . Attach ( cStdin , stdin , cStdout , cStderr )
2013-04-03 01:07:16 +00:00
Debugf ( "Starting\n" )
2013-04-02 06:52:20 +00:00
if err := container . Start ( ) ; err != nil {
return err
2013-02-14 01:10:00 +00:00
}
2013-04-03 01:07:16 +00:00
if cStdout == nil && cStderr == nil {
2013-03-31 09:02:01 +00:00
fmt . Fprintln ( stdout , container . ShortId ( ) )
2013-02-14 01:10:00 +00:00
}
2013-04-03 01:07:16 +00:00
Debugf ( "Waiting for attach to return\n" )
2013-04-02 19:21:35 +00:00
<- attachErr
// Expecting I/O pipe error, discarding
2013-04-22 18:16:32 +00:00
// If we are in stdinonce mode, wait for the process to end
// otherwise, simply return
if config . StdinOnce && ! config . Tty {
container . Wait ( )
}
2013-04-02 19:21:35 +00:00
return nil
2013-02-14 01:10:00 +00:00
}
2013-04-25 02:01:23 +00:00
func NewServer ( autoRestart bool ) ( * Server , error ) {
2013-03-21 09:04:10 +00:00
if runtime . GOARCH != "amd64" {
log . Fatalf ( "The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting." , runtime . GOARCH )
}
2013-04-25 02:01:23 +00:00
runtime , err := NewRuntime ( autoRestart )
2013-02-14 01:10:00 +00:00
if err != nil {
return nil , err
}
srv := & Server {
2013-03-21 07:41:15 +00:00
runtime : runtime ,
2013-02-14 01:10:00 +00:00
}
return srv , nil
}
type Server struct {
2013-03-21 07:41:15 +00:00
runtime * Runtime
2013-02-14 01:10:00 +00:00
}