func (a *ACBuild) writeEmptyManifest() error { acid, err := types.NewACIdentifier("acbuild-unnamed") if err != nil { return err } archlabel, err := types.NewACIdentifier("arch") if err != nil { return err } oslabel, err := types.NewACIdentifier("os") if err != nil { return err } manifest := &schema.ImageManifest{ ACKind: schema.ImageManifestKind, ACVersion: schema.AppContainerVersion, Name: *acid, Labels: types.Labels{ types.Label{ *archlabel, runtime.GOARCH, }, types.Label{ *oslabel, runtime.GOOS, }, }, } 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 }
// NewAppFromString takes a command line app parameter and returns a map of labels. // // Example app parameters: // example.com/reduce-worker:1.0.0 // example.com/reduce-worker,channel=alpha,label=value // example.com/reduce-worker:1.0.0,label=value // // As can be seen in above examples - colon, comma and equal sign have // special meaning. If any of them has to be a part of a label's value // then consider writing your own string to App parser. func NewAppFromString(app string) (*App, error) { var ( name string labels map[types.ACIdentifier]string ) preparedApp, err := prepareAppString(app) if err != nil { return nil, err } v, err := url.ParseQuery(preparedApp) if err != nil { return nil, err } labels = make(map[types.ACIdentifier]string, 0) for key, val := range v { if len(val) > 1 { return nil, fmt.Errorf("label %s with multiple values %q", key, val) } if key == "name" { name = val[0] continue } labelName, err := types.NewACIdentifier(key) if err != nil { return nil, err } labels[*labelName] = val[0] } a, err := NewApp(name, labels) if err != nil { return nil, err } return a, nil }
// AddLabel will add a label with the given name and value to the untarred ACI // stored at a.CurrentACIPath. If the label already exists its value will be updated to // the new value. func (a *ACBuild) AddLabel(name, value string) (err error) { if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() acid, err := types.NewACIdentifier(name) if err != nil { return err } fn := func(s *schema.ImageManifest) { removeLabelFromMan(*acid)(s) s.Labels = append(s.Labels, types.Label{ Name: *acid, Value: value, }) } return util.ModifyManifest(fn, a.CurrentACIPath) }
// AddDependency will add a dependency with the given name, id, labels, and size // to the untarred ACI stored at acipath. If the dependency already exists its // fields will be updated to the new values. func AddDependency(acipath, imageName, imageId string, labels types.Labels, size uint) error { acid, err := types.NewACIdentifier(imageName) if err != nil { return err } var hash *types.Hash if imageId != "" { var err error hash, err = types.NewHash(imageId) if err != nil { return err } } fn := func(s *schema.ImageManifest) { removeDep(*acid)(s) s.Dependencies = append(s.Dependencies, types.Dependency{ ImageName: *acid, ImageID: hash, Labels: labels, Size: size, }) } return util.ModifyManifest(fn, acipath) }
// NewAppFromString takes a command line app parameter and returns a map of labels. // // Example app parameters: // example.com/reduce-worker:1.0.0 // example.com/reduce-worker,channel=alpha,label=value func NewAppFromString(app string) (*App, error) { var ( name string labels map[types.ACIdentifier]string ) app = strings.Replace(app, ":", ",version=", -1) app = "name=" + app v, err := url.ParseQuery(strings.Replace(app, ",", "&", -1)) if err != nil { return nil, err } labels = make(map[types.ACIdentifier]string, 0) for key, val := range v { if len(val) > 1 { return nil, fmt.Errorf("label %s with multiple values %q", key, val) } if key == "name" { name = val[0] continue } labelName, err := types.NewACIdentifier(key) if err != nil { return nil, err } labels[*labelName] = val[0] } a, err := NewApp(name, labels) if err != nil { return nil, err } return a, nil }
func (a *ACBuild) AddIsolator(name string, value []byte) (err error) { if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() acid, err := types.NewACIdentifier(name) if err != nil { return err } rawMsg := json.RawMessage(value) fn := func(s *schema.ImageManifest) error { if s.App == nil { s.App = newManifestApp() } removeIsolatorFromMan(*acid)(s) s.App.Isolators = append(s.App.Isolators, types.Isolator{ Name: *acid, ValueRaw: &rawMsg, }) return nil } return util.ModifyManifest(fn, a.CurrentACIPath) }
// RemoveDependency will remove the dependency with the given name from the // untarred ACI stored at acipath func RemoveDependency(acipath, imageName string) error { acid, err := types.NewACIdentifier(imageName) if err != nil { return err } return util.ModifyManifest(removeDep(*acid), acipath) }
// RemoveAnnotation will remove the annotation with the given name from the // untarred ACI stored at acipath func RemoveAnnotation(acipath, name string) error { acid, err := types.NewACIdentifier(name) if err != nil { return err } return util.ModifyManifest(removeAnnotation(*acid), acipath) }
// AddAnnotation will add an annotation with the given name and value to the // untarred ACI stored at acipath. If the annotation already exists its value // will be updated to the new value. func AddAnnotation(acipath, name, value string) error { acid, err := types.NewACIdentifier(name) if err != nil { return err } fn := func(s *schema.ImageManifest) { s.Annotations.Set(*acid, value) } return util.ModifyManifest(fn, acipath) }
func NewApp(name string, labels map[types.ACIdentifier]string) (*App, error) { if labels == nil { labels = make(map[types.ACIdentifier]string, 0) } acn, err := types.NewACIdentifier(name) if err != nil { return nil, err } return &App{ Name: *acn, Labels: labels, }, nil }
// SetName sets the name for the untarred ACI stored at acipath func SetName(acipath, name string) error { if name == "" { return fmt.Errorf("name cannot be empty") } acid, err := types.NewACIdentifier(name) if err != nil { return err } fn := func(s *schema.ImageManifest) { s.Name = *acid } return util.ModifyManifest(fn, acipath) }
func (ls *labellist) Set(input string) error { parts := strings.SplitN(input, "=", 2) if len(parts) != 2 { return fmt.Errorf("no '=' character in %q", input) } acid, err := types.NewACIdentifier(parts[0]) if err != nil { return err } *ls = append(*ls, types.Label{ Name: *acid, Value: parts[1], }) return nil }
// AddLabel will add a label with the given name and value to the untarred ACI // stored at acipath. If the label already exists its value will be updated to // the new value. func AddLabel(acipath, name, value string) error { acid, err := types.NewACIdentifier(name) if err != nil { return err } fn := func(s *schema.ImageManifest) { removeLabelFromMan(*acid)(s) s.Labels = append(s.Labels, types.Label{ Name: *acid, Value: value, }) } return util.ModifyManifest(fn, acipath) }
// RemoveAnnotation will remove the annotation with the given name from the // untarred ACI stored at a.CurrentACIPath func (a *ACBuild) RemoveAnnotation(name string) (err error) { if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() acid, err := types.NewACIdentifier(name) if err != nil { return err } return util.ModifyManifest(removeAnnotation(*acid), a.CurrentACIPath) }
// AddAnnotation will add an annotation with the given name and value to the // untarred ACI stored at a.CurrentACIPath. If the annotation already exists // its value will be updated to the new value. func (a *ACBuild) AddAnnotation(name, value string) (err error) { if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() acid, err := types.NewACIdentifier(name) if err != nil { return err } fn := func(s *schema.ImageManifest) { s.Annotations.Set(*acid, value) } return util.ModifyManifest(fn, a.CurrentACIPath) }
// SetName sets the name for the untarred ACI stored at a.CurrentACIPath func (a *ACBuild) SetName(name string) (err error) { if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() if name == "" { return fmt.Errorf("name cannot be empty") } acid, err := types.NewACIdentifier(name) if err != nil { return err } fn := func(s *schema.ImageManifest) { s.Name = *acid } return util.ModifyManifest(fn, a.CurrentACIPath) }
// AddDependency will add a dependency with the given name, id, labels, and size // to the untarred ACI stored at a.CurrentACIPath. If the dependency already // exists its fields will be updated to the new values. func (a *ACBuild) AddDependency(imageName, imageId string, labels types.Labels, size uint) (err error) { if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() acid, err := types.NewACIdentifier(imageName) if err != nil { return err } var hash *types.Hash if imageId != "" { var err error hash, err = types.NewHash(imageId) if err != nil { return err } } fn := func(s *schema.ImageManifest) error { removeDep(*acid)(s) s.Dependencies = append(s.Dependencies, types.Dependency{ ImageName: *acid, ImageID: hash, Labels: labels, Size: size, }) return nil } return util.ModifyManifest(fn, a.CurrentACIPath) }
// 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) { _, err = os.Stat(a.ContextPath) switch { case os.IsNotExist(err): break case err != nil: return err default: 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 } }() defer func() { // If there was an error while beginning, we don't want to produce an // unexpected build context if err != nil { os.RemoveAll(a.ContextPath) } }() if start != "" { err = os.MkdirAll(a.CurrentACIPath, 0755) if err != nil { return err } if start[0] == '.' || start[0] == '/' { return a.beginFromLocalImage(start) } else { return a.beginFromRemoteImage(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 } archlabel, err := types.NewACIdentifier("arch") if err != nil { return err } oslabel, err := types.NewACIdentifier("os") if err != nil { return err } manifest := &schema.ImageManifest{ ACKind: schema.ImageManifestKind, ACVersion: schema.AppContainerVersion, Name: *acid, Labels: types.Labels{ types.Label{ *archlabel, runtime.GOARCH, }, types.Label{ *oslabel, runtime.GOOS, }, }, } 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 }
// 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 }
// 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 }