1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #8827 from jlhawn/build_implied_from_scratch

Make `FROM scratch` a special cased 'no-base' spec
This commit is contained in:
Tibor Vass 2014-12-18 18:21:16 -05:00
commit 610842f906
17 changed files with 70 additions and 42 deletions

View file

@ -1696,7 +1696,12 @@ func (cli *DockerCli) CmdPs(args ...string) error {
ports.ReadListFrom([]byte(out.Get("Ports")))
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, out.Get("Image"), outCommand,
image := out.Get("Image")
if image == "" {
image = "<no image>"
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, image, outCommand,
units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))),
out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ","))

View file

@ -21,6 +21,12 @@ import (
"github.com/docker/docker/runconfig"
)
const (
// NoBaseImageSpecifier is the symbol used by the FROM
// command to specify that no base image is to be used.
NoBaseImageSpecifier string = "scratch"
)
// dispatch with no layer / parsing. This is effectively not a command.
func nullDispatch(b *Builder, args []string, attributes map[string]bool, original string) error {
return nil
@ -115,6 +121,12 @@ func from(b *Builder, args []string, attributes map[string]bool, original string
name := args[0]
if name == NoBaseImageSpecifier {
b.image = ""
b.noBaseImage = true
return nil
}
image, err := b.Daemon.Repositories().LookupImage(name)
if b.Pull {
image, err = b.pullImage(name)
@ -191,7 +203,7 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str
// RUN [ "echo", "hi" ] # echo hi
//
func run(b *Builder, args []string, attributes map[string]bool, original string) error {
if b.image == "" {
if b.image == "" && !b.noBaseImage {
return fmt.Errorf("Please provide a source image with `from` prior to run")
}

View file

@ -110,7 +110,7 @@ type Builder struct {
cmdSet bool // indicates is CMD was set in current Dockerfile
context tarsum.TarSum // the context is a tarball that is uploaded by the client
contextPath string // the path of the temporary directory the local context is unpacked to (server side)
noBaseImage bool // indicates that this build does not start from any base image, but is being built from an empty file system.
}
// Run the builder with the context. This is the lynchpin of this package. This

View file

@ -58,7 +58,7 @@ func (b *Builder) readContext(context io.Reader) error {
}
func (b *Builder) commit(id string, autoCmd []string, comment string) error {
if b.image == "" {
if b.image == "" && !b.noBaseImage {
return fmt.Errorf("Please provide a source image with `from` prior to commit")
}
b.Config.Image = b.image
@ -513,7 +513,7 @@ func (b *Builder) probeCache() (bool, error) {
}
func (b *Builder) create() (*daemon.Container, error) {
if b.image == "" {
if b.image == "" && !b.noBaseImage {
return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
}
b.Config.Image = b.image

View file

@ -59,17 +59,17 @@ func (daemon *Daemon) Commit(container *Container, repository, tag, comment, aut
// Create a new image from the container's base layers + a new layer from container changes
var (
containerID, containerImage string
containerConfig *runconfig.Config
containerID, parentImageID string
containerConfig *runconfig.Config
)
if container != nil {
containerID = container.ID
containerImage = container.Image
parentImageID = container.ImageID
containerConfig = container.Config
}
img, err := daemon.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config)
img, err := daemon.graph.Create(rwTar, containerID, parentImageID, comment, author, containerConfig, config)
if err != nil {
return nil, err
}

View file

@ -62,8 +62,8 @@ type Container struct {
Path string
Args []string
Config *runconfig.Config
Image string
Config *runconfig.Config
ImageID string `json:"Image"`
NetworkSettings *NetworkSettings
@ -186,7 +186,7 @@ func (container *Container) WriteHostConfig() error {
func (container *Container) LogEvent(action string) {
d := container.daemon
if err := d.eng.Job("log", action, container.ID, d.Repositories().ImageName(container.Image)).Run(); err != nil {
if err := d.eng.Job("log", action, container.ID, d.Repositories().ImageName(container.ImageID)).Run(); err != nil {
log.Errorf("Error logging event %s for %s: %s", action, container.ID, err)
}
}
@ -786,7 +786,7 @@ func (container *Container) GetImage() (*image.Image, error) {
if container.daemon == nil {
return nil, fmt.Errorf("Can't get image of unregistered container")
}
return container.daemon.graph.Get(container.Image)
return container.daemon.graph.Get(container.ImageID)
}
func (container *Container) Unmount() error {

View file

@ -5,6 +5,7 @@ import (
"github.com/docker/docker/engine"
"github.com/docker/docker/graph"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/runconfig"
"github.com/docker/libcontainer/label"
@ -68,15 +69,22 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
var (
container *Container
warnings []string
img *image.Image
imgID string
err error
)
img, err := daemon.repositories.LookupImage(config.Image)
if err != nil {
return nil, nil, err
}
if err := img.CheckDepth(); err != nil {
return nil, nil, err
if config.Image != "" {
img, err = daemon.repositories.LookupImage(config.Image)
if err != nil {
return nil, nil, err
}
if err = img.CheckDepth(); err != nil {
return nil, nil, err
}
imgID = img.ID
}
if warnings, err = daemon.mergeAndVerifyConfig(config, img); err != nil {
return nil, nil, err
}
@ -86,13 +94,13 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
return nil, nil, err
}
}
if container, err = daemon.newContainer(name, config, img); err != nil {
if container, err = daemon.newContainer(name, config, imgID); err != nil {
return nil, nil, err
}
if err := daemon.Register(container); err != nil {
return nil, nil, err
}
if err := daemon.createRootfs(container, img); err != nil {
if err := daemon.createRootfs(container); err != nil {
return nil, nil, err
}
if hostConfig != nil {

View file

@ -417,10 +417,10 @@ func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool {
func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image.Image) ([]string, error) {
warnings := []string{}
if daemon.checkDeprecatedExpose(img.Config) || daemon.checkDeprecatedExpose(config) {
if (img != nil && daemon.checkDeprecatedExpose(img.Config)) || daemon.checkDeprecatedExpose(config) {
warnings = append(warnings, "The mapping to public ports on your host via Dockerfile EXPOSE (host:port:port) has been deprecated. Use -p to publish the ports.")
}
if img.Config != nil {
if img != nil && img.Config != nil {
if err := runconfig.Merge(config, img.Config); err != nil {
return nil, err
}
@ -557,7 +557,7 @@ func parseSecurityOpt(container *Container, config *runconfig.HostConfig) error
return err
}
func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *image.Image) (*Container, error) {
func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID string) (*Container, error) {
var (
id string
err error
@ -578,7 +578,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *i
Args: args, //FIXME: de-duplicate from config
Config: config,
hostConfig: &runconfig.HostConfig{},
Image: img.ID, // Always use the resolved image id
ImageID: imgID,
NetworkSettings: &NetworkSettings{},
Name: name,
Driver: daemon.driver.String(),
@ -590,14 +590,14 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *i
return container, err
}
func (daemon *Daemon) createRootfs(container *Container, img *image.Image) error {
func (daemon *Daemon) createRootfs(container *Container) error {
// Step 1: create the container directory.
// This doubles as a barrier to avoid race conditions.
if err := os.Mkdir(container.root, 0700); err != nil {
return err
}
initID := fmt.Sprintf("%s-init", container.ID)
if err := daemon.driver.Create(initID, img.ID); err != nil {
if err := daemon.driver.Create(initID, container.ImageID); err != nil {
return err
}
initPath, err := daemon.driver.Get(initID, "")

View file

@ -131,7 +131,7 @@ func (daemon *Daemon) DeleteImage(eng *engine.Engine, name string, imgs *engine.
func (daemon *Daemon) canDeleteImage(imgID string, force bool) error {
for _, container := range daemon.List() {
parent, err := daemon.Repositories().LookupImage(container.Image)
parent, err := daemon.Repositories().LookupImage(container.ImageID)
if err != nil {
if daemon.Graph().IsNotExist(err) {
return nil

View file

@ -35,7 +35,7 @@ func (daemon *Daemon) ContainerInspect(job *engine.Job) engine.Status {
out.SetList("Args", container.Args)
out.SetJson("Config", container.Config)
out.SetJson("State", container.State)
out.SetJson("Image", container.Image)
out.Set("Image", container.ImageID)
out.SetJson("NetworkSettings", container.NetworkSettings)
out.Set("ResolvConfPath", container.ResolvConfPath)
out.Set("HostnamePath", container.HostnamePath)

View file

@ -116,7 +116,7 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
out := &engine.Env{}
out.SetJson("Id", container.ID)
out.SetList("Names", names[container.ID])
out.SetJson("Image", daemon.Repositories().ImageName(container.Image))
out.SetJson("Image", daemon.Repositories().ImageName(container.ImageID))
if len(container.Args) > 0 {
args := []string{}
for _, arg := range container.Args {

View file

@ -298,6 +298,9 @@ func validateRepoName(name string) error {
if name == "" {
return fmt.Errorf("Repository name can't be empty")
}
if name == "scratch" {
return fmt.Errorf("'scratch' is a reserved name")
}
return nil
}

View file

@ -230,9 +230,9 @@ func TestEventsRedirectStdout(t *testing.T) {
func TestEventsImagePull(t *testing.T) {
since := time.Now().Unix()
pullCmd := exec.Command(dockerBinary, "pull", "scratch")
pullCmd := exec.Command(dockerBinary, "pull", "hello-world")
if out, _, err := runCommandWithOutput(pullCmd); err != nil {
t.Fatalf("pulling the scratch image from has failed: %s, %v", out, err)
t.Fatalf("pulling the hello-world image from has failed: %s, %v", out, err)
}
eventsCmd := exec.Command(dockerBinary, "events",
@ -243,7 +243,7 @@ func TestEventsImagePull(t *testing.T) {
events := strings.Split(strings.TrimSpace(out), "\n")
event := strings.TrimSpace(events[len(events)-1])
if !strings.HasSuffix(event, "scratch:latest: pull") {
if !strings.HasSuffix(event, "hello-world:latest: pull") {
t.Fatalf("Missing pull event - got:%q", event)
}

View file

@ -7,7 +7,7 @@ import (
)
func TestInspectImage(t *testing.T) {
imageTest := "scratch"
imageTest := "emptyfs"
imageTestID := "511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158"
imagesCmd := exec.Command(dockerBinary, "inspect", "--format='{{.Id}}'", imageTest)
out, exitCode, err := runCommandWithOutput(imagesCmd)

View file

@ -9,11 +9,11 @@ import (
// pulling an image from the central registry should work
func TestPullImageFromCentralRegistry(t *testing.T) {
pullCmd := exec.Command(dockerBinary, "pull", "scratch")
pullCmd := exec.Command(dockerBinary, "pull", "hello-world")
if out, _, err := runCommandWithOutput(pullCmd); err != nil {
t.Fatalf("pulling the scratch image from the registry has failed: %s, %v", out, err)
t.Fatalf("pulling the hello-world image from the registry has failed: %s, %v", out, err)
}
logDone("pull - pull scratch")
logDone("pull - pull hello-world")
}
// pulling a non-existing image from the central registry should return a non-zero exit code

View file

@ -270,7 +270,7 @@ func TestSaveSingleTag(t *testing.T) {
func TestSaveImageId(t *testing.T) {
repoName := "foobar-save-image-id-test"
tagCmdFinal := fmt.Sprintf("%v tag scratch:latest %v:latest", dockerBinary, repoName)
tagCmdFinal := fmt.Sprintf("%v tag emptyfs:latest %v:latest", dockerBinary, repoName)
tagCmd := exec.Command("bash", "-c", tagCmdFinal)
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
t.Fatalf("failed to tag repo: %s, %v", out, err)
@ -370,7 +370,7 @@ func TestSaveMultipleNames(t *testing.T) {
repoName := "foobar-save-multi-name-test"
// Make one image
tagCmdFinal := fmt.Sprintf("%v tag scratch:latest %v-one:latest", dockerBinary, repoName)
tagCmdFinal := fmt.Sprintf("%v tag emptyfs:latest %v-one:latest", dockerBinary, repoName)
tagCmd := exec.Command("bash", "-c", tagCmdFinal)
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
t.Fatalf("failed to tag repo: %s, %v", out, err)
@ -378,7 +378,7 @@ func TestSaveMultipleNames(t *testing.T) {
defer deleteImages(repoName + "-one")
// Make two images
tagCmdFinal = fmt.Sprintf("%v tag scratch:latest %v-two:latest", dockerBinary, repoName)
tagCmdFinal = fmt.Sprintf("%v tag emptyfs:latest %v-two:latest", dockerBinary, repoName)
tagCmd = exec.Command("bash", "-c", tagCmdFinal)
if out, _, err := runCommandWithOutput(tagCmd); err != nil {
t.Fatalf("failed to tag repo: %s, %v", out, err)

View file

@ -1,13 +1,13 @@
#!/bin/bash
if ! docker inspect scratch &> /dev/null; then
# let's build a "docker save" tarball for "scratch"
# let's build a "docker save" tarball for "emptyfs"
# see https://github.com/docker/docker/pull/5262
# and also https://github.com/docker/docker/issues/4242
mkdir -p /docker-scratch
(
cd /docker-scratch
echo '{"scratch":{"latest":"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158"}}' > repositories
echo '{"emptyfs":{"latest":"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158"}}' > repositories
mkdir -p 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
(
cd 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158