Example #1
0
// FetchImage will take an image as either a path, a URL or a name
// string and import it into the store if found. If ascPath is not "",
// it must exist as a local file and will be used as the signature
// file for verification, unless verification is disabled. If
// f.WithDeps is true also image dependencies are fetched.
func (f *Fetcher) FetchImage(d dist.Distribution, image, ascPath string) (*types.Hash, error) {
	ensureLogger(f.Debug)
	db := &distBundle{
		dist:  d,
		image: image,
	}
	a := f.getAsc(ascPath)
	hash, err := f.fetchSingleImage(db, a)
	if err != nil {
		return nil, err
	}
	if f.WithDeps {
		err = f.fetchImageDeps(hash)
		if err != nil {
			return nil, err
		}
	}

	// we need to be able to do a chroot and access to the tree store
	// directories, we need to
	// 1) check if the system supports OverlayFS
	// 2) check if we're root
	if common.SupportsOverlay() == nil && os.Geteuid() == 0 {
		if _, _, err := f.Ts.Render(hash, false); err != nil {
			return nil, errwrap.Wrap(errors.New("error rendering tree store"), err)
		}
	}
	h, err := types.NewHash(hash)
	if err != nil {
		// should never happen
		log.PanicE("invalid hash", err)
	}
	return h, nil
}
Example #2
0
File: fetcher.go Project: nhlfr/rkt
// FetchImage will take an image as either a path, a URL or a name
// string and import it into the store if found. If ascPath is not "",
// it must exist as a local file and will be used as the signature
// file for verification, unless verification is disabled. If
// f.WithDeps is true also image dependencies are fetched.
func (f *Fetcher) FetchImage(img string, ascPath string, imgType apps.AppImageType) (string, error) {
	ensureLogger(f.Debug)
	a := f.getAsc(ascPath)
	hash, err := f.fetchSingleImage(img, a, imgType)
	if err != nil {
		return "", err
	}
	if f.WithDeps {
		err = f.fetchImageDeps(hash)
		if err != nil {
			return "", err
		}
	}

	// we need to be able to do a chroot and access to the tree store
	// directories, we need to
	// 1) check if the system supports OverlayFS
	// 2) check if we're root
	if common.SupportsOverlay() == nil && os.Geteuid() == 0 {
		if _, _, err := f.Ts.Render(hash, false); err != nil {
			return "", errwrap.Wrap(errors.New("error rendering tree store"), err)
		}
	}
	return hash, nil
}
Example #3
0
func TestExport(t *testing.T) {
	if !common.SupportsOverlay() {
		t.Skip("Overlay fs not supported.")
	}

	// TODO(iaguis): we need a new function to unmount the fly pod so we can also test
	// overlaySimulateReboot
	NewTestExport(overlaySimpleTest).Execute(t)
}
Example #4
0
func TestExport(t *testing.T) {
	if err := common.SupportsOverlay(); err != nil {
		t.Skipf("Overlay fs not supported: %v", err)
	}
	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	// TODO(iaguis): we need a new function to unmount the fly pod so we can also test
	// overlaySimulateReboot
	exportTestCases["overlaySimpleTest"].Execute(t, ctx)
}
Example #5
0
func TestImageGCTreeStore(t *testing.T) {
	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	expectedTreeStores := 2
	// If overlayfs is not supported only the stage1 image is rendered in the treeStore
	if !common.SupportsOverlay() {
		expectedTreeStores = 1
	}

	// at this point we know that RKT_INSPECT_IMAGE env var is not empty
	referencedACI := os.Getenv("RKT_INSPECT_IMAGE")
	cmd := fmt.Sprintf("%s --insecure-options=image run --mds-register=false %s", ctx.Cmd(), referencedACI)
	t.Logf("Running %s: %v", referencedACI, cmd)
	child, err := gexpect.Spawn(cmd)
	if err != nil {
		t.Fatalf("Cannot exec: %v", err)
	}
	if err := child.Wait(); err != nil {
		t.Fatalf("rkt didn't terminate correctly: %v", err)
	}

	treeStoreIDs, err := getTreeStoreIDs(ctx)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	// We expect 2 treeStoreIDs for stage1 and app (only 1 if overlay is not supported/enabled)
	if len(treeStoreIDs) != expectedTreeStores {
		t.Fatalf("expected %d entries in the treestore but found %d entries", expectedTreeStores, len(treeStoreIDs))
	}

	runImageGC(t, ctx)

	treeStoreIDs, err = getTreeStoreIDs(ctx)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	// We expect 1/2 treeStoreIDs again as no pod gc has been executed
	if len(treeStoreIDs) != expectedTreeStores {
		t.Fatalf("expected %d entries in the treestore but found %d entries", expectedTreeStores, len(treeStoreIDs))
	}

	runGC(t, ctx)
	runImageGC(t, ctx)

	treeStoreIDs, err = getTreeStoreIDs(ctx)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if len(treeStoreIDs) != 0 {
		t.Fatalf("expected empty treestore but found %d entries", len(treeStoreIDs))
	}
}
Example #6
0
File: run.go Project: krieg/rkt
func preparedWithOverlay(dir string) (bool, error) {
	_, err := os.Stat(filepath.Join(dir, common.OverlayPreparedFilename))
	if os.IsNotExist(err) {
		return false, nil
	}
	if err != nil {
		return false, err
	}

	if !common.SupportsOverlay() {
		return false, fmt.Errorf("the pod was prepared with overlay but overlay is not supported")
	}

	return true, nil
}
func TestExport(t *testing.T) {
	testCases := []ExportTestCase{noOverlaySimpleTest}

	// Need to do both checks
	if common.SupportsUserNS() && checkUserNS() == nil {
		testCases = append(testCases, userNS)
	}

	if common.SupportsOverlay() {
		testCases = append(testCases, overlaySimpleTest)
		testCases = append(testCases, overlaySimulateReboot)
	}

	NewTestExport(testCases...).Execute(t)
}
Example #8
0
func TestRenderOnFetch(t *testing.T) {
	// If overlayfs is not supported, we don't render images on fetch
	if !common.SupportsOverlay() {
		t.Skip("Overlay fs not supported.")
	}
	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	server := runServer(t, taas.GetDefaultServerSetup())
	defer server.Close()

	fileSet, imageList := generateComplexDependencyTree(t, ctx)
	for _, img := range imageList {
		defer os.Remove(img.fileName)
	}

	if err := server.UpdateFileSet(fileSet); err != nil {
		t.Fatalf("Failed to populate a file list in test aci server: %v", err)
	}

	for i := len(imageList) - 1; i >= 0; i-- {
		img := imageList[i]
		if img.prefetch {
			t.Logf("Importing image %q: %q", img.imageName, img.fileName)
			testImageShortHash, err := importImageAndFetchHash(t, ctx, "", img.fileName)
			if err != nil {
				t.Fatalf("%v", err)
			}
			t.Logf("Imported image %q: %s", img.imageName, testImageShortHash)
		}
	}

	fetchCmd := fmt.Sprintf("%s --debug --insecure-options=image,tls fetch %s", ctx.Cmd(), topImage)
	child := spawnOrFail(t, fetchCmd)

	treeStoreDir := filepath.Join(ctx.DataDir(), "cas", "tree")
	trees, err := ioutil.ReadDir(treeStoreDir)
	if err != nil {
		panic(fmt.Sprintf("Cannot read tree store dir: %v", err))
	}

	// We expect 2 trees: stage1 and the image
	if len(trees) != 2 {
		t.Fatalf("Expected 2 trees but found %d", len(trees))
	}

	waitOrFail(t, child, 0)
}
func TestExport(t *testing.T) {
	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()
	overlay := (common.SupportsOverlay() == nil)
	userns := (common.SupportsUserNS() && checkUserNS() == nil && !TestedFlavor.Kvm)

	for name, testCase := range exportTestCases {
		if testCase.NeedsOverlay && !overlay {
			t.Logf("TestExport/%v needs overlay, skipping", name)
			continue
		}
		if testCase.NeedsUserNS && !userns {
			t.Logf("TestExport/%v needs userns, skipping", name)
			continue
		}
		t.Logf("TestExport/%v", name)
		testCase.Execute(t, ctx)
	}
}
Example #10
0
// FetchImage will take an image as either a path, a URL or a name
// string and import it into the store if found. If ascPath is not "",
// it must exist as a local file and will be used as the signature
// file for verification, unless verification is disabled. If
// f.WithDeps is true also image dependencies are fetched.
func (f *Fetcher) FetchImage(img string, ascPath string, imgType apps.AppImageType) (string, error) {
	ensureLogger(f.Debug)
	a := f.getAsc(ascPath)
	hash, err := f.fetchSingleImage(img, a, imgType)
	if err != nil {
		return "", err
	}
	if f.WithDeps {
		err = f.fetchImageDeps(hash)
		if err != nil {
			return "", err
		}
	}
	if common.SupportsOverlay() {
		if _, _, err := f.S.RenderTreeStore(hash, false); err != nil {
			return "", errwrap.Wrap(errors.New("error rendering tree store"), err)
		}
	}
	return hash, nil
}
Example #11
0
func TestGCAfterUnmount(t *testing.T) {
	if err := common.SupportsOverlay(); err != nil {
		t.Skipf("Overlay fs not supported: %v", err)
	}

	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	imagePath := getInspectImagePath()

	for _, rmNetns := range []bool{false, true} {
		_, err := importImageAndFetchHash(t, ctx, "", imagePath)
		if err != nil {
			t.Fatalf("%v", err)
		}
		cmd := fmt.Sprintf("%s --insecure-options=image prepare %s", ctx.Cmd(), imagePath)
		uuid := runRktAndGetUUID(t, cmd)

		cmd = fmt.Sprintf("%s run-prepared %s", ctx.Cmd(), uuid)
		runRktAndCheckOutput(t, cmd, "", false)

		unmountPod(t, ctx, uuid, rmNetns)

		pods := podsRemaining(t, ctx)
		if len(pods) == 0 {
			t.Fatalf("pods should still be present in rkt's data directory")
		}

		gcCmd := fmt.Sprintf("%s gc --debug --mark-only=false --expire-prepared=0 --grace-period=0", ctx.Cmd())
		// check we don't get any output (an error) after "executing net-plugin..."
		runRktAndCheckRegexOutput(t, gcCmd, `executing net-plugin .*\n\z`)

		pods = podsRemaining(t, ctx)
		if len(pods) != 0 {
			t.Fatalf("no pods should exist rkt's data directory, but found: %v", pods)
		}

	}
}
Example #12
0
File: prepare.go Project: krieg/rkt
func runPrepare(cmd *cobra.Command, args []string) (exit int) {
	var err error
	origStdout := os.Stdout
	if flagQuiet {
		if os.Stdout, err = os.Open("/dev/null"); err != nil {
			stderr("prepare: unable to open /dev/null")
			return 1
		}
	}

	if err = parseApps(&rktApps, args, cmd.Flags(), true); err != nil {
		stderr("prepare: error parsing app image arguments: %v", err)
		return 1
	}

	if len(flagPodManifest) > 0 && (len(flagVolumes) > 0 || len(flagPorts) > 0 || flagInheritEnv || !flagExplicitEnv.IsEmpty() || flagLocal) {
		stderr("prepare: conflicting flags set with --pod-manifest (see --help)")
		return 1
	}

	if rktApps.Count() < 1 && len(flagPodManifest) == 0 {
		stderr("prepare: must provide at least one image or specify the pod manifest")
		return 1
	}

	if globalFlags.Dir == "" {
		log.Printf("dir unset - using temporary directory")
		globalFlags.Dir, err = ioutil.TempDir("", "rkt")
		if err != nil {
			stderr("prepare: error creating temporary directory: %v", err)
			return 1
		}
	}

	s, err := store.NewStore(globalFlags.Dir)
	if err != nil {
		stderr("prepare: cannot open store: %v", err)
		return 1
	}

	config, err := getConfig()
	if err != nil {
		stderr("prepare: cannot get configuration: %v", err)
		return 1
	}
	fn := &finder{
		imageActionData: imageActionData{
			s:                  s,
			headers:            config.AuthPerHost,
			dockerAuth:         config.DockerCredentialsPerRegistry,
			insecureSkipVerify: globalFlags.InsecureSkipVerify,
			debug:              globalFlags.Debug,
		},
		local:    flagLocal,
		withDeps: false,
	}

	s1img, err := getStage1Hash(s, flagStage1Image)
	if err != nil {
		stderr("prepare: %v", err)
		return 1
	}

	fn.ks = getKeystore()
	fn.withDeps = true
	if err := fn.findImages(&rktApps); err != nil {
		stderr("%v", err)
		return 1
	}

	p, err := newPod()
	if err != nil {
		stderr("prepare: error creating new pod: %v", err)
		return 1
	}

	cfg := stage0.CommonConfig{
		Store:       s,
		Stage1Image: *s1img,
		UUID:        p.uuid,
		Debug:       globalFlags.Debug,
	}

	pcfg := stage0.PrepareConfig{
		CommonConfig: cfg,
		UseOverlay:   !flagNoOverlay && common.SupportsOverlay(),
	}

	if len(flagPodManifest) > 0 {
		pcfg.PodManifest = flagPodManifest
	} else {
		pcfg.Volumes = []types.Volume(flagVolumes)
		pcfg.Ports = []types.ExposedPort(flagPorts)
		pcfg.InheritEnv = flagInheritEnv
		pcfg.ExplicitEnv = flagExplicitEnv.Strings()
		pcfg.Apps = &rktApps
	}

	if err = stage0.Prepare(pcfg, p.path(), p.uuid); err != nil {
		stderr("prepare: error setting up stage0: %v", err)
		return 1
	}

	if err := p.sync(); err != nil {
		stderr("prepare: error syncing pod data: %v", err)
		return 1
	}

	if err := p.xToPrepared(); err != nil {
		stderr("prepare: error transitioning to prepared: %v", err)
		return 1
	}

	os.Stdout = origStdout // restore output in case of --quiet
	stdout("%s", p.uuid.String())

	return 0
}
Example #13
0
func runRun(cmd *cobra.Command, args []string) (exit int) {
	privateUsers := user.NewBlankUidRange()
	err := parseApps(&rktApps, args, cmd.Flags(), true)
	if err != nil {
		stderr.PrintE("error parsing app image arguments", err)
		return 1
	}

	if flagStoreOnly && flagNoStore {
		stderr.Print("both --store-only and --no-store specified")
		return 1
	}

	if flagPrivateUsers {
		if !common.SupportsUserNS() {
			stderr.Print("--private-users is not supported, kernel compiled without user namespace support")
			return 1
		}
		privateUsers.SetRandomUidRange(user.DefaultRangeCount)
	}

	if len(flagPorts) > 0 && flagNet.None() {
		stderr.Print("--port flag does not work with 'none' networking")
		return 1
	}
	if len(flagPorts) > 0 && flagNet.Host() {
		stderr.Print("--port flag does not work with 'host' networking")
		return 1
	}

	if flagMDSRegister && flagNet.None() {
		stderr.Print("--mds-register flag does not work with --net=none. Please use 'host', 'default' or an equivalent network")
		return 1
	}

	if len(flagPodManifest) > 0 && (len(flagPorts) > 0 || rktApps.Count() > 0 || flagStoreOnly || flagNoStore ||
		flagInheritEnv || !flagExplicitEnv.IsEmpty() || !flagEnvFromFile.IsEmpty() ||
		(*appsVolume)(&rktApps).String() != "" || (*appMount)(&rktApps).String() != "" || (*appExec)(&rktApps).String() != "" ||
		(*appUser)(&rktApps).String() != "" || (*appGroup)(&rktApps).String() != "" ||
		(*appCapsRetain)(&rktApps).String() != "" || (*appCapsRemove)(&rktApps).String() != "") {
		stderr.Print("conflicting flags set with --pod-manifest (see --help)")
		return 1
	}

	if flagInteractive && rktApps.Count() > 1 {
		stderr.Print("interactive option only supports one image")
		return 1
	}

	if rktApps.Count() < 1 && len(flagPodManifest) == 0 {
		stderr.Print("must provide at least one image or specify the pod manifest")
		return 1
	}

	s, err := imagestore.NewStore(storeDir())
	if err != nil {
		stderr.PrintE("cannot open store", err)
		return 1
	}

	ts, err := treestore.NewStore(treeStoreDir(), s)
	if err != nil {
		stderr.PrintE("cannot open treestore", err)
		return 1
	}

	config, err := getConfig()
	if err != nil {
		stderr.PrintE("cannot get configuration", err)
		return 1
	}

	s1img, err := getStage1Hash(s, ts, config)
	if err != nil {
		stderr.Error(err)
		return 1
	}

	fn := &image.Finder{
		S:                  s,
		Ts:                 ts,
		Ks:                 getKeystore(),
		Headers:            config.AuthPerHost,
		DockerAuth:         config.DockerCredentialsPerRegistry,
		InsecureFlags:      globalFlags.InsecureFlags,
		Debug:              globalFlags.Debug,
		TrustKeysFromHTTPS: globalFlags.TrustKeysFromHTTPS,

		StoreOnly: flagStoreOnly,
		NoStore:   flagNoStore,
		WithDeps:  true,
	}
	if err := fn.FindImages(&rktApps); err != nil {
		stderr.Error(err)
		return 1
	}

	p, err := newPod()
	if err != nil {
		stderr.PrintE("error creating new pod", err)
		return 1
	}

	// if requested, write out pod UUID early so "rkt rm" can
	// clean it up even if something goes wrong
	if flagUUIDFileSave != "" {
		if err := writeUUIDToFile(p.uuid, flagUUIDFileSave); err != nil {
			stderr.PrintE("error saving pod UUID to file", err)
			return 1
		}
	}

	processLabel, mountLabel, err := label.InitLabels([]string{"mcsdir:/var/run/rkt/mcs"})
	if err != nil {
		stderr.PrintE("error initialising SELinux", err)
		return 1
	}

	p.mountLabel = mountLabel

	cfg := stage0.CommonConfig{
		MountLabel:   mountLabel,
		ProcessLabel: processLabel,
		Store:        s,
		TreeStore:    ts,
		Stage1Image:  *s1img,
		UUID:         p.uuid,
		Debug:        globalFlags.Debug,
	}

	pcfg := stage0.PrepareConfig{
		CommonConfig:       &cfg,
		UseOverlay:         !flagNoOverlay && common.SupportsOverlay() && common.FSSupportsOverlay(getDataDir()),
		PrivateUsers:       privateUsers,
		SkipTreeStoreCheck: globalFlags.InsecureFlags.SkipOnDiskCheck(),
	}

	if len(flagPodManifest) > 0 {
		pcfg.PodManifest = flagPodManifest
	} else {
		pcfg.Ports = []types.ExposedPort(flagPorts)
		pcfg.InheritEnv = flagInheritEnv
		pcfg.ExplicitEnv = flagExplicitEnv.Strings()
		pcfg.EnvFromFile = flagEnvFromFile.Strings()
		pcfg.Apps = &rktApps
	}

	if globalFlags.Debug {
		stage0.InitDebug()
	}

	keyLock, err := lock.SharedKeyLock(lockDir(), common.PrepareLock)
	if err != nil {
		stderr.PrintE("cannot get shared prepare lock", err)
		return 1
	}
	err = stage0.Prepare(pcfg, p.path(), p.uuid)
	if err != nil {
		stderr.PrintE("error setting up stage0", err)
		keyLock.Close()
		return 1
	}
	keyLock.Close()

	// get the lock fd for run
	lfd, err := p.Fd()
	if err != nil {
		stderr.PrintE("error getting pod lock fd", err)
		return 1
	}

	// skip prepared by jumping directly to run, we own this pod
	if err := p.xToRun(); err != nil {
		stderr.PrintE("unable to transition to run", err)
		return 1
	}

	rktgid, err := common.LookupGid(common.RktGroup)
	if err != nil {
		stderr.Printf("group %q not found, will use default gid when rendering images", common.RktGroup)
		rktgid = -1
	}

	rcfg := stage0.RunConfig{
		CommonConfig: &cfg,
		Net:          flagNet,
		LockFd:       lfd,
		Interactive:  flagInteractive,
		DNS:          flagDNS,
		DNSSearch:    flagDNSSearch,
		DNSOpt:       flagDNSOpt,
		MDSRegister:  flagMDSRegister,
		LocalConfig:  globalFlags.LocalConfigDir,
		RktGid:       rktgid,
		Hostname:     flagHostname,
	}

	apps, err := p.getApps()
	if err != nil {
		stderr.PrintE("cannot get the appList in the pod manifest", err)
		return 1
	}
	rcfg.Apps = apps
	stage0.Run(rcfg, p.path(), getDataDir()) // execs, never returns

	return 1
}
Example #14
0
func runRun(cmd *cobra.Command, args []string) (exit int) {
	privateUsers := uid.NewBlankUidRange()
	err := parseApps(&rktApps, args, cmd.Flags(), true)
	if err != nil {
		stderr("run: error parsing app image arguments: %v", err)
		return 1
	}

	if flagStoreOnly && flagNoStore {
		stderr("both --store-only and --no-store specified")
		return 1
	}

	if flagPrivateUsers {
		if !common.SupportsUserNS() {
			stderr("run: --private-users is not supported, kernel compiled without user namespace support")
			return 1
		}
		privateUsers.SetRandomUidRange(uid.DefaultRangeCount)
	}

	if len(flagPorts) > 0 && flagNet.None() {
		stderr("--port flag does not work with 'none' networking")
		return 1
	}
	if len(flagPorts) > 0 && flagNet.Host() {
		stderr("--port flag does not work with 'host' networking")
		return 1
	}

	if flagMDSRegister && flagNet.None() {
		stderr("--mds-register flag does not work with --net=none. Please use 'host', 'default' or an equivalent network")
		return 1
	}

	if len(flagPodManifest) > 0 && (len(flagPorts) > 0 || flagInheritEnv || !flagExplicitEnv.IsEmpty() || rktApps.Count() > 0 || flagStoreOnly || flagNoStore) {
		stderr("conflicting flags set with --pod-manifest (see --help)")
		return 1
	}

	if flagInteractive && rktApps.Count() > 1 {
		stderr("run: interactive option only supports one image")
		return 1
	}

	if rktApps.Count() < 1 && len(flagPodManifest) == 0 {
		stderr("run: must provide at least one image or specify the pod manifest")
		return 1
	}

	s, err := store.NewStore(globalFlags.Dir)
	if err != nil {
		stderr("run: cannot open store: %v", err)
		return 1
	}

	config, err := getConfig()
	if err != nil {
		stderr("run: cannot get configuration: %v", err)
		return 1
	}
	fn := &finder{
		imageActionData: imageActionData{
			s:                  s,
			headers:            config.AuthPerHost,
			dockerAuth:         config.DockerCredentialsPerRegistry,
			insecureSkipVerify: globalFlags.InsecureSkipVerify,
			debug:              globalFlags.Debug,
		},
		storeOnly: flagStoreOnly,
		noStore:   flagNoStore,
		withDeps:  false,
	}

	s1img, err := getStage1Hash(s, cmd)
	if err != nil {
		stderr("%v", err)
		return 1
	}

	fn.ks = getKeystore()
	fn.withDeps = true
	if err := fn.findImages(&rktApps); err != nil {
		stderr("%v", err)
		return 1
	}

	p, err := newPod()
	if err != nil {
		stderr("Error creating new pod: %v", err)
		return 1
	}

	// if requested, write out pod UUID early so "rkt rm" can
	// clean it up even if something goes wrong
	if flagUUIDFileSave != "" {
		if err := writeUUIDToFile(p.uuid, flagUUIDFileSave); err != nil {
			stderr("Error saving pod UUID to file: %v", err)
			return 1
		}
	}

	processLabel, mountLabel, err := label.InitLabels(nil)
	if err != nil {
		stderr("Error initialising SELinux: %v", err)
		return 1
	}

	cfg := stage0.CommonConfig{
		MountLabel:   mountLabel,
		ProcessLabel: processLabel,
		Store:        s,
		Stage1Image:  *s1img,
		UUID:         p.uuid,
		Debug:        globalFlags.Debug,
	}

	pcfg := stage0.PrepareConfig{
		CommonConfig: cfg,
		UseOverlay:   !flagNoOverlay && common.SupportsOverlay(),
		PrivateUsers: privateUsers,
	}

	if len(flagPodManifest) > 0 {
		pcfg.PodManifest = flagPodManifest
	} else {
		pcfg.Ports = []types.ExposedPort(flagPorts)
		pcfg.InheritEnv = flagInheritEnv
		pcfg.ExplicitEnv = flagExplicitEnv.Strings()
		pcfg.Apps = &rktApps
	}

	if globalFlags.Debug {
		stage0.InitDebug()
	}

	keyLock, err := lock.SharedKeyLock(lockDir(), common.PrepareLock)
	if err != nil {
		stderr("rkt: cannot get shared prepare lock: %v", err)
		return 1
	}
	err = stage0.Prepare(pcfg, p.path(), p.uuid)
	if err != nil {
		stderr("run: error setting up stage0: %v", err)
		keyLock.Close()
		return 1
	}
	keyLock.Close()

	// get the lock fd for run
	lfd, err := p.Fd()
	if err != nil {
		stderr("Error getting pod lock fd: %v", err)
		return 1
	}

	// skip prepared by jumping directly to run, we own this pod
	if err := p.xToRun(); err != nil {
		stderr("run: unable to transition to run: %v", err)
		return 1
	}

	rktgid, err := common.LookupGid(common.RktGroup)
	if err != nil {
		stderr("run: group %q not found, will use default gid when rendering images", common.RktGroup)
		rktgid = -1
	}

	rcfg := stage0.RunConfig{
		CommonConfig: cfg,
		Net:          flagNet,
		LockFd:       lfd,
		Interactive:  flagInteractive,
		MDSRegister:  flagMDSRegister,
		LocalConfig:  globalFlags.LocalConfigDir,
		RktGid:       rktgid,
	}

	apps, err := p.getApps()
	if err != nil {
		stderr("run: cannot get the appList in the pod manifest: %v", err)
		return 1
	}
	rcfg.Apps = apps
	stage0.Run(rcfg, p.path(), globalFlags.Dir) // execs, never returns

	return 1
}
Example #15
0
func TestImageSize(t *testing.T) {
	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	image := patchTestACI("rkt-size.aci", "--no-compression", "--name=size-test")
	defer os.Remove(image)

	imageHash := "sha512-" + getHashOrPanic(image)[:64]

	fi, err := os.Stat(image)
	if err != nil {
		t.Fatalf("cannot stat image %q: %v", image, err)
	}
	imageSize := fi.Size()

	fetchCmd := fmt.Sprintf("%s --insecure-options=image fetch %s", ctx.Cmd(), image)
	spawnAndWaitOrFail(t, fetchCmd, 0)

	imageListCmd := fmt.Sprintf("%s image list --no-legend --full", ctx.Cmd())

	// if we don't support overlay fs, we don't render the image on fetch
	if !common.SupportsOverlay() {
		// check that the printed size is the same as the actual image size
		expectedStr := fmt.Sprintf("(?s)%s.*%d.*", imageHash, imageSize)

		runRktAndCheckRegexOutput(t, imageListCmd, expectedStr)

		// run the image, so rkt renders it in the tree store
		runCmd := fmt.Sprintf("%s --insecure-options=image run %s", ctx.Cmd(), image)
		spawnAndWaitOrFail(t, runCmd, 0)
	}

	tmpDir := createTempDirOrPanic("rkt_image_list_test")
	defer os.RemoveAll(tmpDir)
	imageRenderCmd := fmt.Sprintf("%s image render --overwrite %s %s", ctx.Cmd(), imageHash, tmpDir)
	spawnAndWaitOrFail(t, imageRenderCmd, 0)
	/*
		recreate the tree store directory contents to get an accurate size:
		- hash file
		- image file
		- rendered file
		NOTE: if/when we add new files to the tree store directory, this test
		will fail and will need an update.
	*/
	if err := ioutil.WriteFile(filepath.Join(tmpDir, "hash"), []byte(imageHash), 0600); err != nil {
		t.Fatalf(`error writing "hash" file: %v`, err)
	}
	if err := ioutil.WriteFile(filepath.Join(tmpDir, "image"), []byte(imageHash), 0600); err != nil {
		t.Fatalf(`error writing "image" file: %v`, err)
	}
	if err := ioutil.WriteFile(filepath.Join(tmpDir, "rendered"), []byte{}, 0600); err != nil {
		t.Fatalf(`error writing "rendered" file: %v`, err)
	}
	tsSize, err := fileutil.DirSize(tmpDir)
	if err != nil {
		t.Fatalf("error calculating rendered size: %v", err)
	}

	// check the size with the rendered image
	expectedStr := fmt.Sprintf("(?s)%s.*%d.*", imageHash, imageSize+tsSize)
	runRktAndCheckRegexOutput(t, imageListCmd, expectedStr)

	// gc the pod
	gcCmd := fmt.Sprintf("%s gc --grace-period=0s", ctx.Cmd())
	spawnAndWaitOrFail(t, gcCmd, 0)

	// image gc to remove the tree store
	imageGCCmd := fmt.Sprintf("%s image gc", ctx.Cmd())
	spawnAndWaitOrFail(t, imageGCCmd, 0)

	// check that the size goes back to the original (only the image size)
	expectedStr = fmt.Sprintf("(?s)%s.*%d.*", imageHash, imageSize)
	runRktAndCheckRegexOutput(t, imageListCmd, expectedStr)
}
Example #16
0
File: run.go Project: fdserr/rkt
func runRun(cmd *cobra.Command, args []string) (exit int) {
	err := parseApps(&rktApps, args, cmd.Flags(), true)
	if err != nil {
		stderr("run: error parsing app image arguments: %v", err)
		return 1
	}

	if len(flagPorts) > 0 && !flagPrivateNet.Any() {
		stderr("--port flag requires --private-net")
		return 1
	}

	if len(flagPodManifest) > 0 && (len(flagVolumes) > 0 || len(flagPorts) > 0 || flagInheritEnv || !flagExplicitEnv.IsEmpty() || rktApps.Count() > 0 || flagLocal) {
		stderr("conflicting flags set with --pod-manifest (see --help)")
		return 1
	}

	if globalFlags.Dir == "" {
		log.Printf("dir unset - using temporary directory")
		var err error
		globalFlags.Dir, err = ioutil.TempDir("", "rkt")
		if err != nil {
			stderr("error creating temporary directory: %v", err)
			return 1
		}
	}

	if flagInteractive && rktApps.Count() > 1 {
		stderr("run: interactive option only supports one image")
		return 1
	}

	if rktApps.Count() < 1 && len(flagPodManifest) == 0 {
		stderr("run: must provide at least one image or specify the pod manifest")
		return 1
	}

	s, err := store.NewStore(globalFlags.Dir)
	if err != nil {
		stderr("run: cannot open store: %v", err)
		return 1
	}

	config, err := getConfig()
	if err != nil {
		stderr("run: cannot get configuration: %v", err)
		return 1
	}
	fn := &finder{
		imageActionData: imageActionData{
			s:                  s,
			headers:            config.AuthPerHost,
			dockerAuth:         config.DockerCredentialsPerRegistry,
			insecureSkipVerify: globalFlags.InsecureSkipVerify,
			debug:              globalFlags.Debug,
		},
		local:    flagLocal,
		withDeps: false,
	}
	s1img, err := fn.findImage(flagStage1Image, "", false)
	if err != nil {
		stderr("Error finding stage1 image %q: %v", flagStage1Image, err)
		return 1
	}

	fn.ks = getKeystore()
	fn.withDeps = true
	if err := fn.findImages(&rktApps); err != nil {
		stderr("%v", err)
		return 1
	}

	p, err := newPod()
	if err != nil {
		stderr("Error creating new pod: %v", err)
		return 1
	}

	processLabel, mountLabel, err := label.InitLabels(nil)
	if err != nil {
		stderr("Error initialising SELinux: %v", err)
		return 1
	}

	cfg := stage0.CommonConfig{
		MountLabel:   mountLabel,
		ProcessLabel: processLabel,
		Store:        s,
		Stage1Image:  *s1img,
		UUID:         p.uuid,
		Debug:        globalFlags.Debug,
	}

	pcfg := stage0.PrepareConfig{
		CommonConfig: cfg,
		UseOverlay:   !flagNoOverlay && common.SupportsOverlay(),
	}

	if len(flagPodManifest) > 0 {
		pcfg.PodManifest = flagPodManifest
	} else {
		pcfg.Volumes = []types.Volume(flagVolumes)
		pcfg.Ports = []types.ExposedPort(flagPorts)
		pcfg.InheritEnv = flagInheritEnv
		pcfg.ExplicitEnv = flagExplicitEnv.Strings()
		pcfg.Apps = &rktApps
	}

	err = stage0.Prepare(pcfg, p.path(), p.uuid)
	if err != nil {
		stderr("run: error setting up stage0: %v", err)
		return 1
	}

	// get the lock fd for run
	lfd, err := p.Fd()
	if err != nil {
		stderr("Error getting pod lock fd: %v", err)
		return 1
	}

	// skip prepared by jumping directly to run, we own this pod
	if err := p.xToRun(); err != nil {
		stderr("run: unable to transition to run: %v", err)
		return 1
	}

	rcfg := stage0.RunConfig{
		CommonConfig: cfg,
		PrivateNet:   flagPrivateNet,
		LockFd:       lfd,
		Interactive:  flagInteractive,
		MDSRegister:  flagMDSRegister,
		LocalConfig:  globalFlags.LocalConfigDir,
	}

	imgs, err := p.getApps()
	if err != nil {
		stderr("run: cannot get the image hashes in the pod manifest: %v", err)
		return 1
	}
	rcfg.Images = imgs
	stage0.Run(rcfg, p.path()) // execs, never returns

	return 1
}
Example #17
0
func runPrepare(cmd *cobra.Command, args []string) (exit int) {
	var err error
	origStdout := os.Stdout
	privateUsers := uid.NewBlankUidRange()
	if flagQuiet {
		if os.Stdout, err = os.Open("/dev/null"); err != nil {
			stderr("prepare: unable to open /dev/null: %v", err)
			return 1
		}
	}

	if flagStoreOnly && flagNoStore {
		stderr("both --store-only and --no-store specified")
		return 1
	}

	if flagPrivateUsers {
		if !common.SupportsUserNS() {
			stderr("prepare: --private-users is not supported, kernel compiled without user namespace support")
			return 1
		}
		privateUsers.SetRandomUidRange(uid.DefaultRangeCount)
	}

	if err = parseApps(&rktApps, args, cmd.Flags(), true); err != nil {
		stderr("prepare: error parsing app image arguments: %v", err)
		return 1
	}

	if len(flagPodManifest) > 0 && (len(flagPorts) > 0 || flagInheritEnv || !flagExplicitEnv.IsEmpty() || flagStoreOnly || flagNoStore) {
		stderr("prepare: conflicting flags set with --pod-manifest (see --help)")
		return 1
	}

	if rktApps.Count() < 1 && len(flagPodManifest) == 0 {
		stderr("prepare: must provide at least one image or specify the pod manifest")
		return 1
	}

	s, err := store.NewStore(getDataDir())
	if err != nil {
		stderr("prepare: cannot open store: %v", err)
		return 1
	}

	config, err := getConfig()
	if err != nil {
		stderr("prepare: cannot get configuration: %v", err)
		return 1
	}

	s1img, err := getStage1Hash(s, cmd)
	if err != nil {
		stderr("prepare: %v", err)
		return 1
	}

	fn := &image.Finder{
		S:                  s,
		Ks:                 getKeystore(),
		Headers:            config.AuthPerHost,
		DockerAuth:         config.DockerCredentialsPerRegistry,
		InsecureFlags:      globalFlags.InsecureFlags,
		Debug:              globalFlags.Debug,
		TrustKeysFromHttps: globalFlags.TrustKeysFromHttps,

		StoreOnly: flagStoreOnly,
		NoStore:   flagNoStore,
		WithDeps:  true,
	}
	if err := fn.FindImages(&rktApps); err != nil {
		stderr("prepare: %v", err)
		return 1
	}

	p, err := newPod()
	if err != nil {
		stderr("prepare: error creating new pod: %v", err)
		return 1
	}

	cfg := stage0.CommonConfig{
		Store:       s,
		Stage1Image: *s1img,
		UUID:        p.uuid,
		Debug:       globalFlags.Debug,
	}

	pcfg := stage0.PrepareConfig{
		CommonConfig: &cfg,
		UseOverlay:   !flagNoOverlay && common.SupportsOverlay(),
		PrivateUsers: privateUsers,
	}

	if len(flagPodManifest) > 0 {
		pcfg.PodManifest = flagPodManifest
	} else {
		pcfg.Ports = []types.ExposedPort(flagPorts)
		pcfg.InheritEnv = flagInheritEnv
		pcfg.ExplicitEnv = flagExplicitEnv.Strings()
		pcfg.Apps = &rktApps
	}

	if globalFlags.Debug {
		stage0.InitDebug()
	}

	keyLock, err := lock.SharedKeyLock(lockDir(), common.PrepareLock)
	if err != nil {
		stderr("rkt: cannot get shared prepare lock: %v", err)
		return 1
	}
	if err = stage0.Prepare(pcfg, p.path(), p.uuid); err != nil {
		stderr("prepare: error setting up stage0: %v", err)
		keyLock.Close()
		return 1
	}
	keyLock.Close()

	if err := p.sync(); err != nil {
		stderr("prepare: error syncing pod data: %v", err)
		return 1
	}

	if err := p.xToPrepared(); err != nil {
		stderr("prepare: error transitioning to prepared: %v", err)
		return 1
	}

	os.Stdout = origStdout // restore output in case of --quiet
	stdout("%s", p.uuid.String())

	return 0
}