|
@@ -33,30 +33,25 @@ func (srv *Server) Close() error {
|
|
}
|
|
}
|
|
|
|
|
|
func init() {
|
|
func init() {
|
|
- engine.Register("serveapi", JobServeApi)
|
|
|
|
|
|
+ engine.Register("initapi", jobInitApi)
|
|
}
|
|
}
|
|
|
|
|
|
-func JobServeApi(job *engine.Job) string {
|
|
|
|
- srv, err := NewServer(ConfigFromJob(job))
|
|
|
|
|
|
+// jobInitApi runs the remote api server `srv` as a daemon,
|
|
|
|
+// Only one api server can run at the same time - this is enforced by a pidfile.
|
|
|
|
+// The signals SIGINT, SIGKILL and SIGTERM are intercepted for cleanup.
|
|
|
|
+func jobInitApi(job *engine.Job) string {
|
|
|
|
+ job.Logf("Creating server")
|
|
|
|
+ srv, err := NewServer(job.Eng, ConfigFromJob(job))
|
|
if err != nil {
|
|
if err != nil {
|
|
return err.Error()
|
|
return err.Error()
|
|
}
|
|
}
|
|
- defer srv.Close()
|
|
|
|
- if err := srv.Daemon(); err != nil {
|
|
|
|
- return err.Error()
|
|
|
|
- }
|
|
|
|
- return "0"
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// Daemon runs the remote api server `srv` as a daemon,
|
|
|
|
-// Only one api server can run at the same time - this is enforced by a pidfile.
|
|
|
|
-// The signals SIGINT, SIGKILL and SIGTERM are intercepted for cleanup.
|
|
|
|
-func (srv *Server) Daemon() error {
|
|
|
|
- if err := utils.CreatePidFile(srv.runtime.config.Pidfile); err != nil {
|
|
|
|
- log.Fatal(err)
|
|
|
|
|
|
+ if srv.runtime.config.Pidfile != "" {
|
|
|
|
+ job.Logf("Creating pidfile")
|
|
|
|
+ if err := utils.CreatePidFile(srv.runtime.config.Pidfile); err != nil {
|
|
|
|
+ log.Fatal(err)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- defer utils.RemovePidFile(srv.runtime.config.Pidfile)
|
|
|
|
-
|
|
|
|
|
|
+ job.Logf("Setting up signal traps")
|
|
c := make(chan os.Signal, 1)
|
|
c := make(chan os.Signal, 1)
|
|
signal.Notify(c, os.Interrupt, os.Kill, os.Signal(syscall.SIGTERM))
|
|
signal.Notify(c, os.Interrupt, os.Kill, os.Signal(syscall.SIGTERM))
|
|
go func() {
|
|
go func() {
|
|
@@ -66,8 +61,21 @@ func (srv *Server) Daemon() error {
|
|
srv.Close()
|
|
srv.Close()
|
|
os.Exit(0)
|
|
os.Exit(0)
|
|
}()
|
|
}()
|
|
|
|
+ job.Eng.Hack_SetGlobalVar("httpapi.server", srv)
|
|
|
|
+ if err := job.Eng.Register("create", srv.ContainerCreate); err != nil {
|
|
|
|
+ return err.Error()
|
|
|
|
+ }
|
|
|
|
+ if err := job.Eng.Register("start", srv.ContainerStart); err != nil {
|
|
|
|
+ return err.Error()
|
|
|
|
+ }
|
|
|
|
+ if err := job.Eng.Register("serveapi", srv.ListenAndServe); err != nil {
|
|
|
|
+ return err.Error()
|
|
|
|
+ }
|
|
|
|
+ return "0"
|
|
|
|
+}
|
|
|
|
|
|
- protoAddrs := srv.runtime.config.ProtoAddresses
|
|
|
|
|
|
+func (srv *Server) ListenAndServe(job *engine.Job) string {
|
|
|
|
+ protoAddrs := job.Args
|
|
chErrors := make(chan error, len(protoAddrs))
|
|
chErrors := make(chan error, len(protoAddrs))
|
|
for _, protoAddr := range protoAddrs {
|
|
for _, protoAddr := range protoAddrs {
|
|
protoAddrParts := strings.SplitN(protoAddr, "://", 2)
|
|
protoAddrParts := strings.SplitN(protoAddr, "://", 2)
|
|
@@ -81,19 +89,20 @@ func (srv *Server) Daemon() error {
|
|
log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
|
|
log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
|
|
}
|
|
}
|
|
default:
|
|
default:
|
|
- return fmt.Errorf("Invalid protocol format.")
|
|
|
|
|
|
+ return "Invalid protocol format."
|
|
}
|
|
}
|
|
go func() {
|
|
go func() {
|
|
- chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], srv, true)
|
|
|
|
|
|
+ // FIXME: merge Server.ListenAndServe with ListenAndServe
|
|
|
|
+ chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], srv, job.GetenvBool("Logging"))
|
|
}()
|
|
}()
|
|
}
|
|
}
|
|
for i := 0; i < len(protoAddrs); i += 1 {
|
|
for i := 0; i < len(protoAddrs); i += 1 {
|
|
err := <-chErrors
|
|
err := <-chErrors
|
|
if err != nil {
|
|
if err != nil {
|
|
- return err
|
|
|
|
|
|
+ return err.Error()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- return nil
|
|
|
|
|
|
+ return "0"
|
|
}
|
|
}
|
|
|
|
|
|
func (srv *Server) DockerVersion() APIVersion {
|
|
func (srv *Server) DockerVersion() APIVersion {
|
|
@@ -154,7 +163,7 @@ func (srv *Server) ContainerKill(name string, sig int) error {
|
|
if err := container.Kill(); err != nil {
|
|
if err := container.Kill(); err != nil {
|
|
return fmt.Errorf("Cannot kill container %s: %s", name, err)
|
|
return fmt.Errorf("Cannot kill container %s: %s", name, err)
|
|
}
|
|
}
|
|
- srv.LogEvent("kill", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
|
|
|
|
|
|
+ srv.LogEvent("kill", container.ID, srv.runtime.repositories.ImageName(container.Image))
|
|
} else {
|
|
} else {
|
|
// Otherwise, just send the requested signal
|
|
// Otherwise, just send the requested signal
|
|
if err := container.kill(sig); err != nil {
|
|
if err := container.kill(sig); err != nil {
|
|
@@ -180,7 +189,7 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error {
|
|
if _, err := io.Copy(out, data); err != nil {
|
|
if _, err := io.Copy(out, data); err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
- srv.LogEvent("export", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
|
|
|
|
|
|
+ srv.LogEvent("export", container.ID, srv.runtime.repositories.ImageName(container.Image))
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
return fmt.Errorf("No such container: %s", name)
|
|
return fmt.Errorf("No such container: %s", name)
|
|
@@ -198,39 +207,39 @@ func (srv *Server) ImagesSearch(term string) ([]registry.SearchResult, error) {
|
|
return results.Results, nil
|
|
return results.Results, nil
|
|
}
|
|
}
|
|
|
|
|
|
-func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.StreamFormatter) (string, error) {
|
|
|
|
|
|
+func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.StreamFormatter) error {
|
|
out = utils.NewWriteFlusher(out)
|
|
out = utils.NewWriteFlusher(out)
|
|
img, err := srv.runtime.repositories.LookupImage(name)
|
|
img, err := srv.runtime.repositories.LookupImage(name)
|
|
if err != nil {
|
|
if err != nil {
|
|
- return "", err
|
|
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
|
|
|
|
file, err := utils.Download(url, out)
|
|
file, err := utils.Download(url, out)
|
|
if err != nil {
|
|
if err != nil {
|
|
- return "", err
|
|
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
defer file.Body.Close()
|
|
defer file.Body.Close()
|
|
|
|
|
|
config, _, _, err := ParseRun([]string{img.ID, "echo", "insert", url, path}, srv.runtime.capabilities)
|
|
config, _, _, err := ParseRun([]string{img.ID, "echo", "insert", url, path}, srv.runtime.capabilities)
|
|
if err != nil {
|
|
if err != nil {
|
|
- return "", err
|
|
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
|
|
|
|
c, _, err := srv.runtime.Create(config, "")
|
|
c, _, err := srv.runtime.Create(config, "")
|
|
if err != nil {
|
|
if err != nil {
|
|
- return "", err
|
|
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
|
|
|
|
- if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, sf.FormatProgress("", "Downloading", "%8v/%v (%v)"), sf, true), path); err != nil {
|
|
|
|
- return "", err
|
|
|
|
|
|
+ if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, sf.FormatProgress("", "Downloading", "%8v/%v (%v)"), sf, false), path); err != nil {
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
// FIXME: Handle custom repo, tag comment, author
|
|
// FIXME: Handle custom repo, tag comment, author
|
|
img, err = srv.runtime.Commit(c, "", "", img.Comment, img.Author, nil)
|
|
img, err = srv.runtime.Commit(c, "", "", img.Comment, img.Author, nil)
|
|
if err != nil {
|
|
if err != nil {
|
|
- return "", err
|
|
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
- out.Write(sf.FormatStatus("", img.ID))
|
|
|
|
- return img.ShortID(), nil
|
|
|
|
|
|
+ out.Write(sf.FormatStatus(img.ID, ""))
|
|
|
|
+ return nil
|
|
}
|
|
}
|
|
|
|
|
|
func (srv *Server) ImagesViz(out io.Writer) error {
|
|
func (srv *Server) ImagesViz(out io.Writer) error {
|
|
@@ -250,9 +259,9 @@ func (srv *Server) ImagesViz(out io.Writer) error {
|
|
return fmt.Errorf("Error while getting parent image: %v", err)
|
|
return fmt.Errorf("Error while getting parent image: %v", err)
|
|
}
|
|
}
|
|
if parentImage != nil {
|
|
if parentImage != nil {
|
|
- out.Write([]byte(" \"" + parentImage.ShortID() + "\" -> \"" + image.ShortID() + "\"\n"))
|
|
|
|
|
|
+ out.Write([]byte(" \"" + parentImage.ID + "\" -> \"" + image.ID + "\"\n"))
|
|
} else {
|
|
} else {
|
|
- out.Write([]byte(" base -> \"" + image.ShortID() + "\" [style=invis]\n"))
|
|
|
|
|
|
+ out.Write([]byte(" base -> \"" + image.ID + "\" [style=invis]\n"))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -465,7 +474,7 @@ func (srv *Server) Containers(all, size bool, n int, since, before string) []API
|
|
continue
|
|
continue
|
|
}
|
|
}
|
|
if before != "" {
|
|
if before != "" {
|
|
- if container.ShortID() == before {
|
|
|
|
|
|
+ if container.ID == before || utils.TruncateID(container.ID) == before {
|
|
foundBefore = true
|
|
foundBefore = true
|
|
continue
|
|
continue
|
|
}
|
|
}
|
|
@@ -476,7 +485,7 @@ func (srv *Server) Containers(all, size bool, n int, since, before string) []API
|
|
if displayed == n {
|
|
if displayed == n {
|
|
break
|
|
break
|
|
}
|
|
}
|
|
- if container.ShortID() == since {
|
|
|
|
|
|
+ if container.ID == since || utils.TruncateID(container.ID) == since {
|
|
break
|
|
break
|
|
}
|
|
}
|
|
displayed++
|
|
displayed++
|
|
@@ -518,7 +527,7 @@ func (srv *Server) ContainerCommit(name, repo, tag, author, comment string, conf
|
|
if err != nil {
|
|
if err != nil {
|
|
return "", err
|
|
return "", err
|
|
}
|
|
}
|
|
- return img.ShortID(), err
|
|
|
|
|
|
+ return img.ID, err
|
|
}
|
|
}
|
|
|
|
|
|
func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
|
|
func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
|
|
@@ -1018,37 +1027,47 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- out.Write(sf.FormatStatus("", img.ShortID()))
|
|
|
|
|
|
+ out.Write(sf.FormatStatus("", img.ID))
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
-func (srv *Server) ContainerCreate(config *Config, name string) (string, []string, error) {
|
|
|
|
|
|
+func (srv *Server) ContainerCreate(job *engine.Job) string {
|
|
|
|
+ var name string
|
|
|
|
+ if len(job.Args) == 1 {
|
|
|
|
+ name = job.Args[0]
|
|
|
|
+ } else if len(job.Args) > 1 {
|
|
|
|
+ return fmt.Sprintf("Usage: %s ", job.Name)
|
|
|
|
+ }
|
|
|
|
+ var config Config
|
|
|
|
+ if err := job.ExportEnv(&config); err != nil {
|
|
|
|
+ return err.Error()
|
|
|
|
+ }
|
|
if config.Memory != 0 && config.Memory < 524288 {
|
|
if config.Memory != 0 && config.Memory < 524288 {
|
|
- return "", nil, fmt.Errorf("Memory limit must be given in bytes (minimum 524288 bytes)")
|
|
|
|
|
|
+ return "Minimum memory limit allowed is 512k"
|
|
}
|
|
}
|
|
-
|
|
|
|
if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
|
|
if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
|
|
config.Memory = 0
|
|
config.Memory = 0
|
|
}
|
|
}
|
|
-
|
|
|
|
if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
|
|
if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
|
|
config.MemorySwap = -1
|
|
config.MemorySwap = -1
|
|
}
|
|
}
|
|
- container, buildWarnings, err := srv.runtime.Create(config, name)
|
|
|
|
|
|
+ container, buildWarnings, err := srv.runtime.Create(&config, name)
|
|
if err != nil {
|
|
if err != nil {
|
|
if srv.runtime.graph.IsNotExist(err) {
|
|
if srv.runtime.graph.IsNotExist(err) {
|
|
-
|
|
|
|
_, tag := utils.ParseRepositoryTag(config.Image)
|
|
_, tag := utils.ParseRepositoryTag(config.Image)
|
|
if tag == "" {
|
|
if tag == "" {
|
|
tag = DEFAULTTAG
|
|
tag = DEFAULTTAG
|
|
}
|
|
}
|
|
-
|
|
|
|
- return "", nil, fmt.Errorf("No such image: %s (tag: %s)", config.Image, tag)
|
|
|
|
|
|
+ return fmt.Sprintf("No such image: %s (tag: %s)", config.Image, tag)
|
|
}
|
|
}
|
|
- return "", nil, err
|
|
|
|
|
|
+ return err.Error()
|
|
|
|
+ }
|
|
|
|
+ srv.LogEvent("create", container.ID, srv.runtime.repositories.ImageName(container.Image))
|
|
|
|
+ job.Printf("%s\n", container.ID)
|
|
|
|
+ for _, warning := range buildWarnings {
|
|
|
|
+ job.Errorf("%s\n", warning)
|
|
}
|
|
}
|
|
- srv.LogEvent("create", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
|
|
|
|
- return container.ShortID(), buildWarnings, nil
|
|
|
|
|
|
+ return "0"
|
|
}
|
|
}
|
|
|
|
|
|
func (srv *Server) ContainerRestart(name string, t int) error {
|
|
func (srv *Server) ContainerRestart(name string, t int) error {
|
|
@@ -1056,7 +1075,7 @@ func (srv *Server) ContainerRestart(name string, t int) error {
|
|
if err := container.Restart(t); err != nil {
|
|
if err := container.Restart(t); err != nil {
|
|
return fmt.Errorf("Cannot restart container %s: %s", name, err)
|
|
return fmt.Errorf("Cannot restart container %s: %s", name, err)
|
|
}
|
|
}
|
|
- srv.LogEvent("restart", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
|
|
|
|
|
|
+ srv.LogEvent("restart", container.ID, srv.runtime.repositories.ImageName(container.Image))
|
|
} else {
|
|
} else {
|
|
return fmt.Errorf("No such container: %s", name)
|
|
return fmt.Errorf("No such container: %s", name)
|
|
}
|
|
}
|
|
@@ -1112,7 +1131,7 @@ func (srv *Server) ContainerDestroy(name string, removeVolume, removeLink bool)
|
|
if err := srv.runtime.Destroy(container); err != nil {
|
|
if err := srv.runtime.Destroy(container); err != nil {
|
|
return fmt.Errorf("Cannot destroy container %s: %s", name, err)
|
|
return fmt.Errorf("Cannot destroy container %s: %s", name, err)
|
|
}
|
|
}
|
|
- srv.LogEvent("destroy", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
|
|
|
|
|
|
+ srv.LogEvent("destroy", container.ID, srv.runtime.repositories.ImageName(container.Image))
|
|
|
|
|
|
if removeVolume {
|
|
if removeVolume {
|
|
// Retrieve all volumes from all remaining containers
|
|
// Retrieve all volumes from all remaining containers
|
|
@@ -1229,8 +1248,8 @@ func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, erro
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
if tagDeleted {
|
|
if tagDeleted {
|
|
- imgs = append(imgs, APIRmi{Untagged: img.ShortID()})
|
|
|
|
- srv.LogEvent("untag", img.ShortID(), "")
|
|
|
|
|
|
+ imgs = append(imgs, APIRmi{Untagged: img.ID})
|
|
|
|
+ srv.LogEvent("untag", img.ID, "")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if len(srv.runtime.repositories.ByID()[img.ID]) == 0 {
|
|
if len(srv.runtime.repositories.ByID()[img.ID]) == 0 {
|
|
@@ -1258,6 +1277,26 @@ func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
|
|
}
|
|
}
|
|
return nil, nil
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // Prevent deletion if image is used by a running container
|
|
|
|
+ for _, container := range srv.runtime.List() {
|
|
|
|
+ if container.State.Running {
|
|
|
|
+ parent, err := srv.runtime.repositories.LookupImage(container.Image)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if err := parent.WalkHistory(func(p *Image) error {
|
|
|
|
+ if img.ID == p.ID {
|
|
|
|
+ return fmt.Errorf("Conflict, cannot delete %s because the running container %s is using it", name, container.ID)
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+ }); err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
if strings.Contains(img.ID, name) {
|
|
if strings.Contains(img.ID, name) {
|
|
//delete via ID
|
|
//delete via ID
|
|
return srv.deleteImage(img, "", "")
|
|
return srv.deleteImage(img, "", "")
|
|
@@ -1303,7 +1342,6 @@ func (srv *Server) RegisterLinks(name string, hostConfig *HostConfig) error {
|
|
return fmt.Errorf("No such container: %s", name)
|
|
return fmt.Errorf("No such container: %s", name)
|
|
}
|
|
}
|
|
|
|
|
|
- // Register links
|
|
|
|
if hostConfig != nil && hostConfig.Links != nil {
|
|
if hostConfig != nil && hostConfig.Links != nil {
|
|
for _, l := range hostConfig.Links {
|
|
for _, l := range hostConfig.Links {
|
|
parts, err := parseLink(l)
|
|
parts, err := parseLink(l)
|
|
@@ -1317,7 +1355,6 @@ func (srv *Server) RegisterLinks(name string, hostConfig *HostConfig) error {
|
|
if child == nil {
|
|
if child == nil {
|
|
return fmt.Errorf("Could not get container for %s", parts["name"])
|
|
return fmt.Errorf("Could not get container for %s", parts["name"])
|
|
}
|
|
}
|
|
-
|
|
|
|
if err := runtime.RegisterLink(container, child, parts["alias"]); err != nil {
|
|
if err := runtime.RegisterLink(container, child, parts["alias"]); err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
@@ -1333,41 +1370,57 @@ func (srv *Server) RegisterLinks(name string, hostConfig *HostConfig) error {
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
-func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
|
|
|
|
|
|
+func (srv *Server) ContainerStart(job *engine.Job) string {
|
|
|
|
+ if len(job.Args) < 1 {
|
|
|
|
+ return fmt.Sprintf("Usage: %s container_id", job.Name)
|
|
|
|
+ }
|
|
|
|
+ name := job.Args[0]
|
|
runtime := srv.runtime
|
|
runtime := srv.runtime
|
|
container := runtime.Get(name)
|
|
container := runtime.Get(name)
|
|
|
|
|
|
- if hostConfig != nil {
|
|
|
|
|
|
+ if container == nil {
|
|
|
|
+ return fmt.Sprintf("No such container: %s", name)
|
|
|
|
+ }
|
|
|
|
+ // If no environment was set, then no hostconfig was passed.
|
|
|
|
+ if len(job.Environ()) > 0 {
|
|
|
|
+ var hostConfig HostConfig
|
|
|
|
+ if err := job.ExportEnv(&hostConfig); err != nil {
|
|
|
|
+ return err.Error()
|
|
|
|
+ }
|
|
|
|
+ // Validate the HostConfig binds. Make sure that:
|
|
|
|
+ // 1) the source of a bind mount isn't /
|
|
|
|
+ // The bind mount "/:/foo" isn't allowed.
|
|
|
|
+ // 2) Check that the source exists
|
|
|
|
+ // The source to be bind mounted must exist.
|
|
for _, bind := range hostConfig.Binds {
|
|
for _, bind := range hostConfig.Binds {
|
|
splitBind := strings.Split(bind, ":")
|
|
splitBind := strings.Split(bind, ":")
|
|
source := splitBind[0]
|
|
source := splitBind[0]
|
|
|
|
|
|
// refuse to bind mount "/" to the container
|
|
// refuse to bind mount "/" to the container
|
|
if source == "/" {
|
|
if source == "/" {
|
|
- return fmt.Errorf("Invalid bind mount '%s' : source can't be '/'", bind)
|
|
|
|
|
|
+ return fmt.Sprintf("Invalid bind mount '%s' : source can't be '/'", bind)
|
|
}
|
|
}
|
|
|
|
|
|
// ensure the source exists on the host
|
|
// ensure the source exists on the host
|
|
_, err := os.Stat(source)
|
|
_, err := os.Stat(source)
|
|
if err != nil && os.IsNotExist(err) {
|
|
if err != nil && os.IsNotExist(err) {
|
|
- return fmt.Errorf("Invalid bind mount '%s' : source doesn't exist", bind)
|
|
|
|
|
|
+ return fmt.Sprintf("Invalid bind mount '%s' : source doesn't exist", bind)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- }
|
|
|
|
-
|
|
|
|
- if container == nil {
|
|
|
|
- return fmt.Errorf("No such container: %s", name)
|
|
|
|
- }
|
|
|
|
- if hostConfig != nil {
|
|
|
|
- container.hostConfig = hostConfig
|
|
|
|
|
|
+ // Register any links from the host config before starting the container
|
|
|
|
+ // FIXME: we could just pass the container here, no need to lookup by name again.
|
|
|
|
+ if err := srv.RegisterLinks(name, &hostConfig); err != nil {
|
|
|
|
+ return err.Error()
|
|
|
|
+ }
|
|
|
|
+ container.hostConfig = &hostConfig
|
|
container.ToDisk()
|
|
container.ToDisk()
|
|
}
|
|
}
|
|
if err := container.Start(); err != nil {
|
|
if err := container.Start(); err != nil {
|
|
- return fmt.Errorf("Cannot start container %s: %s", name, err)
|
|
|
|
|
|
+ return fmt.Sprintf("Cannot start container %s: %s", name, err)
|
|
}
|
|
}
|
|
- srv.LogEvent("start", container.ShortID(), runtime.repositories.ImageName(container.Image))
|
|
|
|
|
|
+ srv.LogEvent("start", container.ID, runtime.repositories.ImageName(container.Image))
|
|
|
|
|
|
- return nil
|
|
|
|
|
|
+ return "0"
|
|
}
|
|
}
|
|
|
|
|
|
func (srv *Server) ContainerStop(name string, t int) error {
|
|
func (srv *Server) ContainerStop(name string, t int) error {
|
|
@@ -1375,7 +1428,7 @@ func (srv *Server) ContainerStop(name string, t int) error {
|
|
if err := container.Stop(t); err != nil {
|
|
if err := container.Stop(t); err != nil {
|
|
return fmt.Errorf("Cannot stop container %s: %s", name, err)
|
|
return fmt.Errorf("Cannot stop container %s: %s", name, err)
|
|
}
|
|
}
|
|
- srv.LogEvent("stop", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
|
|
|
|
|
|
+ srv.LogEvent("stop", container.ID, srv.runtime.repositories.ImageName(container.Image))
|
|
} else {
|
|
} else {
|
|
return fmt.Errorf("No such container: %s", name)
|
|
return fmt.Errorf("No such container: %s", name)
|
|
}
|
|
}
|
|
@@ -1518,12 +1571,13 @@ func (srv *Server) ContainerCopy(name string, resource string, out io.Writer) er
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-func NewServer(config *DaemonConfig) (*Server, error) {
|
|
|
|
|
|
+func NewServer(eng *engine.Engine, config *DaemonConfig) (*Server, error) {
|
|
runtime, err := NewRuntime(config)
|
|
runtime, err := NewRuntime(config)
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
srv := &Server{
|
|
srv := &Server{
|
|
|
|
+ Eng: eng,
|
|
runtime: runtime,
|
|
runtime: runtime,
|
|
pullingPool: make(map[string]struct{}),
|
|
pullingPool: make(map[string]struct{}),
|
|
pushingPool: make(map[string]struct{}),
|
|
pushingPool: make(map[string]struct{}),
|
|
@@ -1567,4 +1621,5 @@ type Server struct {
|
|
events []utils.JSONMessage
|
|
events []utils.JSONMessage
|
|
listeners map[string]chan utils.JSONMessage
|
|
listeners map[string]chan utils.JSONMessage
|
|
reqFactory *utils.HTTPRequestFactory
|
|
reqFactory *utils.HTTPRequestFactory
|
|
|
|
+ Eng *engine.Engine
|
|
}
|
|
}
|