Beispiel #1
0
func addACBuildAnnotation(cmd *cobra.Command, args []string) error {
	const annoNamePattern = "appc.io/acbuild/command-%d"

	acb := newACBuild()

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

	var acbuildCount int
	for _, ann := range man.Annotations {
		var tmpCount int
		n, _ := fmt.Sscanf(string(ann.Name), annoNamePattern, &tmpCount)
		if n == 1 && tmpCount > acbuildCount {
			acbuildCount = tmpCount
		}
	}

	command := cmd.Name()
	tmpcmd := cmd.Parent()
	for {
		command = tmpcmd.Name() + " " + command
		if tmpcmd == cmdAcbuild {
			break
		}
		tmpcmd = tmpcmd.Parent()
	}

	for _, a := range args {
		command += fmt.Sprintf(" %q", a)
	}

	return acb.AddAnnotation(fmt.Sprintf(annoNamePattern, acbuildCount+1), command)
}
Beispiel #2
0
func genDeplist(acipath string, reg registry.Registry) ([]string, error) {
	man, err := util.GetManifest(acipath)
	if err != nil {
		return nil, err
	}
	key, err := reg.GetACI(man.Name, man.Labels)
	if err != nil {
		fmt.Printf("Name: %s", man.Name)
		return nil, err
	}

	var deps []string
	for _, dep := range man.Dependencies {
		depkey, err := reg.GetACI(dep.ImageName, dep.Labels)
		if err != nil {
			return nil, err
		}

		subdeps, err := genDeplist(path.Join(reg.DepStoreExpandedPath, depkey), reg)
		if err != nil {
			return nil, err
		}
		deps = append(deps, subdeps...)
	}

	deps = append(deps, key)
	return deps, nil
}
Beispiel #3
0
// Returns the key for the ACI with the given name and labels
func (r Registry) GetACI(name types.ACIdentifier, labels types.Labels) (string, error) {
	files, err := ioutil.ReadDir(r.DepStoreExpandedPath)
	if err != nil {
		return "", err
	}
nextkey:
	for _, file := range files {
		man, err := util.GetManifest(path.Join(r.DepStoreExpandedPath, file.Name()))
		if err != nil {
			return "", err
		}
		if man.Name != name {
			continue
		}
		for _, l := range labels {
			val, ok := man.Labels.Get(l.Name.String())
			if !ok {
				continue
			}
			if val != l.Value {
				continue nextkey
			}
		}
		return file.Name(), nil
	}
	return "", ErrNotFound
}
Beispiel #4
0
// CatManifest will print to stdout the manifest from the expanded ACI stored
// at a.CurrentACIPath, optionally inserting whitespace to make it more human
// readable.
func (a *ACBuild) CatManifest(prettyPrint bool) (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
	}

	return util.PrintManifest(man, prettyPrint)
}
Beispiel #5
0
func (a *ACBuild) renderACI(insecure, debug bool) ([]string, error) {
	reg := registry.Registry{
		DepStoreTarPath:      a.DepStoreTarPath,
		DepStoreExpandedPath: a.DepStoreExpandedPath,
		Insecure:             insecure,
		Debug:                debug,
	}

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

	if len(man.Dependencies) == 0 {
		return nil, nil
	}

	var deplist []string
	for _, dep := range man.Dependencies {
		err := reg.FetchAndRender(dep.ImageName, dep.Labels, dep.Size)
		if err != nil {
			return nil, err
		}

		depkey, err := reg.GetACI(dep.ImageName, dep.Labels)
		if err != nil {
			return nil, err
		}

		subdeplist, err := genDeplist(path.Join(a.DepStoreExpandedPath, depkey), reg)
		if err != nil {
			return nil, err
		}
		deplist = append(deplist, subdeplist...)
	}

	return deplist, nil
}
Beispiel #6
0
// Run will execute the given command in the ACI being built. a.CurrentACIPath
// is where the untarred ACI is stored, a.DepStoreTarPath is the directory to
// download dependencies into, a.DepStoreExpandedPath is where the dependencies
// are expanded into, and a.OverlayWorkPath is the work directory used by
// overlayfs.
//
// Arguments:
//
// - cmd:        The command to run and its arguments.
//
// - workingDir: If specified, the current directory inside the container is
// changed to its value before running the given command.
//
// - runEngine:  The engine used to perform the execution of the command.
func (a *ACBuild) Run(cmd []string, workingDir string, insecure bool, runEngine engine.Engine) (err error) {
	if err = a.lock(); err != nil {
		return err
	}
	defer func() {
		if err1 := a.unlock(); err == nil {
			err = err1
		}
	}()

	if os.Geteuid() != 0 {
		return fmt.Errorf("the run subcommand must be run as root")
	}

	if len(cmd) == 0 {
		return fmt.Errorf("command to run not set")
	}

	err = util.MaybeUnmount(a.OverlayTargetPath)
	if err != nil {
		return err
	}

	err = util.RmAndMkdir(a.OverlayTargetPath)
	if err != nil {
		return err
	}
	defer os.RemoveAll(a.OverlayTargetPath)
	err = util.RmAndMkdir(a.OverlayWorkPath)
	if err != nil {
		return err
	}
	defer os.RemoveAll(a.OverlayWorkPath)
	err = os.MkdirAll(a.DepStoreExpandedPath, 0755)
	if err != nil {
		return err
	}
	err = os.MkdirAll(a.DepStoreTarPath, 0755)
	if err != nil {
		return err
	}

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

	if len(man.Dependencies) != 0 {
		if !supportsOverlay() {
			err := exec.Command("modprobe", "overlay").Run()
			if err != nil {
				if _, ok := err.(*exec.ExitError); ok {
					return fmt.Errorf("overlayfs is not supported on your system")
				}
				return err
			}
			if !supportsOverlay() {
				return fmt.Errorf(
					"overlayfs support required for using run with dependencies")
			}
		}
	}

	deps, err := a.renderACI(insecure, a.Debug)
	if err != nil {
		return err
	}

	var chrootDir string
	if deps == nil {
		chrootDir = path.Join(a.CurrentACIPath, aci.RootfsDir)
	} else {
		for i, dep := range deps {
			deps[i] = path.Join(a.DepStoreExpandedPath, dep, aci.RootfsDir)
		}
		options := "lowerdir=" + strings.Join(deps, ":") +
			",upperdir=" + path.Join(a.CurrentACIPath, aci.RootfsDir) +
			",workdir=" + a.OverlayWorkPath
		err := syscall.Mount("overlay", a.OverlayTargetPath, "overlay", 0, options)
		if err != nil {
			return err
		}

		defer func() {
			err1 := syscall.Unmount(a.OverlayTargetPath, 0)
			if err == nil {
				err = err1
			}
		}()

		chrootDir = a.OverlayTargetPath
	}

	var env types.Environment
	if man.App != nil {
		env = man.App.Environment
	} else {
		env = types.Environment{}
	}

	err = a.mirrorLocalZoneInfo()
	if err != nil {
		return err
	}

	err = runEngine.Run(cmd[0], cmd[1:], env, chrootDir, workingDir)
	if err != nil {
		return err
	}

	return nil
}
Beispiel #7
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
}
Beispiel #8
0
// Returns the manifest for the ACI with the given key
func (r Registry) GetImageManifest(key string) (*schema.ImageManifest, error) {
	return util.GetManifest(path.Join(r.DepStoreExpandedPath, key))
}