示例#1
0
// AddDependency will add a dependency with the given name, id, labels, and size
// to the untarred ACI stored at acipath. If the dependency already exists its
// fields will be updated to the new values.
func AddDependency(acipath, imageName, imageId string, labels types.Labels, size uint) error {
	acid, err := types.NewACIdentifier(imageName)
	if err != nil {
		return err
	}

	var hash *types.Hash
	if imageId != "" {
		var err error
		hash, err = types.NewHash(imageId)
		if err != nil {
			return err
		}
	}

	fn := func(s *schema.ImageManifest) {
		removeDep(*acid)(s)
		s.Dependencies = append(s.Dependencies,
			types.Dependency{
				ImageName: *acid,
				ImageID:   hash,
				Labels:    labels,
				Size:      size,
			})
	}
	return util.ModifyManifest(fn, acipath)
}
示例#2
0
func runAddDep(cmd *cobra.Command, args []string) (exit int) {
	if len(args) == 0 {
		cmd.Usage()
		return 1
	}
	if len(args) != 1 {
		stderr("dependency add: incorrect number of arguments")
		return 1
	}

	if debug {
		stderr("Adding dependency %q", args[0])
	}

	app, err := discovery.NewAppFromString(args[0])
	if err != nil {
		stderr("dependency add: couldn't parse dependency name: %v", err)
		return 1
	}

	appcLabels := types.Labels(labels)

	for name, value := range app.Labels {
		if _, ok := appcLabels.Get(string(name)); ok {
			stderr("multiple %s labels specified", name)
			return 1
		}
		appcLabels = append(appcLabels, types.Label{
			Name:  name,
			Value: value,
		})
	}

	var hash *types.Hash
	if imageId != "" {
		var err error
		hash, err = types.NewHash(imageId)
		if err != nil {
			stderr("dependency add: couldn't parse image ID: %v", err)
			return 1
		}
	}

	err = newACBuild().AddDependency(app.Name, hash, appcLabels, size)

	if err != nil {
		stderr("dependency add: %v", err)
		return getErrorCode(err)
	}

	return 0
}
示例#3
0
func TestAdd2Dependencies(t *testing.T) {
	workingDir := setUpTest(t)
	defer cleanUpTest(workingDir)

	_, _, _, err := runACBuild(workingDir, "dependency", "add", depName,
		"--image-id", depImageID,
		"--label", newLabel(depLabel1Key, depLabel1Val),
		"--label", newLabel(depLabel2Key, depLabel2Val),
		"--size", strconv.Itoa(int(depSize)))
	if err != nil {
		t.Fatalf("%v\n", err)
	}

	_, _, _, err = runACBuild(workingDir, "dependency", "add", depName2)
	if err != nil {
		t.Fatalf("%v\n", err)
	}

	hash, err1 := types.NewHash(depImageID)
	if err1 != nil {
		panic(err1)
	}

	deps := types.Dependencies{
		types.Dependency{
			ImageName: *types.MustACIdentifier(depName),
			ImageID:   hash,
			Labels: types.Labels{
				types.Label{
					Name:  *types.MustACIdentifier(depLabel1Key),
					Value: depLabel1Val,
				},
				types.Label{
					Name:  *types.MustACIdentifier(depLabel2Key),
					Value: depLabel2Val,
				},
			},
			Size: depSize,
		},
		types.Dependency{
			ImageName: *types.MustACIdentifier(depName2),
		},
	}

	checkManifest(t, workingDir, manWithDeps(deps))
	checkEmptyRootfs(t, workingDir)
}
示例#4
0
// AddDependency will add a dependency with the given name, id, labels, and size
// to the untarred ACI stored at a.CurrentACIPath. If the dependency already
// exists its fields will be updated to the new values.
func (a *ACBuild) AddDependency(imageName, imageId string, labels types.Labels, size uint) (err error) {
	if err = a.lock(); err != nil {
		return err
	}
	defer func() {
		if err1 := a.unlock(); err == nil {
			err = err1
		}
	}()

	acid, err := types.NewACIdentifier(imageName)
	if err != nil {
		return err
	}

	var hash *types.Hash
	if imageId != "" {
		var err error
		hash, err = types.NewHash(imageId)
		if err != nil {
			return err
		}
	}

	fn := func(s *schema.ImageManifest) error {
		removeDep(*acid)(s)
		s.Dependencies = append(s.Dependencies,
			types.Dependency{
				ImageName: *acid,
				ImageID:   hash,
				Labels:    labels,
				Size:      size,
			})
		return nil
	}
	return util.ModifyManifest(fn, a.CurrentACIPath)
}
示例#5
0
func TestAddDependencyWithImageID(t *testing.T) {
	workingDir := setUpTest(t)
	defer cleanUpTest(workingDir)

	_, _, _, err := runACBuild(workingDir, "dependency", "add", depName, "--image-id", depImageID)
	if err != nil {
		t.Fatalf("%v\n", err)
	}

	hash, err1 := types.NewHash(depImageID)
	if err1 != nil {
		panic(err1)
	}

	deps := types.Dependencies{
		types.Dependency{
			ImageName: *types.MustACIdentifier(depName),
			ImageID:   hash,
		},
	}

	checkManifest(t, workingDir, manWithDeps(deps))
	checkEmptyRootfs(t, workingDir)
}
示例#6
0
// Test an image with 1 dep. The parent image has a pathWhiteList.
func TestPWLOnlyParent(t *testing.T) {
	dir, err := ioutil.TempDir("", tstprefix)
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)
	ds := NewTestStore()

	imj := `
		{
		    "acKind": "ImageManifest",
		    "acVersion": "0.1.1",
		    "name": "example.com/test01",
		    "pathWhitelist" : [ "/a/file01.txt", "/a/file02.txt", "/b/link01.txt", "/c/", "/d/" ]
		}
	`

	entries := []*testTarEntry{
		{
			contents: imj,
			header: &tar.Header{
				Name: "manifest",
				Size: int64(len(imj)),
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/a/file01.txt",
				Size: 5,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/a/file02.txt",
				Size: 5,
			},
		},
		// This should not appear in rendered aci
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/a/file03.txt",
				Size: 5,
			},
		},
		{
			header: &tar.Header{
				Name:     "rootfs/b/link01.txt",
				Linkname: "file01.txt",
				Typeflag: tar.TypeSymlink,
			},
		},
		// The file "rootfs/c/file01.txt" should not appear but a new file "rootfs/c/file02.txt" provided by the upper image should appear.
		// The directory should be left with its permissions
		{
			header: &tar.Header{
				Name:     "rootfs/c",
				Typeflag: tar.TypeDir,
				Mode:     0700,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/c/file01.txt",
				Size: 5,
				Mode: 0700,
			},
		},
		// The file "rootfs/d/file01.txt" should not appear but the directory should be left and also its permissions
		{
			header: &tar.Header{
				Name:     "rootfs/d",
				Typeflag: tar.TypeDir,
				Mode:     0700,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/d/file01.txt",
				Size: 5,
				Mode: 0700,
			},
		},
		// The file and the directory should not appear
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/e/file01.txt",
				Size: 5,
				Mode: 0700,
			},
		},
	}

	key1, err := newTestACI(entries, dir, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	im, err := createImageManifest(imj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	image1 := Image{Im: im, Key: key1, Level: 1}

	imj = `
		{
		    "acKind": "ImageManifest",
		    "acVersion": "0.1.1",
		    "name": "example.com/test02"
		}
	`

	k1, _ := types.NewHash(key1)
	imj, err = addDependencies(imj,
		types.Dependency{
			ImageName: "example.com/test01",
			ImageID:   k1},
	)

	entries = []*testTarEntry{
		{
			contents: imj,
			header: &tar.Header{
				Name: "manifest",
				Size: int64(len(imj)),
			},
		},
		{
			contents: "hellohello",
			header: &tar.Header{
				Name: "rootfs/b/file01.txt",
				Size: 10,
			},
		},
		// New file
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/c/file02.txt",
				Size: 5,
			},
		},
	}

	expectedFiles := []*fileInfo{
		&fileInfo{path: "manifest", typeflag: tar.TypeReg},
		&fileInfo{path: "rootfs/a/file01.txt", typeflag: tar.TypeReg, size: 5},
		&fileInfo{path: "rootfs/a/file02.txt", typeflag: tar.TypeReg, size: 5},
		&fileInfo{path: "rootfs/b/link01.txt", typeflag: tar.TypeSymlink},
		&fileInfo{path: "rootfs/b/file01.txt", typeflag: tar.TypeReg, size: 10},
		&fileInfo{path: "rootfs/c", typeflag: tar.TypeDir, mode: 0700},
		&fileInfo{path: "rootfs/c/file02.txt", typeflag: tar.TypeReg, size: 5},
		&fileInfo{path: "rootfs/d", typeflag: tar.TypeDir, mode: 0700},
	}

	key2, err := newTestACI(entries, dir, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	im, err = createImageManifest(imj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	image2 := Image{Im: im, Key: key2, Level: 0}

	images := Images{image2, image1}
	err = checkRenderACIFromList(images, expectedFiles, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	err = checkRenderACI("example.com/test02", expectedFiles, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}
示例#7
0
// Test an image with 1 dep. The upper image overrides a dir provided by a
// parent with a non-dir file.
func TestFileOvverideDir(t *testing.T) {
	dir, err := ioutil.TempDir("", tstprefix)
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)
	ds := NewTestStore()

	imj := `
		{
		    "acKind": "ImageManifest",
		    "acVersion": "0.1.1",
		    "name": "example.com/test01"
		}
	`

	entries := []*testTarEntry{
		{
			contents: imj,
			header: &tar.Header{
				Name: "manifest",
				Size: int64(len(imj)),
			},
		},
		{
			header: &tar.Header{
				Name:     "rootfs/a/b",
				Typeflag: tar.TypeDir,
				Mode:     0700,
			},
		},
		{
			header: &tar.Header{
				Name:     "rootfs/a/b/c",
				Typeflag: tar.TypeDir,
				Mode:     0700,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/a/b/c/file01",
				Size: 5,
			},
		},
	}

	key1, err := newTestACI(entries, dir, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	im, err := createImageManifest(imj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	image1 := Image{Im: im, Key: key1, Level: 1}

	imj = `
		{
		    "acKind": "ImageManifest",
		    "acVersion": "0.1.1",
		    "name": "example.com/test02"
		}
	`

	k1, _ := types.NewHash(key1)
	imj, err = addDependencies(imj,
		types.Dependency{
			ImageName: "example.com/test01",
			ImageID:   k1},
	)

	entries = []*testTarEntry{
		{
			contents: imj,
			header: &tar.Header{
				Name: "manifest",
				Size: int64(len(imj)),
			},
		},
		{
			contents: "hellohello",
			header: &tar.Header{
				Name: "rootfs/a/b",
				Size: 10,
			},
		},
	}

	expectedFiles := []*fileInfo{
		&fileInfo{path: "manifest", typeflag: tar.TypeReg},
		&fileInfo{path: "rootfs/a/b", typeflag: tar.TypeReg, size: 10},
	}

	key2, err := newTestACI(entries, dir, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	im, err = createImageManifest(imj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	image2 := Image{Im: im, Key: key2, Level: 0}

	images := Images{image2, image1}
	err = checkRenderACIFromList(images, expectedFiles, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	err = checkRenderACI("example.com/test02", expectedFiles, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}
示例#8
0
// Test A (pwl) ---- B
//               \-- C -- D
func Test3Deps(t *testing.T) {
	dir, err := ioutil.TempDir("", tstprefix)
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)
	ds := NewTestStore()

	// B
	imj := `
		{
		    "acKind": "ImageManifest",
		    "acVersion": "0.1.1",
		    "name": "example.com/test01"
		}
	`

	entries := []*testTarEntry{
		{
			contents: imj,
			header: &tar.Header{
				Name: "manifest",
				Size: int64(len(imj)),
			},
		},
		// It should be overridden by the one provided by the upper image
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/a/file01.txt",
				Size: 5,
			},
		},
		// It should be overridden by the one provided by the next dep
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/a/file02.txt",
				Size: 5,
			},
		},
		// It should remain like this
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/a/file03.txt",
				Size: 5,
			},
		},
		// It should not appear in rendered aci
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/a/file04.txt",
				Size: 5,
			},
		},
		{
			header: &tar.Header{
				Name:     "rootfs/b/link01.txt",
				Linkname: "file01.txt",
				Typeflag: tar.TypeSymlink,
			},
		},
	}

	key1, err := newTestACI(entries, dir, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	im, err := createImageManifest(imj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	image1 := Image{Im: im, Key: key1, Level: 1}

	// D
	imj = `
		{
		    "acKind": "ImageManifest",
		    "acVersion": "0.1.1",
		    "name": "example.com/test03"
		}
	`

	entries = []*testTarEntry{
		{
			contents: imj,
			header: &tar.Header{
				Name: "manifest",
				Size: int64(len(imj)),
			},
		},
		// It should be overridden by the one provided by the upper image
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/a/file02.txt",
				Size: 5,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/b/file01.txt",
				Size: 5,
			},
		},
		// It should not appear in rendered aci
		{
			header: &tar.Header{
				Name:     "rootfs/d",
				Typeflag: tar.TypeDir,
				Mode:     0700,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/d/file01.txt",
				Size: 5,
				Mode: 0700,
			},
		},
	}

	key2, err := newTestACI(entries, dir, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	im, err = createImageManifest(imj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	image2 := Image{Im: im, Key: key2, Level: 2}

	// C
	imj = `
		{
		    "acKind": "ImageManifest",
		    "acVersion": "0.1.1",
		    "name": "example.com/test02"
		}
	`
	k2, _ := types.NewHash(key2)
	imj, err = addDependencies(imj,
		types.Dependency{
			ImageName: "example.com/test03",
			ImageID:   k2},
	)

	entries = []*testTarEntry{
		{
			contents: imj,
			header: &tar.Header{
				Name: "manifest",
				Size: int64(len(imj)),
			},
		},
		// It should be overridden by the one provided by the upper image
		{
			contents: "hellohello",
			header: &tar.Header{
				Name: "rootfs/a/file01.txt",
				Size: 10,
			},
		},
		{
			contents: "hellohello",
			header: &tar.Header{
				Name: "rootfs/a/file02.txt",
				Size: 10,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/b/file01.txt",
				Size: 5,
			},
		},
	}

	key3, err := newTestACI(entries, dir, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	im, err = createImageManifest(imj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	image3 := Image{Im: im, Key: key3, Level: 1}

	// A
	imj = `
		{
		    "acKind": "ImageManifest",
		    "acVersion": "0.1.1",
		    "name": "example.com/test04",
		    "pathWhitelist" : [ "/a/file01.txt", "/a/file02.txt", "/a/file03.txt", "/b/link01.txt", "/b/file01.txt", "/b/file02.txt", "/c/file01.txt" ]
		}
	`

	k1, _ := types.NewHash(key1)
	k3, _ := types.NewHash(key3)
	imj, err = addDependencies(imj,
		types.Dependency{
			ImageName: "example.com/test01",
			ImageID:   k1},
		types.Dependency{
			ImageName: "example.com/test02",
			ImageID:   k3},
	)

	entries = []*testTarEntry{
		{
			contents: imj,
			header: &tar.Header{
				Name: "manifest",
				Size: int64(len(imj)),
			},
		},
		// Overridden
		{
			contents: "hellohellohello",
			header: &tar.Header{
				Name: "rootfs/a/file01.txt",
				Size: 15,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/b/file02.txt",
				Size: 5,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "rootfs/c/file01.txt",
				Size: 5,
			},
		},
	}

	key4, err := newTestACI(entries, dir, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	im, err = createImageManifest(imj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	image4 := Image{Im: im, Key: key4, Level: 0}

	expectedFiles := []*fileInfo{
		&fileInfo{path: "manifest", typeflag: tar.TypeReg},
		&fileInfo{path: "rootfs/a/file01.txt", typeflag: tar.TypeReg, size: 15},
		&fileInfo{path: "rootfs/a/file02.txt", typeflag: tar.TypeReg, size: 10},
		&fileInfo{path: "rootfs/a/file03.txt", typeflag: tar.TypeReg, size: 5},
		&fileInfo{path: "rootfs/b/link01.txt", typeflag: tar.TypeSymlink},
		&fileInfo{path: "rootfs/b/file01.txt", typeflag: tar.TypeReg, size: 5},
		&fileInfo{path: "rootfs/b/file02.txt", typeflag: tar.TypeReg, size: 5},
		&fileInfo{path: "rootfs/c/file01.txt", typeflag: tar.TypeReg, size: 5},
	}

	images := Images{image4, image3, image2, image1}
	err = checkRenderACIFromList(images, expectedFiles, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	err = checkRenderACI("example.com/test04", expectedFiles, ds)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}