Пример #1
0
func runNew(context *cli.Context) {
	args := context.Args()

	if len(args) < 1 {
		fmt.Printf("args: %v", args)
		log.Errorf("provide an output file name")
		return
	}

	outImageName := context.String("image-name")
	if outImageName == "" {
		log.Errorf("provide an image name")
		return
	}
	fileName := args[0]

	manifest := &schema.ImageManifest{
		ACKind:    schema.ImageManifestKind,
		ACVersion: schema.AppContainerVersion,
		Name:      types.ACIdentifier(outImageName),
	}

	aciDir, err := util.PrepareACIDir(manifest, "")
	if err != nil {
		log.Fatalf("error prepareing ACI dir %v: %v", aciDir, err)
	}

	if err := util.BuildACI(aciDir, fileName, context.Bool("overwrite"), false); err != nil {
		log.Fatalf("error building the final output ACI: %v", err)
	}

	log.Infof("Image %v built successfully", fileName)
}
Пример #2
0
func runRm(context *cli.Context) {
	s := getStore()
	args := context.Args()

	if len(args) < 2 {
		fmt.Println("There need to be at least two arguments.")
		fmt.Println(context.Command.Usage)
		return
	}

	// Get the manifest of the base image
	base := args[0]
	im, err := util.GetManifestFromImage(base)
	if err != nil {
		log.Fatalf("Could not extract manifest from base image: %v", err)
	}

	if context.Bool("all-but-last") {
		im.Dependencies = im.Dependencies[len(im.Dependencies)-1:]
	} else {
		for _, arg := range args[1 : len(args)-1] {
			layer, err := util.ExtractLayerInfo(s, arg)
			if err != nil {
				log.Fatalf("error extracting layer info from %s: %v", s, err)
			}
			for i, dep := range im.Dependencies {
				if reflect.DeepEqual(layer.ImageName, dep.ImageName) && reflect.DeepEqual(layer.ImageID, dep.ImageID) {
					im.Dependencies = append(im.Dependencies[:i], im.Dependencies[i+1:]...)
				}
			}
		}
	}

	out := args[len(args)-1]

	baseFile, err := os.Open(base)
	if err != nil {
		log.Fatalf("error opening base ACI: %v", err)
	}
	defer baseFile.Close()

	outFile, err := os.Create(out)
	if err != nil {
		log.Fatalf("error creating output ACI: %v", err)
	}
	defer outFile.Close()

	flagImageName := context.String("output-image-name")
	if flagImageName != "" {
		im.Name = types.ACIdentifier(flagImageName)
	}

	if err := overwriteManifest(baseFile, outFile, im); err != nil {
		log.Fatalf("error writing to output ACI: %v", err)
	}
}
Пример #3
0
func TestGetAllKeyrings(t *testing.T) {
	// Redirect stdout (how to DRY?)
	origStdout := os.Stdout
	defer func() { os.Stdout = origStdout }()
	if devnull, err := os.Create("/dev/null"); err != nil {
		panic(err)
	} else {
		os.Stdout = devnull
		defer devnull.Close()
	}

	ks := newStore()
	defer os.RemoveAll(ks.Path)
	defer closeSampleKeys()

	prefix := types.ACIdentifier("example.com/foo")

	if _, err := ks.StoreTrustedKey(prefix, openSampleKey(0), sampleKeyFingerprints[0]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix, openSampleKey(1), sampleKeyFingerprints[1]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(Root, openSampleKey(2), sampleKeyFingerprints[2]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	kr, err := ks.GetAllKeys()
	if err != nil {
		t.Errorf("Error getting all keyrings: %v\n", err)
		t.FailNow()
	}

	kc := countKeys(kr)

	if len(kc) != 2 {
		t.Errorf("Got %d keyrings, expected 2: %v\n", len(kc), kc)
	}

	if rkc, ok := kc[Root]; !ok {
		t.Error("No root keyring")
	} else if rkc != 1 {
		t.Error("Root keyring %d long, expected 1\n", rkc)
	}

	if pkc, ok := kc[prefix]; !ok {
		t.Error("No prefix keyring")
	} else if pkc != 2 {
		t.Error("Prefix keyring %d long, expected 2\n", kc)
	}
}
Пример #4
0
func (this *oci2rkt) genImageManifest() {

	// 1. Assemble "acKind" field
	this.imageManifest.ACKind = "ImageManifest"

	// 2. Assemble "acVersion" field
	this.imageManifest.ACVersion = schema.AppContainerVersion

	// 3. Assemble "name" field
	this.imageManifest.Name = "oci"

	// 4. Assemble "labels" field
	// 4.1 "version"
	label := new(types.Label)
	label.Name = types.ACIdentifier("version")
	label.Value = this.linuxSpec.Version
	this.imageManifest.Labels = append(this.imageManifest.Labels, *label)
	// 4.2 "os"
	label = new(types.Label)
	label.Name = types.ACIdentifier("os")
	label.Value = this.linuxSpec.Platform.OS
	this.imageManifest.Labels = append(this.imageManifest.Labels, *label)
	// 4.3 "arch"
	label = new(types.Label)
	label.Name = types.ACIdentifier("arch")
	label.Value = this.linuxSpec.Platform.Arch
	this.imageManifest.Labels = append(this.imageManifest.Labels, *label)

	// 5. Assemble "app" field
	app := new(types.App)
	// 5.1 "exec"
	//fmt.Printf("this.linuxSpec.Process.Args=%v\n", this.linuxSpec.Process.Args)
	app.Exec = this.linuxSpec.Process.Args
	// 5.2 "user"
	app.User = fmt.Sprintf("%d", this.linuxSpec.Process.User.UID)
	// 5.3 "group"
	app.Group = fmt.Sprintf("%d", this.linuxSpec.Process.User.GID)

	this.imageManifest.App = app
}
Пример #5
0
func runAdd(context *cli.Context) {
	s := getStore()
	args := context.Args()

	if len(args) < 2 {
		fmt.Println("There need to be at least two arguments.")
		fmt.Println(context.Command.Usage)
	}

	var dependencies types.Dependencies
	for _, arg := range args[:len(args)-1] {
		layer, err := util.ExtractLayerInfo(s, arg)
		if err != nil {
			log.Fatalf("error extracting layer info from %s: %v", s, err)
		}
		dependencies = append(dependencies, layer)
	}

	out := args[len(args)-1]
	outImageName := context.String("output-image-name")

	manifest := &schema.ImageManifest{
		ACKind:       schema.ImageManifestKind,
		ACVersion:    schema.AppContainerVersion,
		Name:         types.ACIdentifier(outImageName),
		Dependencies: dependencies,
	}

	aciDir, err := util.PrepareACIDir(manifest, "")
	if err != nil {
		log.Fatalf("error prepareing ACI dir %v: %v", aciDir, err)
	}

	if err := util.BuildACI(aciDir, out, true, false); err != nil {
		log.Fatalf("error building the final output ACI: %v", err)
	}
}
Пример #6
0
func genManifest(path string) *schema.ImageManifest {
	// Get runtime.json and config.json
	runtimePath := path + "/runtime.json"
	configPath := path + "/config.json"

	runtime, err := ioutil.ReadFile(runtimePath)
	if err != nil {
		if debugEnabled {
			log.Printf("Open file runtime.json failed: %v", err)
		}
		return nil
	}

	config, err := ioutil.ReadFile(configPath)
	if err != nil {
		if debugEnabled {
			log.Printf("Open file config.json failed: %v", err)
		}
		return nil
	}

	var spec specs.LinuxSpec
	err = json.Unmarshal(config, &spec)
	if err != nil {
		if debugEnabled {
			log.Printf("Unmarshal config.json failed: %v", err)
		}
		return nil
	}

	var runSpec specs.LinuxRuntimeSpec
	err = json.Unmarshal(runtime, &runSpec)
	if err != nil {
		if debugEnabled {
			log.Printf("Unmarshal runtime.json failed: %v", err)
		}
		return nil
	}
	// Begin to convert runtime.json/config.json to manifest
	m := new(schema.ImageManifest)

	// 1. Assemble "acKind" field
	m.ACKind = schema.ImageManifestKind

	// 2. Assemble "acVersion" field
	m.ACVersion = schema.AppContainerVersion

	// 3. Assemble "name" field
	m.Name = types.ACIdentifier(manifestName)

	// 4. Assemble "labels" field
	// 4.1 "version"
	label := new(types.Label)
	label.Name = types.ACIdentifier("version")
	label.Value = spec.Version
	m.Labels = append(m.Labels, *label)
	// 4.2 "os"
	label = new(types.Label)
	label.Name = types.ACIdentifier("os")
	label.Value = spec.Platform.OS
	m.Labels = append(m.Labels, *label)
	// 4.3 "arch"
	label = new(types.Label)
	label.Name = types.ACIdentifier("arch")
	label.Value = spec.Platform.Arch
	m.Labels = append(m.Labels, *label)

	// 5. Assemble "app" field
	app := new(types.App)
	// 5.1 "exec"
	app.Exec = spec.Process.Args

	prefixDir := ""
	//var exeStr string
	if app.Exec == nil {
		app.Exec = append(app.Exec, "/bin/sh")
	} else {
		if !filepath.IsAbs(app.Exec[0]) {
			if spec.Process.Cwd == "" {
				prefixDir = "/"
			} else {
				prefixDir = spec.Process.Cwd
			}
		}
		app.Exec[0] = prefixDir + app.Exec[0]
	}

	// 5.2 "user"
	app.User = fmt.Sprintf("%d", spec.Process.User.UID)
	// 5.3 "group"
	app.Group = fmt.Sprintf("%d", spec.Process.User.GID)
	// 5.4 "eventHandlers"
	event := new(types.EventHandler)
	event.Name = "pre-start"
	for index := range runSpec.Hooks.Prestart {
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Path)
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Args...)
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Env...)
	}
	if len(event.Exec) == 0 {
		event.Exec = append(event.Exec, "/bin/echo")
		event.Exec = append(event.Exec, "-n")
	}
	app.EventHandlers = append(app.EventHandlers, *event)
	event = new(types.EventHandler)
	event.Name = "post-stop"
	for index := range runSpec.Hooks.Poststop {
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Path)
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Args...)
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Env...)
	}
	if len(event.Exec) == 0 {
		event.Exec = append(event.Exec, "/bin/echo")
		event.Exec = append(event.Exec, "-n")
	}
	app.EventHandlers = append(app.EventHandlers, *event)
	// 5.5 "workingDirectory"
	app.WorkingDirectory = spec.Process.Cwd
	// 5.6 "environment"
	env := new(types.EnvironmentVariable)
	for index := range spec.Process.Env {
		s := strings.Split(spec.Process.Env[index], "=")
		env.Name = s[0]
		env.Value = s[1]
		app.Environment = append(app.Environment, *env)
	}

	// 5.7 "mountPoints"
	for index := range spec.Mounts {
		mount := new(types.MountPoint)
		mount.Name = types.ACName(spec.Mounts[index].Name)
		mount.Path = spec.Mounts[index].Path
		mount.ReadOnly = false
		app.MountPoints = append(app.MountPoints, *mount)
	}

	// 5.8 "ports"

	// 5.9 "isolators"
	if runSpec.Linux.Resources != nil {
		if runSpec.Linux.Resources.CPU.Quota != 0 {
			cpuLimt := new(ResourceCPU)
			cpuLimt.Limit = fmt.Sprintf("%dm", runSpec.Linux.Resources.CPU.Quota)
			isolator := new(types.Isolator)
			isolator.Name = types.ACIdentifier("resource/cpu")
			bytes, _ := json.Marshal(cpuLimt)

			valueRaw := json.RawMessage(bytes)
			isolator.ValueRaw = &valueRaw

			app.Isolators = append(app.Isolators, *isolator)
		}
		if runSpec.Linux.Resources.Memory.Limit != 0 {
			memLimt := new(ResourceMem)
			memLimt.Limit = fmt.Sprintf("%dG", runSpec.Linux.Resources.Memory.Limit/(1024*1024*1024))
			isolator := new(types.Isolator)
			isolator.Name = types.ACIdentifier("resource/memory")
			bytes, _ := json.Marshal(memLimt)

			valueRaw := json.RawMessage(bytes)
			isolator.ValueRaw = &valueRaw

			app.Isolators = append(app.Isolators, *isolator)
		}
	}

	if len(spec.Linux.Capabilities) != 0 {
		isolatorCapSet := new(IsolatorCapSet)
		isolatorCapSet.Sets = append(isolatorCapSet.Sets, spec.Linux.Capabilities...)

		isolator := new(types.Isolator)
		isolator.Name = types.ACIdentifier(types.LinuxCapabilitiesRetainSetName)
		bytes, _ := json.Marshal(isolatorCapSet)

		valueRaw := json.RawMessage(bytes)
		isolator.ValueRaw = &valueRaw

		app.Isolators = append(app.Isolators, *isolator)
	}

	// 6. "annotations"

	// 7. "dependencies"

	// 8. "pathWhitelist"

	m.App = app

	return m
}
Пример #7
0
func NewAPIServiceListInspectPodsTest() testutils.Test {
	return testutils.TestFunc(func(t *testing.T) {
		ctx := testutils.NewRktRunCtx()
		defer ctx.Cleanup()

		svc := startAPIService(t, ctx)
		defer stopAPIService(t, svc)

		c, conn := newAPIClientOrFail(t, "localhost:15441")
		defer conn.Close()

		resp, err := c.ListPods(context.Background(), &v1alpha.ListPodsRequest{})
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		if len(resp.Pods) != 0 {
			t.Errorf("Unexpected result: %v, should see zero pods", resp.Pods)
		}

		patches := []string{"--exec=/inspect --print-msg=HELLO_API --exit-code=0"}
		imageHash, err := patchImportAndFetchHash("rkt-inspect-print.aci", patches, t, ctx)
		if err != nil {
			t.Fatalf("%v", err)
		}
		imgID, err := types.NewHash(imageHash)
		if err != nil {
			t.Fatalf("Cannot generate types.Hash from %v: %v", imageHash, err)
		}

		podManifests := []struct {
			mfst             schema.PodManifest
			net              string
			expectedExitCode int
		}{
			{
				// 1, Good pod.
				schema.PodManifest{
					ACKind:    schema.PodManifestKind,
					ACVersion: schema.AppContainerVersion,
					Apps: []schema.RuntimeApp{
						{
							Name: types.ACName("rkt-inspect"),
							Image: schema.RuntimeImage{
								Name: types.MustACIdentifier("coreos.com/rkt-inspect"),
								ID:   *imgID,
							},
							Annotations: []types.Annotation{{Name: types.ACIdentifier("app-test"), Value: "app-test"}},
						},
					},
					Annotations: []types.Annotation{
						{Name: types.ACIdentifier("test"), Value: "test"},
					},
				},
				"default",
				0,
			},
			{
				// 2, Bad pod, won't be launched correctly.
				schema.PodManifest{
					ACKind:    schema.PodManifestKind,
					ACVersion: schema.AppContainerVersion,
					Apps: []schema.RuntimeApp{
						{
							Name: types.ACName("rkt-inspect"),
							Image: schema.RuntimeImage{
								Name: types.MustACIdentifier("coreos.com/rkt-inspect"),
								ID:   *imgID,
							},
						},
					},
				},
				"non-existent-network",
				254,
			},
		}

		// Launch the pods.
		for _, entry := range podManifests {
			manifestFile := generatePodManifestFile(t, &entry.mfst)
			defer os.Remove(manifestFile)

			runCmd := fmt.Sprintf("%s run --net=%s --pod-manifest=%s", ctx.Cmd(), entry.net, manifestFile)
			waitOrFail(t, spawnOrFail(t, runCmd), entry.expectedExitCode)
		}

		time.Sleep(delta)

		gcCmd := fmt.Sprintf("%s gc --mark-only=true", ctx.Cmd())
		waitOrFail(t, spawnOrFail(t, gcCmd), 0)

		gcTime := time.Now()

		// ListPods(detail=false).
		resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{})
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		if len(resp.Pods) != len(podManifests) {
			t.Errorf("Unexpected result: %v, should see %v pods", len(resp.Pods), len(podManifests))
		}

		for _, p := range resp.Pods {
			checkPodBasicsWithGCTime(t, ctx, p, gcTime)

			// Test InspectPod().
			inspectResp, err := c.InspectPod(context.Background(), &v1alpha.InspectPodRequest{Id: p.Id})
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			checkPodDetails(t, ctx, inspectResp.Pod)
		}

		// ListPods(detail=true).
		resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{Detail: true})
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		if len(resp.Pods) != len(podManifests) {
			t.Errorf("Unexpected result: %v, should see %v pods", len(resp.Pods), len(podManifests))
		}

		for _, p := range resp.Pods {
			checkPodDetails(t, ctx, p)
		}

		// ListPods with corrupt pod directory
		// Note that we don't checkPodDetails here, the failure this is testing is
		// the api server panicing, which results in a list call hanging for ages
		// and then failing.
		// TODO: do further validation on the partial pods returned
		for _, p := range resp.Pods {
			numRemoved := 0
			podDir := getPodDir(t, ctx, p.Id)
			filepath.Walk(filepath.Join(podDir, "appsinfo"), filepath.WalkFunc(func(path string, info os.FileInfo, err error) error {
				if err != nil {
					return err
				}
				if info.Name() == "manifest" {
					os.Remove(path)
					numRemoved++
				}
				return nil
			}))
			if numRemoved == 0 {
				t.Fatalf("Expected to remove at least one app manifest for pod %v", p)
			}
		}

		// ListPods(detail=true).
		resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{Detail: true})
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if len(resp.Pods) != len(podManifests) {
			t.Fatalf("Expected %v pods, got %v pods", len(podManifests), len(resp.Pods))
		}
	})
}
Пример #8
0
import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/juju/errors"
	"golang.org/x/crypto/openpgp"

	"github.com/appc/spec/schema/types"
)

// Intentionally invalid ACIdentifier to mark root key
const Root = types.ACIdentifier("@")

type Keystore struct {
	Path string
}

func New(path string) *Keystore {
	return &Keystore{path}
}

func (ks *Keystore) prefixPath(prefix types.ACIdentifier) string {
	if prefix.Empty() {
		panic("Empty prefix!")
	}
	return filepath.Join(ks.Path, strings.Replace(string(prefix), "/", ",", -1))
}
Пример #9
0
func TestGetKeyring(t *testing.T) {
	// Redirect stdout (how to DRY?)
	origStdout := os.Stdout
	defer func() { os.Stdout = origStdout }()
	if devnull, err := os.Create("/dev/null"); err != nil {
		panic(err)
	} else {
		os.Stdout = devnull
		defer devnull.Close()
	}

	ks := newStore()
	defer os.RemoveAll(ks.Path)
	defer closeSampleKeys()

	if _, err := ks.StoreTrustedKey(types.ACIdentifier("example.com/foo"), openSampleKey(0), sampleKeyFingerprints[0]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(types.ACIdentifier("example.com/foo/bar"), openSampleKey(1), sampleKeyFingerprints[1]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	checkKeyCount(t, ks, map[types.ACIdentifier]int{
		types.ACIdentifier("eggsample.com"):           0,
		types.ACIdentifier("eggsample.com/foo"):       0,
		types.ACIdentifier("eggsample.com/foo/bar"):   0,
		types.ACIdentifier("example.com"):             0,
		types.ACIdentifier("example.com/foo"):         1,
		types.ACIdentifier("example.com/foo/baz"):     1,
		types.ACIdentifier("example.com/foo/bar"):     2,
		types.ACIdentifier("example.com/foo/bar/baz"): 2,
		types.ACIdentifier("example.com/foobar"):      1,
		types.ACIdentifier("example.com/baz"):         0,
	})

	if _, err := ks.StoreTrustedKey(Root, openSampleKey(2), sampleKeyFingerprints[2]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	checkKeyCount(t, ks, map[types.ACIdentifier]int{
		types.ACIdentifier("eggsample.com"):           1,
		types.ACIdentifier("eggsample.com/foo"):       1,
		types.ACIdentifier("eggsample.com/foo/bar"):   1,
		types.ACIdentifier("example.com"):             1,
		types.ACIdentifier("example.com/foo"):         2,
		types.ACIdentifier("example.com/foo/baz"):     2,
		types.ACIdentifier("example.com/foo/bar"):     3,
		types.ACIdentifier("example.com/foo/bar/baz"): 3,
		types.ACIdentifier("example.com/foobar"):      2,
		types.ACIdentifier("example.com/baz"):         1,
	})
}
Пример #10
0
func TestImportPrefixEscaped(t *testing.T) {
	testImport(t, types.ACIdentifier("example.com/foo"), "example.com,foo")
}
Пример #11
0
func TestImportPrefix(t *testing.T) {
	testImport(t, types.ACIdentifier("example.com"), "example.com")
}
func TestMakePodManifestAnnotations(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	fr := newFakeRktInterface()
	fs := newFakeSystemd()
	r := &Runtime{apisvc: fr, systemd: fs}

	testCases := []struct {
		in     *api.Pod
		out    *appcschema.PodManifest
		outerr error
	}{
		{
			in: &api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "uid-1",
					Name:      "name-1",
					Namespace: "namespace-1",
					Annotations: map[string]string{
						k8sRktStage1NameAnno: "stage1-override-img",
					},
				},
			},
			out: &appcschema.PodManifest{
				Annotations: []appctypes.Annotation{
					{
						Name:  appctypes.ACIdentifier(k8sRktStage1NameAnno),
						Value: "stage1-override-img",
					},
					{
						Name:  appctypes.ACIdentifier(types.KubernetesPodUIDLabel),
						Value: "uid-1",
					},
					{
						Name:  appctypes.ACIdentifier(types.KubernetesPodNameLabel),
						Value: "name-1",
					},
					{
						Name:  appctypes.ACIdentifier(k8sRktKubeletAnno),
						Value: "true",
					},
					{
						Name:  appctypes.ACIdentifier(types.KubernetesPodNamespaceLabel),
						Value: "namespace-1",
					},
					{
						Name:  appctypes.ACIdentifier(k8sRktRestartCountAnno),
						Value: "0",
					},
				},
			},
		},
	}

	for i, testCase := range testCases {
		hint := fmt.Sprintf("case #%d", i)

		result, err := r.makePodManifest(testCase.in, "", []api.Secret{})
		assert.Equal(t, err, testCase.outerr, hint)
		if err == nil {
			sort.Sort(annotationsByName(result.Annotations))
			sort.Sort(annotationsByName(testCase.out.Annotations))
			assert.Equal(t, result.Annotations, testCase.out.Annotations, hint)
		}
	}
}
Пример #13
0
func TestAPIServiceListInspectPods(t *testing.T) {
	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	svc := startAPIService(t, ctx)
	defer stopAPIService(t, svc)

	c, conn := newAPIClientOrFail(t, "localhost:15441")
	defer conn.Close()

	resp, err := c.ListPods(context.Background(), &v1alpha.ListPodsRequest{})
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	if len(resp.Pods) != 0 {
		t.Errorf("Unexpected result: %v, should see zero pods", resp.Pods)
	}

	patches := []string{"--exec=/inspect --print-msg=HELLO_API --exit-code=0"}
	imageHash := patchImportAndFetchHash("rkt-inspect-print.aci", patches, t, ctx)
	imgID, err := types.NewHash(imageHash)
	if err != nil {
		t.Fatalf("Cannot generate types.Hash from %v: %v", imageHash, err)
	}
	pm := schema.BlankPodManifest()
	pm.Apps = []schema.RuntimeApp{
		{
			Name: types.ACName("rkt-inspect"),
			Image: schema.RuntimeImage{
				Name: types.MustACIdentifier("coreos.com/rkt-inspect"),
				ID:   *imgID,
			},
			Annotations: []types.Annotation{{Name: types.ACIdentifier("app-test"), Value: "app-test"}},
		},
	}
	pm.Annotations = []types.Annotation{{Name: types.ACIdentifier("test"), Value: "test"}}
	manifestFile := generatePodManifestFile(t, pm)
	defer os.Remove(manifestFile)

	runCmd := fmt.Sprintf("%s run --pod-manifest=%s", ctx.Cmd(), manifestFile)
	waitOrFail(t, spawnOrFail(t, runCmd), 0)

	gcCmd := fmt.Sprintf("%s gc --mark-only=true", ctx.Cmd())
	waitOrFail(t, spawnOrFail(t, gcCmd), 0)

	gcTime := time.Now()

	// ListPods(detail=false).
	resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{})
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	if len(resp.Pods) == 0 {
		t.Errorf("Unexpected result: %v, should see non-zero pods", resp.Pods)
	}

	for _, p := range resp.Pods {
		checkPodBasicsWithGCTime(t, ctx, p, gcTime)

		// Test InspectPod().
		inspectResp, err := c.InspectPod(context.Background(), &v1alpha.InspectPodRequest{Id: p.Id})
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		checkPodDetails(t, ctx, inspectResp.Pod)

		// Test Apps.
		for i, app := range p.Apps {
			checkAnnotations(t, pm.Apps[i].Annotations, app.Annotations)
		}
	}

	// ListPods(detail=true).
	resp, err = c.ListPods(context.Background(), &v1alpha.ListPodsRequest{Detail: true})
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	if len(resp.Pods) == 0 {
		t.Errorf("Unexpected result: %v, should see non-zero pods", resp.Pods)
	}

	for _, p := range resp.Pods {
		checkPodDetails(t, ctx, p)
	}
}
Пример #14
0
func TestRankedName(t *testing.T) {
	tests := []struct {
		li string
		lj string

		expected bool
	}{
		{
			"version", "os",
			true,
		},
		{
			"os", "version",
			false,
		},
		{
			"version", "a",
			true,
		},
		{
			"a", "os",
			false,
		},
		{
			"os", "a",
			true,
		},
		{
			"", "os",
			false,
		},
		{
			"os", "",
			true,
		},
		{
			"a", "version",
			false,
		},
		{
			"a", "b",
			true,
		},
		{
			"b", "a",
			false,
		},
		{
			"a", "a",
			false,
		},
		{
			"version", "version",
			false,
		},
	}

	for i, tt := range tests {
		li := types.Label{
			Name: types.ACIdentifier(tt.li),
		}

		lj := types.Label{
			Name: types.ACIdentifier(tt.lj),
		}

		if result := RankedName(li, lj); result != tt.expected {
			t.Errorf("test %d expected %q < %q = %t but got %t", i, tt.li, tt.lj, tt.expected, result)
		}
	}
}
Пример #15
0
// Write will produce the resulting ACI from the current build context, saving
// it to the given path, optionally signing it.
func (a *ACBuild) Write(output string, overwrite, sign bool, gpgflags []string) (err error) {
	if err = a.lock(); err != nil {
		return err
	}
	defer func() {
		if err1 := a.unlock(); err == nil {
			err = err1
		}
	}()

	man, err := util.GetManifest(a.CurrentACIPath)
	if err != nil {
		return err
	}

	if man.App != nil && len(man.App.Exec) == 0 {
		fmt.Fprintf(os.Stderr, "warning: exec command was never set.\n")
	}

	if man.Name == types.ACIdentifier(placeholdername) {
		return fmt.Errorf("can't write ACI, name was never set")
	}

	fileFlags := os.O_CREATE | os.O_WRONLY

	_, err = os.Stat(output)
	switch {
	case os.IsNotExist(err):
		break
	case err != nil:
		return err
	default:
		if !overwrite {
			return fmt.Errorf("ACI already exists: %s", output)
		}
		fileFlags |= os.O_TRUNC
	}

	// open/create the aci file
	ofile, err := os.OpenFile(output, fileFlags, 0644)
	if err != nil {
		return err
	}
	defer ofile.Close()

	defer func() {
		// When write is done, if an error is encountered remove the partial
		// ACI that had been written.
		if err != nil {
			os.Remove(output)
			os.Remove(output + ".asc")
		}
	}()

	// setup compression
	gzwriter := gzip.NewWriter(ofile)
	defer gzwriter.Close()

	// create the aci writer
	aw := aci.NewImageWriter(*man, tar.NewWriter(gzwriter))
	err = filepath.Walk(a.CurrentACIPath, aci.BuildWalker(a.CurrentACIPath, aw, nil))
	defer aw.Close()
	if err != nil {
		pathErr, ok := err.(*os.PathError)
		if !ok {
			fmt.Printf("not a path error!\n")
			return err
		}
		syscallErrno, ok := pathErr.Err.(syscall.Errno)
		if !ok {
			fmt.Printf("not a syscall errno!\n")
			return err
		}
		if pathErr.Op == "open" && syscallErrno != syscall.EACCES {
			return err
		}
		problemPath := pathErr.Path[len(path.Join(a.CurrentACIPath, aci.RootfsDir)):]
		return fmt.Errorf("%q: permission denied - call write as root", problemPath)
	}

	if sign {
		err = signACI(output, output+".asc", gpgflags)
		if err != nil {
			return err
		}
	}

	return nil
}
Пример #16
0
package acutil

import "github.com/appc/spec/schema/types"

// Empty ACName
const ACNoName = types.ACName("")

// Empty ACIdentifier
const ACNoIdentifier = types.ACIdentifier("")
Пример #17
0
func TestUntrustKey(t *testing.T) {
	// Redirect stdout (how to DRY?)
	origStdout := os.Stdout
	defer func() { os.Stdout = origStdout }()
	if devnull, err := os.Create("/dev/null"); err != nil {
		panic(err)
	} else {
		os.Stdout = devnull
		defer devnull.Close()
	}

	ks := newStore()
	defer os.RemoveAll(ks.Path)
	defer closeSampleKeys()

	prefix := types.ACIdentifier("example.com/foo")
	prefix2 := types.ACIdentifier("example.org/bar")

	if _, err := ks.StoreTrustedKey(prefix, openSampleKey(0), sampleKeyFingerprints[0]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix, openSampleKey(1), sampleKeyFingerprints[1]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix2, openSampleKey(1), sampleKeyFingerprints[1]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix2, openSampleKey(2), sampleKeyFingerprints[2]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(Root, openSampleKey(2), sampleKeyFingerprints[2]); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	kr, err := ks.GetAllKeys()
	if err != nil {
		panic(err)
	}
	kc := countKeys(kr)

	if kc[Root] != 1 || kc[prefix] != 2 || kc[prefix2] != 2 {
		t.Errorf("Wrong keyrings even before remove: %v\n", kc)
	}

	if prefixes, err := ks.UntrustKey(sampleKeyFingerprints[2]); err != nil {
		t.Errorf("Error untrusting key: %v %v\n", err, prefixes)
	} else {
		sort.Sort(acNames(prefixes))
		expectedPrefixes := []types.ACIdentifier{Root, prefix2}
		if !reflect.DeepEqual(prefixes, expectedPrefixes) {
			t.Errorf("Expected removed prefixes to be %v, got %v instead.\n", expectedPrefixes, prefixes)
		}
	}

	kr, err = ks.GetAllKeys()
	if err != nil {
		panic(err)
	}
	kc = countKeys(kr)

	if kc[Root] != 0 || kc[prefix] != 2 || kc[prefix2] != 1 {
		t.Errorf("Wrong counts after remove: %v\n", kc)
	}
}
Пример #18
0
func runExec(context *cli.Context) {
	flagIn := context.String("in")
	flagCmd := context.String("cmd")
	flagOut := context.String("out")
	if flagIn == "" || flagCmd == "" || flagOut == "" {
		log.Fatalf("--in, --cmd, and --out need to be set")
	}

	flagNoOverlay := context.Bool("no-overlay")
	useOverlay := util.SupportsOverlay() && !flagNoOverlay

	s := getStore()
	mounts, err := getMounts(context)
	if err != nil {
		log.Fatalf("error parsing mounts: %v", err)
	}

	// Render the given image in tree store
	imageHash, err := renderInStore(s, flagIn)
	if err != nil {
		log.Fatalf("error rendering image in store: %s", err)
	}
	imagePath := s.GetTreeStorePath(imageHash)

	// Create a tmp directory
	tmpDir, err := ioutil.TempDir("", "acbuild-")
	if err != nil {
		log.Fatalf("error creating temporary directory: %s", err)
	}

	// Copy the manifest into the tmp directory
	if err := shutil.CopyFile(filepath.Join(imagePath, aci.ManifestFile),
		filepath.Join(tmpDir, aci.ManifestFile), true); err != nil {
		log.Fatalf("error copying manifest to a temporary directory: %s", err)
	}

	// Extract a ImageManifest from the manifest file
	manifestFile, err := os.Open(filepath.Join(tmpDir, aci.ManifestFile))
	if err != nil {
		log.Fatalf("error opening the copied manifest file: %v", err)
	}
	manifestContent, err := ioutil.ReadAll(manifestFile)
	if err != nil {
		log.Fatalf("error reading the copied manifest file: %v", err)
	}
	im := &schema.ImageManifest{}
	if err := im.UnmarshalJSON(manifestContent); err != nil {
		log.Fatalf("error unmarshalling JSON to manifest: %v", err)
	}

	// If an output image name is not given, we grab it from the input ACI
	flagImageName := context.String("output-image-name")
	if flagImageName == "" {
		flagImageName = string(im.Name)
	}

	flagJail := context.Bool("jail")

	// If the system supports overlayfs, use it.
	// Otherwise, copy the entire rendered image to a working directory.
	storeRootfsDir := filepath.Join(imagePath, aci.RootfsDir)
	tmpRootfsDir := filepath.Join(tmpDir, aci.RootfsDir)
	if useOverlay {
		upperDir, err := mountOverlayfs(tmpRootfsDir, storeRootfsDir)
		if err != nil {
			log.Fatalf("error mounting overlayfs: %v", err)
		}
		// Note that defer functions are not run if the program
		// exits via os.Exit() and by extension log.Fatal(), which
		// is the behaviour that we want.
		defer unmountOverlayfs(tmpRootfsDir)

		if err := runCmdInDir(im, flagCmd, tmpRootfsDir, flagJail, mounts); err != nil {
			log.Fatalf("error executing command: %v", err)
		}

		// We store the delta (i.e. side effects of the executed command) into its own ACI
		// The name of the ACI is a hash of (command, hash of input image).  This will make
		// implementing caching easier in the future.
		deltaACIName, err := util.Hash(flagCmd, imageHash)
		if err != nil {
			log.Fatalf("error hashing (%s %s): %s", flagCmd, imageHash, err)
		}
		deltaManifest := &schema.ImageManifest{
			ACKind:    schema.ImageManifestKind,
			ACVersion: schema.AppContainerVersion,
			Name:      types.ACIdentifier(deltaACIName),
		}
		deltaACIDir, err := util.PrepareACIDir(deltaManifest, upperDir)
		if err != nil {
			log.Fatalf("error preparing delta ACI dir: %v", err)
		}

		// Create a temp directory for placing delta ACI
		deltaACITempDir, err := ioutil.TempDir("", "")
		if err != nil {
			log.Fatalf("error creating temp dir to put delta ACI: %v", err)
		}
		deltaACIPath := filepath.Join(deltaACITempDir, "delta.aci")

		// Build the delta ACI
		if err := util.BuildACI(deltaACIDir, deltaACIPath, true, false); err != nil {
			log.Fatalf("error building delta ACI: %v", err)
		}

		// Put the delta ACI into tree store
		deltaACIFile, err := os.Open(deltaACIPath)
		if err != nil {
			log.Fatalf("error opening the delta ACI file: %v", err)
		}
		deltaKey, err := s.WriteACI(deltaACIFile, false)
		if err != nil {
			log.Fatalf("error writing the delta ACI into the tree store: %v", err)
		}
		deltaKeyHash, err := types.NewHash(deltaKey)
		if err != nil {
			log.Fatalf("error creating hash from an image ID (%s): %v", deltaKeyHash, err)
		}

		// The manifest for the output ACI
		manifest := &schema.ImageManifest{
			ACKind:    schema.ImageManifestKind,
			ACVersion: schema.AppContainerVersion,
			Name:      types.ACIdentifier(flagImageName),
		}
		if context.Bool("split") {
			layers, err := util.ExtractLayers(s, flagIn)
			if err != nil {
				log.Fatalf("error extracting layers from %s: %v", flagIn, err)
			}
			manifest.Dependencies = append(manifest.Dependencies, layers...)
			manifest.Dependencies = append(manifest.Dependencies, types.Dependency{
				ImageName: types.ACIdentifier(deltaACIName),
				ImageID:   deltaKeyHash,
			})
		} else {
			layer, err := util.ExtractLayerInfo(s, flagIn)
			if err != nil {
				log.Fatalf("error extracting layer info from input ACI: %v", err)
			}
			// two layers:
			// 1. The original ACI
			// 2. The delta ACI
			manifest.Dependencies = types.Dependencies{
				layer,
				types.Dependency{
					ImageName: types.ACIdentifier(deltaACIName),
					ImageID:   deltaKeyHash,
				},
			}
		}

		// The rootfs is empty
		aciDir, err := util.PrepareACIDir(manifest, "")
		if err != nil {
			log.Fatalf("error prepareing ACI dir %v: %v", aciDir, err)
		}

		// Build the output ACI
		if err := util.BuildACI(aciDir, flagOut, true, false); err != nil {
			log.Fatalf("error building the final output ACI: %v", err)
		}
	} else {
		if err := shutil.CopyTree(storeRootfsDir, tmpRootfsDir, &shutil.CopyTreeOptions{
			Symlinks:               true,
			IgnoreDanglingSymlinks: true,
			CopyFunction:           shutil.Copy,
		}); err != nil {
			log.Fatalf("error copying rootfs to a temporary directory: %v", err)
		}

		if err := runCmdInDir(im, flagCmd, tmpRootfsDir, flagJail, mounts); err != nil {
			log.Fatalf("error executing command: %v", err)
		}

		err = util.BuildACI(tmpDir, flagOut, true, false)
		if err != nil {
			log.Fatalf("error building output ACI image: %v", err)
		}
	}
}