2013-10-21 12:04:42 -04:00
package engine
import (
"fmt"
2013-11-07 15:19:24 -05:00
"github.com/dotcloud/docker/utils"
2013-10-23 02:53:40 -04:00
"log"
2013-11-07 15:19:24 -05:00
"os"
2013-10-23 02:53:40 -04:00
"runtime"
2013-10-27 03:01:15 -04:00
"strings"
2013-10-21 12:04:42 -04:00
)
2013-11-20 02:37:03 -05:00
type Handler func ( * Job ) Status
2013-10-21 12:04:42 -04:00
var globalHandlers map [ string ] Handler
2013-10-26 22:24:01 -04:00
func init ( ) {
globalHandlers = make ( map [ string ] Handler )
}
2013-10-21 12:04:42 -04:00
func Register ( name string , handler Handler ) error {
2013-10-27 02:54:51 -04:00
_ , exists := globalHandlers [ name ]
if exists {
return fmt . Errorf ( "Can't overwrite global handler for command %s" , name )
2013-10-21 12:04:42 -04:00
}
globalHandlers [ name ] = handler
return nil
}
// The Engine is the core of Docker.
// It acts as a store for *containers*, and allows manipulation of these
// containers by executing *jobs*.
type Engine struct {
2013-11-13 14:25:55 -05:00
root string
handlers map [ string ] Handler
hack Hack // data for temporary hackery (see hack.go)
id string
2013-10-27 03:01:15 -04:00
}
func ( eng * Engine ) Root ( ) string {
return eng . root
2013-10-21 12:04:42 -04:00
}
2013-10-27 02:54:51 -04:00
func ( eng * Engine ) Register ( name string , handler Handler ) error {
eng . Logf ( "Register(%s) (handlers=%v)" , name , eng . handlers )
_ , exists := eng . handlers [ name ]
if exists {
return fmt . Errorf ( "Can't overwrite handler for command %s" , name )
}
eng . handlers [ name ] = handler
return nil
2013-10-21 12:04:42 -04:00
}
// New initializes a new engine managing the directory specified at `root`.
// `root` is used to store containers and any other state private to the engine.
// Changing the contents of the root without executing a job will cause unspecified
// behavior.
func New ( root string ) ( * Engine , error ) {
2013-10-23 02:53:40 -04:00
// Check for unsupported architectures
if runtime . GOARCH != "amd64" {
return nil , fmt . Errorf ( "The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting." , runtime . GOARCH )
}
// Check for unsupported kernel versions
// FIXME: it would be cleaner to not test for specific versions, but rather
// test for specific functionalities.
// Unfortunately we can't test for the feature "does not cause a kernel panic"
// without actually causing a kernel panic, so we need this workaround until
// the circumstances of pre-3.8 crashes are clearer.
// For details see http://github.com/dotcloud/docker/issues/407
if k , err := utils . GetKernelVersion ( ) ; err != nil {
log . Printf ( "WARNING: %s\n" , err )
} else {
if utils . CompareKernelVersion ( k , & utils . KernelVersionInfo { Kernel : 3 , Major : 8 , Minor : 0 } ) < 0 {
log . Printf ( "WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0." , k . String ( ) )
}
}
2013-10-21 12:04:42 -04:00
if err := os . MkdirAll ( root , 0700 ) ; err != nil && ! os . IsExist ( err ) {
return nil , err
}
eng := & Engine {
2013-11-13 14:25:55 -05:00
root : root ,
handlers : make ( map [ string ] Handler ) ,
id : utils . RandomString ( ) ,
2013-10-27 02:54:51 -04:00
}
// Copy existing global handlers
for k , v := range globalHandlers {
eng . handlers [ k ] = v
2013-10-21 12:04:42 -04:00
}
return eng , nil
}
2013-10-27 03:01:15 -04:00
func ( eng * Engine ) String ( ) string {
return fmt . Sprintf ( "%s|%s" , eng . Root ( ) , eng . id [ : 8 ] )
}
2013-10-21 12:04:42 -04:00
// Job creates a new job which can later be executed.
// This function mimics `Command` from the standard os/exec package.
2013-10-26 20:49:16 -04:00
func ( eng * Engine ) Job ( name string , args ... string ) * Job {
2013-10-21 12:04:42 -04:00
job := & Job {
2013-11-13 14:25:55 -05:00
Eng : eng ,
Name : name ,
Args : args ,
2013-11-20 02:37:03 -05:00
Stdin : NewInput ( ) ,
Stdout : NewOutput ( ) ,
Stderr : NewOutput ( ) ,
2013-10-21 12:04:42 -04:00
}
2013-11-20 02:37:03 -05:00
job . Stdout . Add ( utils . NopWriteCloser ( os . Stdout ) )
job . Stderr . Add ( utils . NopWriteCloser ( os . Stderr ) )
2013-10-26 20:49:16 -04:00
handler , exists := eng . handlers [ name ]
if exists {
job . handler = handler
}
return job
2013-10-21 12:04:42 -04:00
}
2013-10-27 03:01:15 -04:00
func ( eng * Engine ) Logf ( format string , args ... interface { } ) ( n int , err error ) {
prefixedFormat := fmt . Sprintf ( "[%s] %s\n" , eng , strings . TrimRight ( format , "\n" ) )
2013-10-27 22:20:00 -04:00
return fmt . Fprintf ( os . Stderr , prefixedFormat , args ... )
2013-10-27 03:01:15 -04:00
}