Exemple #1
0
func (a *ACBuild) lock() error {
	ex, err := util.Exists(a.ContextPath)
	if err != nil {
		return err
	}
	if !ex {
		return fmt.Errorf("build not in progress in this working dir - try \"acbuild begin\"")
	}

	if a.lockFile != nil {
		return fmt.Errorf("lock already held by this ACBuild")
	}

	a.lockFile, err = os.OpenFile(a.LockPath, os.O_CREATE|os.O_RDWR, 0644)
	if err != nil {
		return err
	}

	err = syscall.Flock(int(a.lockFile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
	if err != nil {
		if err == syscall.EWOULDBLOCK {
			return fmt.Errorf("lock already held - is another acbuild running in this working dir?")
		}
		return err
	}

	return nil
}
Exemple #2
0
func runBegin(cmd *cobra.Command, args []string) (exit int) {
	if len(args) > 1 {
		stderr("begin: incorrect number of arguments")
		return 1
	}

	ex, err := util.Exists(path.Join(contextpath, workprefix))
	if err != nil {
		stderr("begin: %v", err)
		return 1
	}
	if ex {
		stderr("begin: build already in progress in this working dir")
		return 1
	}

	err = os.MkdirAll(path.Join(contextpath, workprefix), 0755)
	if err != nil {
		stderr("begin: %v", err)
		return 1
	}

	lockfile, err := getLock()
	if err != nil {
		stderr("begin: %v", err)
		return 1
	}
	defer func() {
		if err := releaseLock(lockfile); err != nil {
			stderr("begin: %v", err)
			exit = 1
		}
	}()

	if debug {
		if len(args) == 0 {
			stderr("Beginning build with an empty ACI")
		} else {
			stderr("Beginning build with %s", args[0])
		}
	}

	if len(args) == 0 {
		err = lib.Begin(tmpacipath(), "")
	} else {
		err = lib.Begin(tmpacipath(), args[0])
	}

	if err != nil {
		stderr("begin: %v", err)
		return 1
	}

	return 0
}
Exemple #3
0
func findCmdInPath(pathlist []string, cmd, prefix string) (string, error) {
	if len(cmd) != 0 && cmd[0] == '/' {
		return cmd, nil
	}

	for _, p := range pathlist {
		ex, err := util.Exists(path.Join(prefix, p, cmd))
		if err != nil {
			return "", err
		}
		if ex {
			return path.Join(p, cmd), nil
		}
	}
	return "", fmt.Errorf("%s not found in any of: %v", cmd, pathlist)
}
Exemple #4
0
// Abort will abort the current build, given the path that the build resources
// are stored at. An error will be returned if no build is in progress.
func Abort(contextpath string) error {
	ok, err := util.Exists(contextpath)
	if err != nil {
		return err
	}
	if !ok {
		return fmt.Errorf("build not in progress")
	}

	err = os.RemoveAll(contextpath)
	if err != nil {
		return err
	}

	return nil
}
Exemple #5
0
// FetchAndRender will fetch the given image and all of its dependencies if
// they have not been fetched yet, and will then render them on to the
// filesystem if they have not been rendered yet.
func (r Registry) FetchAndRender(imagename types.ACIdentifier, labels types.Labels, size uint) error {
	_, err := r.GetACI(imagename, labels)
	if err == ErrNotFound {
		err := r.fetchACIWithSize(imagename, labels, size)
		if err != nil {
			return err
		}
	}

	filesToRender, err := acirenderer.GetRenderedACI(imagename,
		labels, r)
	if err != nil {
		return err
	}

	for _, fs := range filesToRender {
		ex, err := util.Exists(path.Join(r.Scratchpath, fs.Key, "rendered"))
		if err != nil {
			return err
		}
		if ex {
			//This ACI has already been rendered
			continue
		}

		err = util.UnTar(path.Join(r.Depstore, fs.Key),
			path.Join(r.Scratchpath, fs.Key), fs.FileMap)
		if err != nil {
			return err
		}

		rfile, err := os.Create(path.Join(r.Scratchpath, fs.Key, "rendered"))
		if err != nil {
			return err
		}
		rfile.Close()
	}
	return nil
}
Exemple #6
0
// FetchAndRender will fetch the given image and all of its dependencies if
// they have not been fetched yet, and will then render them on to the
// filesystem if they have not been rendered yet.
func (r Registry) FetchAndRender(imagename types.ACIdentifier, labels types.Labels, size uint) error {
	err := r.Fetch(imagename, labels, size, true)
	if err != nil {
		return err
	}

	filesToRender, err := acirenderer.GetRenderedACI(imagename,
		labels, r)
	if err != nil {
		return err
	}

	for _, fs := range filesToRender {
		ex, err := util.Exists(
			path.Join(r.DepStoreExpandedPath, fs.Key, "rendered"))
		if err != nil {
			return err
		}
		if ex {
			//This ACI has already been rendered
			continue
		}

		err = util.ExtractImage(path.Join(r.DepStoreTarPath, fs.Key),
			path.Join(r.DepStoreExpandedPath, fs.Key), fs.FileMap)
		if err != nil {
			return err
		}

		rfile, err := os.Create(
			path.Join(r.DepStoreExpandedPath, fs.Key, "rendered"))
		if err != nil {
			return err
		}
		rfile.Close()
	}
	return nil
}
Exemple #7
0
func getLock() (*os.File, error) {
	ex, err := util.Exists(path.Join(contextpath, workprefix))
	if err != nil {
		return nil, err
	}
	if !ex {
		return nil, fmt.Errorf("build not in progress in this working dir - try \"acbuild begin\"")
	}

	lockfile, err := os.OpenFile(lockpath(), os.O_CREATE|os.O_RDWR, 0644)
	if err != nil {
		return nil, err
	}

	err = syscall.Flock(int(lockfile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
	if err != nil {
		if err == syscall.EWOULDBLOCK {
			return nil, fmt.Errorf("lock already held - is another acbuild running in this working dir?")
		}
		return nil, err
	}

	return lockfile, nil
}
Exemple #8
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

	ex, err := util.Exists(output)
	if err != nil {
		return err
	}
	if ex {
		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()

	// 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 {
		return err
	}

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

	return nil
}
Exemple #9
0
// Begin will start a new build, storing the untarred ACI the build operates on
// at a.CurrentACIPath. If start is the empty string, the build will begin with
// an empty ACI, otherwise the ACI stored at start will be used at the starting
// point.
func (a *ACBuild) Begin(start string, insecure bool) (err error) {
	ex, err := util.Exists(a.ContextPath)
	if err != nil {
		return err
	}
	if ex {
		return fmt.Errorf("build already in progress in this working dir")
	}

	err = os.MkdirAll(a.ContextPath, 0755)
	if err != nil {
		return err
	}

	if err = a.lock(); err != nil {
		return err
	}
	defer func() {
		if err1 := a.unlock(); err == nil {
			err = err1
		}
	}()

	if start != "" {
		err = os.MkdirAll(a.CurrentACIPath, 0755)
		if err != nil {
			return err
		}
		return a.beginFromImage(start, insecure)
	}

	err = os.MkdirAll(path.Join(a.CurrentACIPath, aci.RootfsDir), 0755)
	if err != nil {
		return err
	}

	acid, err := types.NewACIdentifier("acbuild-unnamed")
	if err != nil {
		return err
	}

	manifest := &schema.ImageManifest{
		ACKind:    schema.ImageManifestKind,
		ACVersion: schema.AppContainerVersion,
		Name:      *acid,
		App: &types.App{
			Exec:  nil,
			User:  "******",
			Group: "0",
		},
	}

	manblob, err := manifest.MarshalJSON()
	if err != nil {
		return err
	}

	manfile, err := os.Create(path.Join(a.CurrentACIPath, aci.ManifestFile))
	if err != nil {
		return err
	}

	_, err = manfile.Write(manblob)
	if err != nil {
		return err
	}

	err = manfile.Close()
	if err != nil {
		return err
	}

	return nil
}
Exemple #10
0
// Begin will start a new build, storing the untarred ACI the build operates on
// at tmpaci. If start is the empty string, the build will begin with an empty
// ACI, otherwise the ACI stored at start will be used at the starting point.
func Begin(tmpaci, start string) error {
	ex, err := util.Exists(tmpaci)
	if err != nil {
		return err
	}
	if ex {
		return fmt.Errorf("build already in progress? path exists: %s", tmpaci)
	}

	err = os.MkdirAll(path.Join(tmpaci, aci.RootfsDir), 0755)
	if err != nil {
		return err
	}

	if start != "" {
		ex, err := util.Exists(start)
		if err != nil {
			return err
		}
		if !ex {
			return fmt.Errorf("start aci doesn't exist: %s", start)
		}

		err = util.UnTar(start, tmpaci, nil)
		if err != nil {
			return err
		}

		return nil
	}

	acid, err := types.NewACIdentifier("acbuild-unnamed")
	if err != nil {
		return err
	}

	manifest := &schema.ImageManifest{
		ACKind:    schema.ImageManifestKind,
		ACVersion: schema.AppContainerVersion,
		Name:      *acid,
		App: &types.App{
			Exec:  placeholderexec,
			User:  "******",
			Group: "0",
		},
	}

	manblob, err := manifest.MarshalJSON()
	if err != nil {
		return err
	}

	manfile, err := os.Create(path.Join(tmpaci, aci.ManifestFile))
	if err != nil {
		return err
	}

	_, err = manfile.Write(manblob)
	if err != nil {
		return err
	}

	err = manfile.Close()
	if err != nil {
		return err
	}

	return nil
}