diff --git a/docs/yaml.md b/docs/yaml.md index 396106931..1980e38c3 100644 --- a/docs/yaml.md +++ b/docs/yaml.md @@ -10,8 +10,8 @@ The yaml configuration specifies the components used to build up an image . All are downloaded at build time to create an image. The image is self-contained and immutable, so it can be tested reliably for continuous delivery. -The configuration file is processed in the order `kernel`, `init`, `onboot`, `services`, `files`. -Each section adds file to the root file system. Sections may be omitted. +The configuration file is processed in the order `kernel`, `init`, `onboot`, `onshutdown`, +`services`, `files`. Each section adds files to the root file system. Sections may be omitted. Each container that is specified is allocated a unique `uid` and `gid` that it may use if it wishes to run as an isolated user (or user namespace). Anywhere you specify a `uid` or `gid` @@ -62,6 +62,15 @@ images. They are run sequentially and each must exit before the next one is run. These images can be used to configure one shot settings. See [Image specification](#image-specification) for a list of supported fields. +## `onshutdown` + +This is a list of images to run on a clean shutdown. Note that you must not rely on these +being run at all, as machines may be be powered off or shut down without having time to run +these scripts. If you add anything here you should test both in the case where they are +run and when they are not. Most systems are likely to be "crash only" and not have any setup here, +but you can attempt to deregister cleanly from a network service here, rather than relying +on timeouts, for example. + ## `services` The `services` section is a list of images for long running services which are diff --git a/src/moby/build.go b/src/moby/build.go index 9312733ed..15f0ec04d 100644 --- a/src/moby/build.go +++ b/src/moby/build.go @@ -133,6 +133,10 @@ func Build(m Moby, w io.Writer, pull bool, tp string) error { idMap[image.Name] = id id++ } + for _, image := range m.Onshutdown { + idMap[image.Name] = id + id++ + } for _, image := range m.Services { idMap[image.Name] = id id++ @@ -182,6 +186,24 @@ func Build(m Moby, w io.Writer, pull bool, tp string) error { } } + if len(m.Onshutdown) != 0 { + log.Infof("Add onshutdown containers:") + } + for i, image := range m.Onshutdown { + log.Infof(" Create OCI config for %s", image.Image) + useTrust := enforceContentTrust(image.Image, &m.Trust) + config, err := ConfigToOCI(image, useTrust, idMap) + if err != nil { + return fmt.Errorf("Failed to create config.json for %s: %v", image.Image, err) + } + so := fmt.Sprintf("%03d", i) + path := "containers/onshutdown/" + so + "-" + image.Name + err = ImageBundle(path, image.Image, config, iw, useTrust, pull) + if err != nil { + return fmt.Errorf("Failed to extract root filesystem for %s: %v", image.Image, err) + } + } + if len(m.Services) != 0 { log.Infof("Add service containers:") } diff --git a/src/moby/config.go b/src/moby/config.go index be23975d5..1f1caa2a2 100644 --- a/src/moby/config.go +++ b/src/moby/config.go @@ -19,12 +19,13 @@ import ( // Moby is the type of a Moby config file type Moby struct { - Kernel KernelConfig `kernel:"cmdline" json:"kernel,omitempty"` - Init []string `init:"cmdline" json:"init"` - Onboot []Image `yaml:"onboot" json:"onboot"` - Services []Image `yaml:"services" json:"services"` - Trust TrustConfig `yaml:"trust" json:"trust,omitempty"` - Files []File `yaml:"files" json:"files"` + Kernel KernelConfig `kernel:"cmdline" json:"kernel,omitempty"` + Init []string `init:"cmdline" json:"init"` + Onboot []Image `yaml:"onboot" json:"onboot"` + Onshutdown []Image `yaml:"onshutdown" json:"onshutdown"` + Services []Image `yaml:"services" json:"services"` + Trust TrustConfig `yaml:"trust" json:"trust,omitempty"` + Files []File `yaml:"files" json:"files"` } // KernelConfig is the type of the config for a kernel @@ -182,6 +183,7 @@ func AppendConfig(m0, m1 Moby) (Moby, error) { } moby.Init = append(moby.Init, m1.Init...) moby.Onboot = append(moby.Onboot, m1.Onboot...) + moby.Onshutdown = append(moby.Onshutdown, m1.Onshutdown...) moby.Services = append(moby.Services, m1.Services...) moby.Files = append(moby.Files, m1.Files...) moby.Trust.Image = append(moby.Trust.Image, m1.Trust.Image...) diff --git a/src/moby/schema.go b/src/moby/schema.go index 700ba936a..16a81208f 100644 --- a/src/moby/schema.go +++ b/src/moby/schema.go @@ -128,6 +128,7 @@ var schema = string(` "kernel": { "$ref": "#/definitions/kernel" }, "init": { "$ref": "#/definitions/strings" }, "onboot": { "$ref": "#/definitions/images" }, + "onshutdown": { "$ref": "#/definitions/images" }, "services": { "$ref": "#/definitions/images" }, "trust": { "$ref": "#/definitions/trust" }, "files": { "$ref": "#/definitions/files" } diff --git a/test/test.yml b/test/test.yml index fadf86e9f..d2d210f36 100644 --- a/test/test.yml +++ b/test/test.yml @@ -14,6 +14,10 @@ onboot: - name: dhcpcd image: "linuxkit/dhcpcd:7d2f17a0e5d1ef9a75a527821a9ab0d753b22e7e" command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"] +onshutdown: + - name: shutdown + image: busybox:latest + command: ["/bin/echo", "so long and thanks for all the fish"] services: - name: rngd image: "linuxkit/rngd:b67c3151a52b05db50e6207b40876900f2208d14"