Exemple #1
0
func TestGetStoreKeyFromApp(t *testing.T) {
	dir, err := ioutil.TempDir("", "fetch-image")
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)
	s, err := imagestore.NewStore(dir)
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	defer s.Dump(false)

	// Test an aci without os and arch labels
	a, err := aci.NewBasicACI(dir, "example.com/app")
	defer a.Close()
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	// Rewind the ACI
	if _, err := a.Seek(0, 0); err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	_, err = s.WriteACI(a, imagestore.ACIFetchInfo{Latest: false})
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}

	_, err = getStoreKeyFromApp(s, "example.com/app")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}
Exemple #2
0
func runGCImage(cmd *cobra.Command, args []string) (exit int) {
	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 store", err)
		return
	}

	if err := gcTreeStore(ts); err != nil {
		stderr.PrintE("failed to remove unreferenced treestores", err)
		return 1
	}

	if err := gcStore(s, flagImageGracePeriod); err != nil {
		stderr.Error(err)
		return 1
	}

	return 0
}
Exemple #3
0
func runImageExport(cmd *cobra.Command, args []string) (exit int) {
	if len(args) != 2 {
		cmd.Usage()
		return 1
	}

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

	key, err := getStoreKeyFromAppOrHash(s, args[0])
	if err != nil {
		stderr.Error(err)
		return 1
	}

	aci, err := s.ReadStream(key)
	if err != nil {
		stderr.PrintE("error reading image", err)
		return 1
	}
	defer aci.Close()

	mode := os.O_CREATE | os.O_WRONLY
	if flagOverwriteACI {
		mode |= os.O_TRUNC
	} else {
		mode |= os.O_EXCL
	}
	f, err := os.OpenFile(args[1], mode, 0644)
	if err != nil {
		if os.IsExist(err) {
			stderr.Print("output ACI file exists (try --overwrite)")
		} else {
			stderr.PrintE(fmt.Sprintf("unable to open output ACI file %s", args[1]), err)
		}
		return 1
	}
	defer func() {
		err := f.Close()
		if err != nil {
			stderr.PrintE("error closing output ACI file", err)
			exit = 1
		}
	}()

	_, err = io.Copy(f, aci)
	if err != nil {
		stderr.PrintE("error writing to output ACI file", err)
		return 1
	}

	return 0
}
Exemple #4
0
Fichier : gc.go Projet : nhlfr/rkt
// deletePod cleans up files and resource associated with the pod
// pod must be under exclusive lock and be in either ExitedGarbage
// or Garbage state
func deletePod(p *pkgPod.Pod) {
	podState := p.State()
	if podState != pkgPod.ExitedGarbage && podState != pkgPod.Garbage {
		stderr.Panicf("logic error: deletePod called with non-garbage pod %q (status %q)", p.UUID, p.State())
	}

	if podState == pkgPod.ExitedGarbage {
		s, err := imagestore.NewStore(storeDir())
		if err != nil {
			stderr.PrintE("cannot open store", err)
			return
		}
		defer s.Close()

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

		if globalFlags.Debug {
			stage0.InitDebug()
		}

		if err := mountPodStage1(ts, p); err == nil {
			if err = stage0.GC(p.Path(), p.UUID); err != nil {
				stderr.PrintE(fmt.Sprintf("problem performing stage1 GC on %q", p.UUID), err)
			}
			// an overlay fs can be mounted over itself, let's unmount it here
			// if we mounted it before to avoid problems when running
			// stage0.MountGC
			if p.UsesOverlay() {
				stage1Mnt := common.Stage1RootfsPath(p.Path())
				if err := syscall.Unmount(stage1Mnt, 0); err != nil {
					stderr.PrintE("error unmounting stage1", err)
				}
			}
		} else {
			stderr.PrintE("skipping stage1 GC", err)
		}

		// unmount all leftover mounts
		if err := stage0.MountGC(p.Path(), p.UUID.String()); err != nil {
			stderr.PrintE(fmt.Sprintf("GC of leftover mounts for pod %q failed", p.UUID), err)
			return
		}
	}

	if err := os.RemoveAll(p.Path()); err != nil {
		stderr.PrintE(fmt.Sprintf("unable to remove pod %q", p.UUID), err)
		os.Exit(254)
	}
}
Exemple #5
0
func newV1AlphaAPIServer() (*v1AlphaAPIServer, error) {
	s, err := imagestore.NewStore(storeDir())
	if err != nil {
		return nil, err
	}

	cache, err := lru.New(defaultCacheSize)
	if err != nil {
		return nil, err
	}

	return &v1AlphaAPIServer{
		store:    s,
		podCache: cache,
	}, nil
}
Exemple #6
0
func TestTreeStoreRemove(t *testing.T) {
	if !sys.HasChrootCapability() {
		t.Skipf("chroot capability not available. Disabling test.")
	}

	dir, err := ioutil.TempDir("", tstprefix)
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)

	s, err := imagestore.NewStore(dir)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	ts, err := NewStore(dir, s)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	key, err := testStoreWriteACI(dir, s)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	id := "treestoreid01"

	// Test non existent dir
	err = ts.remove(id)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Test rendered tree
	_, err = ts.render(id, key)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	err = ts.remove(id)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}
Exemple #7
0
func runRmImage(cmd *cobra.Command, args []string) (exit int) {
	if len(args) < 1 {
		stderr.Print("must provide at least one image ID")
		return 254
	}

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

	if err := rmImages(s, args); err != nil {
		stderr.Error(err)
		return 254
	}

	return 0
}
Exemple #8
0
// mountOverlay mounts the app from the overlay-rendered pod to the destination directory.
func mountOverlay(pod *pod, app *schema.RuntimeApp, dest string) error {
	if _, err := os.Stat(dest); err != nil {
		return err
	}

	s, err := imagestore.NewStore(getDataDir())
	if err != nil {
		return errwrap.Wrap(errors.New("cannot open store"), err)
	}

	ts, err := treestore.NewStore(treeStoreDir(), s)
	if err != nil {
		return errwrap.Wrap(errors.New("cannot open treestore"), err)
	}

	treeStoreID, err := pod.getAppTreeStoreID(app.Name)
	if err != nil {
		return err
	}
	lower := ts.GetRootFS(treeStoreID)
	imgDir := filepath.Join(filepath.Join(pod.path(), "overlay"), treeStoreID)
	if _, err := os.Stat(imgDir); err != nil {
		return err
	}
	upper := filepath.Join(imgDir, "upper", app.Name.String())
	if _, err := os.Stat(upper); err != nil {
		return err
	}
	work := filepath.Join(imgDir, "work", app.Name.String())
	if _, err := os.Stat(work); err != nil {
		return err
	}

	if err := overlay.Mount(&overlay.MountCfg{lower, upper, work, dest, ""}); err != nil {
		return errwrap.Wrap(errors.New("problem mounting overlayfs directory"), err)
	}

	return nil
}
Exemple #9
0
func runImageCatManifest(cmd *cobra.Command, args []string) (exit int) {
	if len(args) != 1 {
		cmd.Usage()
		return 1
	}

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

	key, err := getStoreKeyFromAppOrHash(s, args[0])
	if err != nil {
		stderr.Error(err)
		return 1
	}

	manifest, err := s.GetImageManifest(key)
	if err != nil {
		stderr.PrintE("cannot get image manifest", err)
		return 1
	}

	var b []byte
	if flagPrettyPrint {
		b, err = json.MarshalIndent(manifest, "", "\t")
	} else {
		b, err = json.Marshal(manifest)
	}
	if err != nil {
		stderr.PrintE("cannot read the image manifest", err)
		return 1
	}

	stdout.Print(string(b))
	return 0
}
Exemple #10
0
func runImages(cmd *cobra.Command, args []string) int {
	var errors []error
	tabBuffer := new(bytes.Buffer)
	tabOut := getTabOutWithWriter(tabBuffer)

	if !flagNoLegend {
		var headerFields []string
		for _, f := range flagImagesFields.Options {
			headerFields = append(headerFields, ImagesFieldHeaderMap[f])
		}
		fmt.Fprintf(tabOut, "%s\n", strings.Join(headerFields, "\t"))
	}

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

	remotes, err := s.GetAllRemotes()
	if err != nil {
		stderr.PrintE("unable to get remotes", err)
		return 1
	}

	remoteMap := make(map[string]*imagestore.Remote)
	for _, r := range remotes {
		remoteMap[r.BlobKey] = r
	}

	var sortAciinfoFields []string
	for _, f := range flagImagesSortFields.Options {
		sortAciinfoFields = append(sortAciinfoFields, ImagesFieldAciInfoMap[f])
	}
	aciInfos, err := s.GetAllACIInfos(sortAciinfoFields, bool(flagImagesSortAsc))
	if err != nil {
		stderr.PrintE("unable to get aci infos", err)
		return 1
	}

	for _, aciInfo := range aciInfos {
		imj, err := s.GetImageManifestJSON(aciInfo.BlobKey)
		if err != nil {
			// ignore aciInfo with missing image manifest as it can be deleted in the meantime
			continue
		}
		var im *schema.ImageManifest
		if err = json.Unmarshal(imj, &im); err != nil {
			errors = append(errors, newImgListLoadError(err, imj, aciInfo.BlobKey))
			continue
		}
		version, ok := im.Labels.Get("version")
		var fieldValues []string
		for _, f := range flagImagesFields.Options {
			fieldValue := ""
			switch f {
			case l(id):
				hashKey := aciInfo.BlobKey
				if !flagFullOutput {
					// The short hash form is [HASH_ALGO]-[FIRST 12 CHAR]
					// For example, sha512-123456789012
					pos := strings.Index(hashKey, "-")
					trimLength := pos + 13
					if pos > 0 && trimLength < len(hashKey) {
						hashKey = hashKey[:trimLength]
					}
				}
				fieldValue = hashKey
			case l(name):
				fieldValue = aciInfo.Name
				if ok {
					fieldValue = fmt.Sprintf("%s:%s", fieldValue, version)
				}
			case l(importTime):
				if flagFullOutput {
					fieldValue = aciInfo.ImportTime.Format(defaultTimeLayout)
				} else {
					fieldValue = humanize.Time(aciInfo.ImportTime)
				}
			case l(lastUsed):
				if flagFullOutput {
					fieldValue = aciInfo.LastUsed.Format(defaultTimeLayout)
				} else {
					fieldValue = humanize.Time(aciInfo.LastUsed)
				}
			case l(size):
				totalSize := aciInfo.Size + aciInfo.TreeStoreSize
				if flagFullOutput {
					fieldValue = fmt.Sprintf("%d", totalSize)
				} else {
					fieldValue = humanize.IBytes(uint64(totalSize))
				}
			case l(latest):
				fieldValue = fmt.Sprintf("%t", aciInfo.Latest)
			case l(insecureOptions):
				f, err := rktflag.NewSecFlagsFromValue(int(aciInfo.InsecureOptions))
				if err != nil {
					stderr.Error(err)
					return 1
				}

				// remove ondisk, it's a runtime insecure option
				sp := strings.Split(f.String(), ",")
				for i, o := range sp {
					if o == "ondisk" {
						sp = append(sp[:i], sp[i+1:]...)
					}
				}

				fieldValue = fmt.Sprintf("%s", strings.Join(sp, ","))
			case l(aciURL):
				if imageRemote := remoteMap[aciInfo.BlobKey]; imageRemote == nil {
					fieldValue = ""
				} else {
					fieldValue = fmt.Sprintf("%s", imageRemote.ACIURL)
				}
			case l(signatureURL):
				if imageRemote := remoteMap[aciInfo.BlobKey]; imageRemote == nil {
					fieldValue = ""
				} else {
					fieldValue = fmt.Sprintf("%s", imageRemote.SigURL)
				}
			}
			fieldValues = append(fieldValues, fieldValue)

		}
		fmt.Fprintf(tabOut, "%s\n", strings.Join(fieldValues, "\t"))
	}

	if len(errors) > 0 {
		sep := "----------------------------------------"
		stderr.Printf("%d error(s) encountered when listing images:", len(errors))
		stderr.Print(sep)
		for _, err := range errors {
			stderr.Error(err)
			stderr.Print(sep)
		}
		stderr.Print("misc:")
		stderr.Printf("  rkt's appc version: %s", schema.AppContainerVersion)
		// make a visible break between errors and the listing
		stderr.Print("")
	}
	tabOut.Flush()
	stdout.Print(tabBuffer.String())
	return 0
}
Exemple #11
0
func TestTreeStore(t *testing.T) {
	if !sys.HasChrootCapability() {
		t.Skipf("chroot capability not available. Disabling test.")
	}

	dir, err := ioutil.TempDir("", tstprefix)
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)

	s, err := imagestore.NewStore(dir)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	ts, err := NewStore(dir, s)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

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

	entries := []*aci.ACIEntry{
		// An empty dir
		{
			Header: &tar.Header{
				Name:     "rootfs/a",
				Typeflag: tar.TypeDir,
			},
		},
		{
			Contents: "hello",
			Header: &tar.Header{
				Name: "hello.txt",
				Size: 5,
			},
		},
		{
			Header: &tar.Header{
				Name:     "rootfs/link.txt",
				Linkname: "rootfs/hello.txt",
				Typeflag: tar.TypeSymlink,
			},
		},
		// dangling symlink
		{
			Header: &tar.Header{
				Name:     "rootfs/link2.txt",
				Linkname: "rootfs/missingfile.txt",
				Typeflag: tar.TypeSymlink,
			},
		},
		{
			Header: &tar.Header{
				Name:     "rootfs/fifo",
				Typeflag: tar.TypeFifo,
			},
		},
	}
	aci, err := aci.NewACI(dir, imj, entries)
	if err != nil {
		t.Fatalf("error creating test tar: %v", err)
	}
	defer aci.Close()

	// Rewind the ACI
	if _, err := aci.Seek(0, 0); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Import the new ACI
	key, err := s.WriteACI(aci, imagestore.ACIFetchInfo{Latest: false})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Ask the store to render the treestore
	id, _, err := ts.Render(key, false)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Verify image Hash. Should be the same.
	_, err = ts.Check(id)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Change a file permission
	rootfs := ts.GetRootFS(id)
	err = os.Chmod(filepath.Join(rootfs, "a"), 0600)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Verify image Hash. Should be different
	_, err = ts.Check(id)
	if err == nil {
		t.Errorf("expected non-nil error!")
	}

	// rebuild the tree
	prevID := id
	id, _, err = ts.Render(key, true)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	if id != prevID {
		t.Fatalf("unexpected different IDs. prevID: %s, id: %s", prevID, id)
	}

	// Add a file
	rootfs = ts.GetRootFS(id)
	err = ioutil.WriteFile(filepath.Join(rootfs, "newfile"), []byte("newfile"), 0644)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Verify image Hash. Should be different
	_, err = ts.Check(id)
	if err == nil {
		t.Errorf("expected non-nil error!")
	}
}
Exemple #12
0
func runAppAdd(cmd *cobra.Command, args []string) (exit int) {
	if len(args) < 2 {
		stderr.Print("must provide the pod UUID and an IMAGEID")
		return 254
	}

	err := parseApps(&rktApps, args[1:], cmd.Flags(), true)
	if err != nil {
		stderr.PrintE("error parsing app image arguments", err)
		return 254
	}

	if rktApps.Count() > 1 {
		stderr.Print("must give only one app")
		return 254
	}

	p, err := pkgPod.PodFromUUIDString(getDataDir(), args[0])
	if err != nil {
		stderr.PrintE("problem retrieving pod", err)
		return 254
	}
	defer p.Close()

	if p.State() != pkgPod.Running {
		stderr.Printf("pod %q isn't currently running", p.UUID)
		return 254
	}

	if !p.IsSupervisorReady() {
		stderr.Printf("supervisor for pod %q is not yet ready", p.UUID)
		return 254
	}

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

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

	fn := &image.Finder{
		S:  s,
		Ts: ts,
		Ks: getKeystore(),

		StoreOnly: true,
		NoStore:   false,
	}

	img, err := fn.FindImage(args[1], "")
	if err != nil {
		stderr.PrintE("error finding images", err)
		return 254
	}

	podPID, err := p.ContainerPid1()
	if err != nil {
		stderr.PrintE(fmt.Sprintf("unable to determine the pid for pod %q", p.UUID), err)
		return 254
	}

	ccfg := stage0.CommonConfig{
		DataDir:   getDataDir(),
		Store:     s,
		TreeStore: ts,
		UUID:      p.UUID,
		Debug:     globalFlags.Debug,
	}

	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
	}

	cfg := stage0.AddConfig{
		CommonConfig: &ccfg,
		Image:        *img,
		Apps:         &rktApps,
		RktGid:       rktgid,
		UsesOverlay:  p.UsesOverlay(),
		PodPath:      p.Path(),
		PodPID:       podPID,
	}

	if globalFlags.Debug {
		stage0.InitDebug()
	}

	err = stage0.AddApp(cfg)
	if err != nil {
		stderr.PrintE("error adding app to pod", err)
		return 254
	}

	return 0
}
Exemple #13
0
func runImages(cmd *cobra.Command, args []string) int {
	var errors []error
	tabBuffer := new(bytes.Buffer)
	tabOut := getTabOutWithWriter(tabBuffer)

	if !flagNoLegend {
		var headerFields []string
		for _, f := range flagImagesFields.Options {
			headerFields = append(headerFields, ImagesFieldHeaderMap[f])
		}
		fmt.Fprintf(tabOut, "%s\n", strings.Join(headerFields, "\t"))
	}

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

	remotes, err := s.GetAllRemotes()
	if err != nil {
		stderr.PrintE("unable to get remotes", err)
		return 254
	}

	remoteMap := make(map[string]*imagestore.Remote)
	for _, r := range remotes {
		remoteMap[r.BlobKey] = r
	}

	var sortAciinfoFields []string
	for _, f := range flagImagesSortFields.Options {
		sortAciinfoFields = append(sortAciinfoFields, ImagesFieldAciInfoMap[f])
	}
	aciInfos, err := s.GetAllACIInfos(sortAciinfoFields, bool(flagImagesSortAsc))
	if err != nil {
		stderr.PrintE("unable to get aci infos", err)
		return 254
	}

	for _, aciInfo := range aciInfos {
		imj, err := s.GetImageManifestJSON(aciInfo.BlobKey)
		if err != nil {
			// ignore aciInfo with missing image manifest as it can be deleted in the meantime
			continue
		}
		var im *schema.ImageManifest
		if err = json.Unmarshal(imj, &im); err != nil {
			errors = append(errors, newImgListLoadError(err, imj, aciInfo.BlobKey))
			continue
		}
		version, ok := im.Labels.Get("version")
		var fieldValues []string
		for _, f := range flagImagesFields.Options {
			fieldValue := ""
			switch f {
			case l(id):
				hashKey := aciInfo.BlobKey
				if !flagFullOutput {
					// The short hash form is [HASH_ALGO]-[FIRST 12 CHAR]
					// For example, sha512-123456789012
					pos := strings.Index(hashKey, "-")
					trimLength := pos + 13
					if pos > 0 && trimLength < len(hashKey) {
						hashKey = hashKey[:trimLength]
					}
				}
				fieldValue = hashKey
			case l(name):
				fieldValue = aciInfo.Name
				if ok {
					fieldValue = fmt.Sprintf("%s:%s", fieldValue, version)
				}
			case l(importTime):
				if flagFullOutput {
					fieldValue = aciInfo.ImportTime.Format(defaultTimeLayout)
				} else {
					fieldValue = humanize.Time(aciInfo.ImportTime)
				}
			case l(lastUsed):
				if flagFullOutput {
					fieldValue = aciInfo.LastUsed.Format(defaultTimeLayout)
				} else {
					fieldValue = humanize.Time(aciInfo.LastUsed)
				}
			case l(size):
				totalSize := aciInfo.Size + aciInfo.TreeStoreSize
				if flagFullOutput {
					fieldValue = fmt.Sprintf("%d", totalSize)
				} else {
					fieldValue = humanize.IBytes(uint64(totalSize))
				}
			case l(latest):
				fieldValue = fmt.Sprintf("%t", aciInfo.Latest)
			}
			fieldValues = append(fieldValues, fieldValue)
		}
		fmt.Fprintf(tabOut, "%s\n", strings.Join(fieldValues, "\t"))
	}

	if len(errors) > 0 {
		printErrors(errors, "listing images")
	}

	tabOut.Flush()
	stdout.Print(tabBuffer.String())
	return 0
}
Exemple #14
0
func runRunPrepared(cmd *cobra.Command, args []string) (exit int) {
	if len(args) != 1 {
		cmd.Usage()
		return 1
	}

	p, err := getPodFromUUIDString(args[0])
	if err != nil {
		stderr.PrintE("problem retrieving pod", err)
		return 1
	}
	defer p.Close()

	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
	}

	if !p.isPrepared {
		stderr.Printf("pod %q is not prepared", p.uuid)
		return 1
	}

	if flagInteractive {
		ac, err := p.getAppCount()
		if err != nil {
			stderr.PrintE("cannot get pod's app count", err)
			return 1
		}
		if ac > 1 {
			stderr.Print("interactive option only supports pods with one app")
			return 1
		}
	}

	// Make sure we have a metadata service available before we move to
	// run state so that the user can rerun the command without needing
	// to prepare the image again.
	if flagMDSRegister {
		if err := stage0.CheckMdsAvailability(); err != nil {
			stderr.Error(err)
			return 1
		}
	}

	if err := p.xToRun(); err != nil {
		stderr.PrintE("cannot transition to run", err)
		return 1
	}

	lfd, err := p.Fd()
	if err != nil {
		stderr.PrintE("unable to get lock fd", err)
		return 1
	}

	apps, err := p.getApps()
	if err != nil {
		stderr.PrintE("unable to get app list", 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: &stage0.CommonConfig{
			Store:     s,
			TreeStore: ts,
			UUID:      p.uuid,
			Debug:     globalFlags.Debug,
		},
		Net:         flagNet,
		LockFd:      lfd,
		Interactive: flagInteractive,
		DNS:         flagDNS,
		DNSSearch:   flagDNSSearch,
		DNSOpt:      flagDNSOpt,
		MDSRegister: flagMDSRegister,
		Apps:        apps,
		RktGid:      rktgid,
		Hostname:    flagHostname,
	}
	if globalFlags.Debug {
		stage0.InitDebug()
	}
	stage0.Run(rcfg, p.path(), getDataDir()) // execs, never returns
	return 1
}
Exemple #15
0
func runPrepare(cmd *cobra.Command, args []string) (exit int) {
	var err error
	origStdout := os.Stdout
	privateUsers := user.NewBlankUidRange()
	if flagQuiet {
		if os.Stdout, err = os.Open("/dev/null"); err != nil {
			stderr.PrintE("unable to open /dev/null", err)
			return 254
		}
	}

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

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

	if err = parseApps(&rktApps, args, cmd.Flags(), true); err != nil {
		stderr.PrintE("error parsing app image arguments", err)
		return 254
	}

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

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

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

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

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

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

	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.PrintE("error finding images", err)
		return 254
	}

	p, err := pkgPod.NewPod(getDataDir())
	if err != nil {
		stderr.PrintE("error creating new pod", err)
		return 254
	}

	cfg := stage0.CommonConfig{
		DataDir:     getDataDir(),
		Store:       s,
		TreeStore:   ts,
		Stage1Image: *s1img,
		UUID:        p.UUID,
		Debug:       globalFlags.Debug,
	}

	ovlOk := true
	if err := common.PathSupportsOverlay(getDataDir()); err != nil {
		if oerr, ok := err.(common.ErrOverlayUnsupported); ok {
			stderr.Printf("disabling overlay support: %q", oerr.Error())
			ovlOk = false
		} else {
			stderr.PrintE("error determining overlay support", err)
			return 254
		}
	}

	pcfg := stage0.PrepareConfig{
		CommonConfig:       &cfg,
		UseOverlay:         !flagNoOverlay && ovlOk,
		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 254
	}
	if err = stage0.Prepare(pcfg, p.Path(), p.UUID); err != nil {
		stderr.PrintE("error setting up stage0", err)
		keyLock.Close()
		return 254
	}
	keyLock.Close()

	if err := p.Sync(); err != nil {
		stderr.PrintE("error syncing pod data", err)
		return 254
	}

	if err := p.ToPrepared(); err != nil {
		stderr.PrintE("error transitioning to prepared", err)
		return 254
	}

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

	return 0
}
Exemple #16
0
func TestDownloading(t *testing.T) {
	dir, err := ioutil.TempDir("", "download-image")
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)

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

	entries := []*aci.ACIEntry{
		// An empty file
		{
			Contents: "hello",
			Header: &tar.Header{
				Name: "rootfs/file01.txt",
				Size: 5,
			},
		},
	}

	aci, err := aci.NewACI(dir, imj, entries)
	if err != nil {
		t.Fatalf("error creating test tar: %v", err)
	}

	// Rewind the ACI
	if _, err := aci.Seek(0, 0); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	body, err := ioutil.ReadAll(aci)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	noauthServer := &serverHandler{
		body: body,
		t:    t,
		auth: "none",
	}
	basicServer := &serverHandler{
		body: body,
		t:    t,
		auth: "basic",
	}
	oauthServer := &serverHandler{
		body: body,
		t:    t,
		auth: "bearer",
	}
	denyServer := &serverHandler{
		body: body,
		t:    t,
		auth: "deny",
	}
	noAuthTS := httptest.NewTLSServer(noauthServer)
	defer noAuthTS.Close()
	basicTS := httptest.NewTLSServer(basicServer)
	defer basicTS.Close()
	oauthTS := httptest.NewTLSServer(oauthServer)
	defer oauthTS.Close()
	denyAuthTS := httptest.NewServer(denyServer)
	noAuth := http.Header{}
	// YmFyOmJheg== is base64(bar:baz)
	basicAuth := http.Header{"Authorization": {"Basic YmFyOmJheg=="}}
	bearerAuth := http.Header{"Authorization": {"Bearer sometoken"}}
	urlToName := map[string]string{
		noAuthTS.URL:   "no auth",
		basicTS.URL:    "basic",
		oauthTS.URL:    "oauth",
		denyAuthTS.URL: "deny auth",
	}
	tests := []struct {
		ACIURL   string
		hit      bool
		options  http.Header
		authFail bool
	}{
		{noAuthTS.URL, false, noAuth, false},
		{noAuthTS.URL, true, noAuth, false},
		{noAuthTS.URL, true, bearerAuth, false},
		{noAuthTS.URL, true, basicAuth, false},

		{basicTS.URL, false, noAuth, true},
		{basicTS.URL, false, bearerAuth, true},
		{basicTS.URL, false, basicAuth, false},

		{oauthTS.URL, false, noAuth, true},
		{oauthTS.URL, false, basicAuth, true},
		{oauthTS.URL, false, bearerAuth, false},

		{denyAuthTS.URL, false, basicAuth, false},
		{denyAuthTS.URL, true, bearerAuth, false},
		{denyAuthTS.URL, true, noAuth, false},
	}

	s, err := imagestore.NewStore(dir)
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}

	for _, tt := range tests {
		_, ok, err := s.GetRemote(tt.ACIURL)
		if err != nil {
			t.Fatalf("unexpected err: %v", err)
		}
		if tt.hit == false && ok {
			t.Fatalf("expected miss got a hit")
		}
		if tt.hit == true && !ok {
			t.Fatalf("expected a hit got a miss")
		}
		parsed, err := url.Parse(tt.ACIURL)
		if err != nil {
			panic(fmt.Sprintf("Invalid url from test server: %s", tt.ACIURL))
		}
		headers := map[string]config.Headerer{
			parsed.Host: &testHeaderer{tt.options},
		}
		ft := &image.Fetcher{
			S:             s,
			Headers:       headers,
			InsecureFlags: insecureFlags,
		}
		_, err = ft.FetchImage(tt.ACIURL, "", apps.AppImageURL)
		if err != nil && !tt.authFail {
			t.Fatalf("expected download to succeed, it failed: %v (server: %q, headers: `%v`)", err, urlToName[tt.ACIURL], tt.options)
		}
		if err == nil && tt.authFail {
			t.Fatalf("expected download to fail, it succeeded (server: %q, headers: `%v`)", urlToName[tt.ACIURL], tt.options)
		}
	}

	s.Dump(false)
}
Exemple #17
0
func runImageExtract(cmd *cobra.Command, args []string) (exit int) {
	if len(args) != 2 {
		cmd.Usage()
		return 254
	}
	outputDir := args[1]

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

	key, err := getStoreKeyFromAppOrHash(s, args[0])
	if err != nil {
		stderr.Error(err)
		return 254
	}

	aci, err := s.ReadStream(key)
	if err != nil {
		stderr.PrintE("error reading ACI from the store", err)
		return 254
	}

	// ExtractTar needs an absolute path
	absOutputDir, err := filepath.Abs(outputDir)
	if err != nil {
		stderr.PrintE("error converting output to an absolute path", err)
		return 254
	}

	if _, err := os.Stat(absOutputDir); err == nil {
		if !flagExtractOverwrite {
			stderr.Print("output directory exists (try --overwrite)")
			return 254
		}

		// don't allow the user to delete the root filesystem by mistake
		if absOutputDir == "/" {
			stderr.Print("this would delete your root filesystem. Refusing.")
			return 254
		}

		if err := os.RemoveAll(absOutputDir); err != nil {
			stderr.PrintE("error removing existing output dir", err)
			return 254
		}
	}

	// if the user only asks for the rootfs we extract the image to a temporary
	// directory and then move/copy the rootfs to the output directory, if not
	// we just extract the image to the output directory
	extractDir := absOutputDir
	if flagExtractRootfsOnly {
		rktTmpDir, err := s.TmpDir()
		if err != nil {
			stderr.PrintE("error creating rkt temporary directory", err)
			return 254
		}

		tmpDir, err := ioutil.TempDir(rktTmpDir, "rkt-image-extract-")
		if err != nil {
			stderr.PrintE("error creating temporary directory", err)
			return 254
		}
		defer os.RemoveAll(tmpDir)

		extractDir = tmpDir
	} else {
		if err := os.MkdirAll(absOutputDir, 0755); err != nil {
			stderr.PrintE("error creating output directory", err)
			return 254
		}
	}

	if err := tar.ExtractTar(aci, extractDir, false, user.NewBlankUidRange(), nil); err != nil {
		stderr.PrintE("error extracting ACI", err)
		return 254
	}

	if flagExtractRootfsOnly {
		rootfsDir := filepath.Join(extractDir, "rootfs")
		if err := os.Rename(rootfsDir, absOutputDir); err != nil {
			if e, ok := err.(*os.LinkError); ok && e.Err == syscall.EXDEV {
				// it's on a different device, fall back to copying
				if err := fileutil.CopyTree(rootfsDir, absOutputDir, user.NewBlankUidRange()); err != nil {
					stderr.PrintE("error copying ACI rootfs", err)
					return 254
				}
			} else {
				stderr.PrintE("error moving ACI rootfs", err)
				return 254
			}
		}
	}

	return 0
}
Exemple #18
0
func runAppSandbox(cmd *cobra.Command, args []string) int {
	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
	}

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

	if flagUUIDFileSave != "" {
		if err := pod.WriteUUIDToFile(p.UUID, flagUUIDFileSave); err != nil {
			stderr.PrintE("error saving pod UUID to file", err)
			return 1
		}
	}

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

	p.MountLabel = mountLabel
	cfg := stage0.CommonConfig{
		DataDir:      getDataDir(),
		MountLabel:   mountLabel,
		ProcessLabel: processLabel,
		Store:        s,
		TreeStore:    ts,
		Stage1Image:  *s1img,
		UUID:         p.UUID,
		Debug:        globalFlags.Debug,
		Mutable:      true,
	}

	ovlOk := true
	if err := common.PathSupportsOverlay(getDataDir()); err != nil {
		if oerr, ok := err.(common.ErrOverlayUnsupported); ok {
			stderr.Printf("disabling overlay support: %q", oerr.Error())
			ovlOk = false
		} else {
			stderr.PrintE("error determining overlay support", err)
			return 1
		}
	}

	useOverlay := !flagNoOverlay && ovlOk

	pcfg := stage0.PrepareConfig{
		CommonConfig:       &cfg,
		UseOverlay:         useOverlay,
		PrivateUsers:       user.NewBlankUidRange(),
		SkipTreeStoreCheck: globalFlags.InsecureFlags.SkipOnDiskCheck(),
		Apps:               &rktApps,
		Ports:              []types.ExposedPort(flagAppPorts),
		UserAnnotations:    parseAnnotations(&flagAnnotations),
		UserLabels:         parseLabels(&flagLabels),
	}

	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.ToRun(); 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
	}

	DNSConfMode, DNSConfig, HostsEntries, err := parseDNSFlags(flagHostsEntries, flagDNS, flagDNSSearch, flagDNSOpt, flagDNSDomain)
	if err != nil {
		stderr.PrintE("error with dns flags", err)
		return 1
	}

	rcfg := stage0.RunConfig{
		CommonConfig:         &cfg,
		Net:                  flagNet,
		LockFd:               lfd,
		Interactive:          true,
		DNSConfMode:          DNSConfMode,
		DNSConfig:            DNSConfig,
		MDSRegister:          false,
		LocalConfig:          globalFlags.LocalConfigDir,
		RktGid:               rktgid,
		Hostname:             flagHostname,
		InsecureCapabilities: globalFlags.InsecureFlags.SkipCapabilities(),
		InsecurePaths:        globalFlags.InsecureFlags.SkipPaths(),
		InsecureSeccomp:      globalFlags.InsecureFlags.SkipSeccomp(),
		UseOverlay:           useOverlay,
		HostsEntries:         *HostsEntries,
	}

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

	return 1
}
Exemple #19
0
func runImageRender(cmd *cobra.Command, args []string) (exit int) {
	if len(args) != 2 {
		cmd.Usage()
		return 254
	}
	outputDir := args[1]

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

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

	key, err := getStoreKeyFromAppOrHash(s, args[0])
	if err != nil {
		stderr.Error(err)
		return 254
	}

	id, _, err := ts.Render(key, false)
	if err != nil {
		stderr.PrintE("error rendering ACI", err)
		return 254
	}
	if _, err := ts.Check(id); err != nil {
		stderr.Print("warning: tree cache is in a bad state. Rebuilding...")
		var err error
		if id, _, err = ts.Render(key, true); err != nil {
			stderr.PrintE("error rendering ACI", err)
			return 254
		}
	}

	if _, err := os.Stat(outputDir); err == nil {
		if !flagRenderOverwrite {
			stderr.Print("output directory exists (try --overwrite)")
			return 254
		}

		// don't allow the user to delete the root filesystem by mistake
		if outputDir == "/" {
			stderr.Print("this would delete your root filesystem. Refusing.")
			return 254
		}

		if err := os.RemoveAll(outputDir); err != nil {
			stderr.PrintE("error removing existing output dir", err)
			return 254
		}
	}
	rootfsOutDir := outputDir
	if !flagRenderRootfsOnly {
		if err := os.MkdirAll(outputDir, 0755); err != nil {
			stderr.PrintE("error creating output directory", err)
			return 254
		}
		rootfsOutDir = filepath.Join(rootfsOutDir, "rootfs")

		manifest, err := s.GetImageManifest(key)
		if err != nil {
			stderr.PrintE("error getting manifest", err)
			return 254
		}

		mb, err := json.Marshal(manifest)
		if err != nil {
			stderr.PrintE("error marshalling image manifest", err)
			return 254
		}

		if err := ioutil.WriteFile(filepath.Join(outputDir, "manifest"), mb, 0700); err != nil {
			stderr.PrintE("error writing image manifest", err)
			return 254
		}
	}

	cachedTreePath := ts.GetRootFS(id)
	if err := fileutil.CopyTree(cachedTreePath, rootfsOutDir, user.NewBlankUidRange()); err != nil {
		stderr.PrintE("error copying ACI rootfs", err)
		return 254
	}

	return 0
}
Exemple #20
0
func runEnter(cmd *cobra.Command, args []string) (exit int) {
	if len(args) < 1 {
		cmd.Usage()
		return 254
	}

	p, err := pkgPod.PodFromUUIDString(getDataDir(), args[0])
	if err != nil {
		stderr.PrintE("problem retrieving pod", err)
		return 254
	}
	defer p.Close()

	if p.State() != pkgPod.Running {
		stderr.Printf("pod %q isn't currently running", p.UUID)
		return 254
	}

	podPID, err := p.ContainerPid1()
	if err != nil {
		stderr.PrintE(fmt.Sprintf("unable to determine the pid for pod %q", p.UUID), err)
		return 254
	}

	appName, err := getAppName(p)
	if err != nil {
		stderr.PrintE("unable to determine app name", err)
		return 254
	}

	argv, err := getEnterArgv(p, args)
	if err != nil {
		stderr.PrintE("enter failed", err)
		return 254
	}

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

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

	stage1TreeStoreID, err := p.GetStage1TreeStoreID()
	if err != nil {
		stderr.PrintE("error getting stage1 treeStoreID", err)
		return 254
	}

	stage1RootFS := ts.GetRootFS(stage1TreeStoreID)

	if err = stage0.Enter(p.Path(), podPID, *appName, stage1RootFS, argv); err != nil {
		stderr.PrintE("enter failed", err)
		return 254
	}
	// not reached when stage0.Enter execs /enter
	return 0
}
Exemple #21
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
}
Exemple #22
0
func runFetch(cmd *cobra.Command, args []string) (exit int) {
	if err := parseApps(&rktApps, args, cmd.Flags(), false); err != nil {
		stderr.PrintE("unable to parse arguments", err)
		return 254
	}

	if rktApps.Count() < 1 {
		stderr.Print("must provide at least one image")
		return 254
	}

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

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

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

	ks := getKeystore()
	config, err := getConfig()
	if err != nil {
		stderr.PrintE("cannot get configuration", err)
		return 254
	}
	ft := &image.Fetcher{
		S:                  s,
		Ts:                 ts,
		Ks:                 ks,
		Headers:            config.AuthPerHost,
		DockerAuth:         config.DockerCredentialsPerRegistry,
		InsecureFlags:      globalFlags.InsecureFlags,
		Debug:              globalFlags.Debug,
		TrustKeysFromHTTPS: globalFlags.TrustKeysFromHTTPS,

		StoreOnly: flagStoreOnly,
		NoStore:   flagNoStore,
		WithDeps:  true,
	}

	err = rktApps.Walk(func(app *apps.App) error {
		hash, err := ft.FetchImage(app.Image, app.Asc, app.ImType)
		if err != nil {
			return err
		}
		if !flagFullHash {
			hash = types.ShortHash(hash)
		}
		stdout.Print(hash)
		return nil
	})
	if err != nil {
		stderr.Error(err)
		return 254
	}

	return
}
Exemple #23
0
func TestFetchImage(t *testing.T) {
	dir, err := ioutil.TempDir("", "fetch-image")
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)
	s, err := imagestore.NewStore(dir)
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	defer s.Dump(false)

	ks, ksPath, err := keystore.NewTestKeystore()
	if err != nil {
		t.Errorf("unexpected error %v", err)
	}
	defer os.RemoveAll(ksPath)

	key := keystoretest.KeyMap["example.com/app"]
	if _, err := ks.StoreTrustedKeyPrefix("example.com/app", bytes.NewBufferString(key.ArmoredPublicKey)); err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	a, err := aci.NewBasicACI(dir, "example.com/app")
	defer a.Close()
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}

	// Rewind the ACI
	if _, err := a.Seek(0, 0); err != nil {
		t.Fatalf("unexpected error %v", err)
	}

	asc, err := aci.NewDetachedSignature(key.ArmoredPrivateKey, a)
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}

	// Rewind the ACI.
	if _, err := a.Seek(0, 0); err != nil {
		t.Fatalf("unexpected error %v", err)
	}

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch filepath.Ext(r.URL.Path) {
		case ".aci":
			io.Copy(w, a)
			return
		case ".asc":
			io.Copy(w, asc)
			return
		default:
			t.Fatalf("unknown extension %v", r.URL.Path)
		}
	}))
	defer ts.Close()
	ft := &image.Fetcher{
		S:             s,
		Ks:            ks,
		InsecureFlags: secureFlags,
	}
	_, err = ft.FetchImage(fmt.Sprintf("%s/app.aci", ts.URL), "", apps.AppImageURL)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}
Exemple #24
0
func runRunPrepared(cmd *cobra.Command, args []string) (exit int) {
	if len(args) != 1 {
		cmd.Usage()
		return 254
	}

	p, err := pkgPod.PodFromUUIDString(getDataDir(), args[0])
	if err != nil {
		stderr.PrintE("problem retrieving pod", err)
		return 254
	}
	defer p.Close()

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

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

	if p.State() != pkgPod.Prepared {
		stderr.Printf("pod %q is not prepared", p.UUID)
		return 254
	}

	_, manifest, err := p.PodManifest()
	if err != nil {
		stderr.PrintE("cannot read pod manifest", err)
		return 254
	}

	if flagInteractive {
		if len(manifest.Apps) > 1 {
			stderr.Print("interactive option only supports pods with one app")
			return 254
		}
	}

	// Make sure we have a metadata service available before we move to
	// run state so that the user can rerun the command without needing
	// to prepare the image again.
	if flagMDSRegister {
		if err := stage0.CheckMdsAvailability(); err != nil {
			stderr.Error(err)
			return 254
		}
	}

	if err := p.ToRun(); err != nil {
		stderr.PrintE("cannot transition to run", err)
		return 254
	}

	lfd, err := p.Fd()
	if err != nil {
		stderr.PrintE("unable to get lock fd", err)
		return 254
	}

	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
	}

	ovlOk := true
	if err := common.PathSupportsOverlay(getDataDir()); err != nil {
		if oerr, ok := err.(common.ErrOverlayUnsupported); ok {
			stderr.Printf("disabling overlay support: %q", oerr.Error())
			ovlOk = false
		} else {
			stderr.PrintE("error determining overlay support", err)
			return 254
		}
	}

	ovlPrep := p.UsesOverlay()

	// should not happen, maybe the data directory moved from an overlay-enabled fs to another location
	// between prepare and run-prepared
	if ovlPrep && !ovlOk {
		stderr.Print("unable to run prepared overlay-enabled pod: overlay not supported")
		return 254
	}

	DNSConfMode, DNSConfig, HostsEntries, err := parseDNSFlags(flagHostsEntries, flagDNS, flagDNSSearch, flagDNSOpt, flagDNSDomain)
	if err != nil {
		stderr.PrintE("error with dns flags", err)
		return 254
	}

	rcfg := stage0.RunConfig{
		CommonConfig: &stage0.CommonConfig{
			DataDir:   getDataDir(),
			Store:     s,
			TreeStore: ts,
			UUID:      p.UUID,
			Debug:     globalFlags.Debug,
		},
		Net:                  flagNet,
		LockFd:               lfd,
		Interactive:          flagInteractive,
		DNSConfMode:          DNSConfMode,
		DNSConfig:            DNSConfig,
		HostsEntries:         *HostsEntries,
		MDSRegister:          flagMDSRegister,
		Apps:                 manifest.Apps,
		RktGid:               rktgid,
		Hostname:             flagHostname,
		InsecureCapabilities: globalFlags.InsecureFlags.SkipCapabilities(),
		InsecurePaths:        globalFlags.InsecureFlags.SkipPaths(),
		InsecureSeccomp:      globalFlags.InsecureFlags.SkipSeccomp(),
		UseOverlay:           ovlPrep && ovlOk,
	}
	if globalFlags.Debug {
		stage0.InitDebug()
	}
	stage0.Run(rcfg, p.Path(), getDataDir()) // execs, never returns
	return 254
}
Exemple #25
0
func TestFetchImageCache(t *testing.T) {
	dir, err := ioutil.TempDir("", "fetch-image-cache")
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)
	s, err := imagestore.NewStore(dir)
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	defer s.Dump(false)

	ks, ksPath, err := keystore.NewTestKeystore()
	if err != nil {
		t.Errorf("unexpected error %v", err)
	}
	defer os.RemoveAll(ksPath)

	key := keystoretest.KeyMap["example.com/app"]
	if _, err := ks.StoreTrustedKeyPrefix("example.com/app", bytes.NewBufferString(key.ArmoredPublicKey)); err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	a, err := aci.NewBasicACI(dir, "example.com/app")
	defer a.Close()
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	// Rewind the ACI
	if _, err := a.Seek(0, 0); err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	asc, err := aci.NewDetachedSignature(key.ArmoredPrivateKey, a)
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	// Rewind the ACI
	if _, err := a.Seek(0, 0); err != nil {
		t.Fatalf("unexpected error %v", err)
	}
	aciBody, err := ioutil.ReadAll(a)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	ascBody, err := ioutil.ReadAll(asc)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	nocacheServer := &cachingServerHandler{
		aciBody: aciBody,
		ascBody: ascBody,
		etag:    "",
		maxAge:  0,
		t:       t,
	}
	etagServer := &cachingServerHandler{
		aciBody: aciBody,
		ascBody: ascBody,
		etag:    "123456789",
		maxAge:  0,
		t:       t,
	}
	maxAgeServer := &cachingServerHandler{
		aciBody: aciBody,
		ascBody: ascBody,
		etag:    "",
		maxAge:  10,
		t:       t,
	}
	etagMaxAgeServer := &cachingServerHandler{
		aciBody: aciBody,
		ascBody: ascBody,
		etag:    "123456789",
		maxAge:  10,
		t:       t,
	}

	nocacheTS := httptest.NewServer(nocacheServer)
	defer nocacheTS.Close()
	etagTS := httptest.NewServer(etagServer)
	defer etagTS.Close()
	maxAgeTS := httptest.NewServer(maxAgeServer)
	defer maxAgeTS.Close()
	etagMaxAgeTS := httptest.NewServer(etagMaxAgeServer)
	defer etagMaxAgeTS.Close()

	type testData struct {
		URL             string
		etag            string
		cacheMaxAge     int
		shouldUseCached bool
	}
	tests := []testData{
		{nocacheTS.URL, "", 0, false},
		{etagTS.URL, "123456789", 0, true},
		{maxAgeTS.URL, "", 10, true},
		{etagMaxAgeTS.URL, "123456789", 10, true},
	}
	testFn := func(tt testData, useRedirect bool) {
		aciURL := fmt.Sprintf("%s/app.aci", tt.URL)
		if useRedirect {
			redirectingTS := httptest.NewServer(&redirectingServerHandler{destServer: tt.URL})
			defer redirectingTS.Close()
			aciURL = fmt.Sprintf("%s/app.aci", redirectingTS.URL)
		}
		ft := &image.Fetcher{
			S:             s,
			Ks:            ks,
			InsecureFlags: secureFlags,
			// Skip local store
			NoStore: true,
		}
		_, err = ft.FetchImage(aciURL, "", apps.AppImageURL)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		rem, _, err := s.GetRemote(aciURL)
		if err != nil {
			t.Fatalf("Error getting remote info: %v\n", err)
		}
		if rem.ETag != tt.etag {
			t.Errorf("expected remote to have a ETag header argument")
		}
		if rem.CacheMaxAge != tt.cacheMaxAge {
			t.Errorf("expected max-age header argument to be %q", tt.cacheMaxAge)
		}

		downloadTime := rem.DownloadTime
		_, err = ft.FetchImage(aciURL, "", apps.AppImageURL)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		rem, _, err = s.GetRemote(aciURL)
		if err != nil {
			t.Fatalf("Error getting remote info: %v\n", err)
		}
		if rem.ETag != tt.etag {
			t.Errorf("expected remote to have a ETag header argument")
		}
		if rem.CacheMaxAge != tt.cacheMaxAge {
			t.Errorf("expected max-age header argument to be %q", tt.cacheMaxAge)
		}
		if tt.shouldUseCached {
			if downloadTime != rem.DownloadTime {
				t.Errorf("expected current download time to be the same as the previous one (no download) but they differ")
			}
		} else {
			if downloadTime == rem.DownloadTime {
				t.Errorf("expected current download time to be different from the previous one (new image download) but they are the same")
			}
		}

		if err := s.RemoveACI(rem.BlobKey); err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
	}

	// repeat the tests with and without a redirecting server
	for i := 0; i <= 1; i++ {
		useRedirect := false
		if i == 1 {
			useRedirect = true
		}
		for _, tt := range tests {
			testFn(tt, useRedirect)
		}
	}
}
Exemple #26
0
func runImages(cmd *cobra.Command, args []string) int {
	var errors []error
	tabBuffer := new(bytes.Buffer)
	tabOut := getTabOutWithWriter(tabBuffer)

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

	remotes, err := s.GetAllRemotes()
	if err != nil {
		stderr.PrintE("unable to get remotes", err)
		return 254
	}

	remoteMap := make(map[string]*imagestore.Remote)
	for _, r := range remotes {
		remoteMap[r.BlobKey] = r
	}

	var sortAciinfoFields []string
	for _, f := range flagImagesSortFields.Options {
		sortAciinfoFields = append(sortAciinfoFields, ImagesFieldAciInfoMap[f])
	}
	aciInfos, err := s.GetAllACIInfos(sortAciinfoFields, bool(flagImagesSortAsc))
	if err != nil {
		stderr.PrintE("unable to get aci infos", err)
		return 254
	}

	var imagesToPrint []printableImage

	for _, aciInfo := range aciInfos {
		imj, err := s.GetImageManifestJSON(aciInfo.BlobKey)
		if err != nil {
			// ignore aciInfo with missing image manifest as it can be deleted in the meantime
			continue
		}
		var im *schema.ImageManifest
		if err = json.Unmarshal(imj, &im); err != nil {
			errors = append(errors, newImgListLoadError(err, imj, aciInfo.BlobKey))
			continue
		}
		version, ok := im.Labels.Get("version")

		imageID := aciInfo.BlobKey
		imageName := aciInfo.Name
		if ok {
			imageName = fmt.Sprintf("%s:%s", imageName, version)
		}

		totalSize := aciInfo.Size + aciInfo.TreeStoreSize

		if !flagFullOutput && flagImageFormat == outputFormatTabbed {
			imageID = trimImageID(imageID)
		}

		imagesToPrint = append(imagesToPrint, printableImage{
			ImageListEntry: rktlib.ImageListEntry{
				ID:           imageID,
				Name:         imageName,
				ImportTime:   aciInfo.ImportTime.UnixNano(),
				LastUsedTime: aciInfo.LastUsed.UnixNano(),
				Size:         totalSize,
			},
			format: flagImageFormat,
			full:   flagFullOutput,
		})
	}

	switch flagImageFormat {
	case outputFormatTabbed:
		if !flagNoLegend {
			var headerFields []string
			for _, f := range flagImagesFields.Options {
				headerFields = append(headerFields, ImagesFieldHeaderMap[f])
			}
			fmt.Fprintf(tabOut, "%s\n", strings.Join(headerFields, "\t"))
		}
		for _, image := range imagesToPrint {
			fmt.Fprintf(tabOut, "%s\n", image.printableString(flagImagesFields))
		}
	case outputFormatJSON:
		result, err := json.Marshal(imagesToPrint)
		if err != nil {
			errors = append(errors, err)
		} else {
			fmt.Fprintf(tabOut, "%s\n", result)
		}
	case outputFormatPrettyJSON:
		result, err := json.MarshalIndent(imagesToPrint, "", "\t")
		if err != nil {
			errors = append(errors, err)
		} else {
			fmt.Fprintf(tabOut, "%s\n", result)
		}
	}

	if len(errors) > 0 {
		printErrors(errors, "listing images")
	}

	tabOut.Flush()
	stdout.Print(tabBuffer.String())
	return 0
}