func NewBuilder(podRoot string, podUUID *types.UUID) (*Builder, error) { pod, err := stage1commontypes.LoadPod(podRoot, podUUID) if err != nil { logs.WithError(err).Fatal("Failed to load pod") } if len(pod.Manifest.Apps) != 1 { logs.Fatal("dgr builder support only 1 application") } fields := data.WithField("aci", manifestApp(pod).Name) aciPath, ok := manifestApp(pod).App.Environment.Get(common.EnvAciPath) if !ok || aciPath == "" { return nil, errs.WithF(fields, "Builder image require "+common.EnvAciPath+" environment variable") } aciTarget, ok := manifestApp(pod).App.Environment.Get(common.EnvAciTarget) if !ok || aciPath == "" { return nil, errs.WithF(fields, "Builder image require "+common.EnvAciTarget+" environment variable") } return &Builder{ fields: fields, aciHomePath: aciPath, aciTargetPath: aciTarget, pod: pod, stage1Rootfs: rktcommon.Stage1RootfsPath(pod.Root), stage2Rootfs: filepath.Join(rktcommon.AppPath(pod.Root, manifestApp(pod).Name), "rootfs"), }, nil }
func (hap *HaProxyClient) SocketUpdate() error { if hap.socketPath == "" { return errs.WithF(hap.fields, "No socket file specified. Cannot update") } logs.WithF(hap.fields).Debug("Updating haproxy by socket") if err := hap.writeConfig(); err != nil { // just to stay in sync logs.WithEF(err, hap.fields).Warn("Failed to write configuration file") } conn, err := net.Dial("unix", hap.socketPath) if err != nil { return errs.WithEF(err, hap.fields.WithField("socket", hap.socketPath), "Failed to connect to haproxy socket") } defer conn.Close() i := 0 b := bytes.Buffer{} for name, servers := range hap.Backend { for _, server := range servers { res := hap.weightRegex.FindStringSubmatch(server) if len(res) == 3 { i++ b.WriteString("set weight " + name + "/" + res[1] + " " + res[2] + "\n") } } } if b.Len() == 0 { logs.WithF(hap.fields).Debug("Nothing to update by socket. No weight set") return nil } commands := b.Bytes() logs.WithF(hap.fields.WithField("command", string(commands))).Trace("Running command on hap socket") count, err := conn.Write(commands) if count != len(commands) || err != nil { return errs.WithEF(err, hap.fields. WithField("written", count). WithField("len", len(commands)). WithField("command", string(commands)), "Failed to write command to haproxy") } buff := bufio.NewReader(conn) line, prefix, err := buff.ReadLine() if err != nil || prefix { return errs.WithEF(err, hap.fields.WithField("line-too-long", prefix), "Failed to read hap socket response") } if string(line) != "" { return errs.WithF(hap.fields.WithField("response", string(line)), "Bad response for haproxy socket command") } return nil }
func (n ACFullname) LatestVersion() (string, error) { app, err := discovery.NewAppFromString(n.Name() + ":latest") if app.Labels["os"] == "" { app.Labels["os"] = "linux" } if app.Labels["arch"] == "" { app.Labels["arch"] = "amd64" } endpoints, _, err := discovery.DiscoverACIEndpoints(*app, nil, discovery.InsecureTLS|discovery.InsecureHTTP) //TODO support security if err != nil { return "", errors.Annotate(err, "Latest discovery fail") } r, _ := regexp.Compile(`^\d+(.\d+){0,2}(-[\.\-\dA-Za-z]+){0,1}$`) // TODO this is nexus specific if len(endpoints) == 0 { return "", errs.WithF(data.WithField("aci", string(n)), "Discovery does not give an endpoint to check latest version") } url := getRedirectForLatest(endpoints[0].ACI) logs.WithField("url", url).Debug("latest verion url") for _, part := range strings.Split(url, "/") { if r.Match([]byte(part)) { return part, nil } } return "", errors.New("No latest version found") }
func ExecCommandFull(cmd []string, env []string, timeoutInMilli int) error { command := exec.Command(cmd[0], cmd[1:]...) var b bytes.Buffer command.Stdout = &b command.Stderr = &b command.Env = env if err := command.Start(); err != nil { return errs.WithEF(err, data.WithField("cmd", cmd), "Failed to start command") } var after *errs.EntryError timer := time.AfterFunc(time.Duration(timeoutInMilli)*time.Millisecond, func() { data := data.WithField("command", strings.Join(cmd, " ")).WithField("timeout", timeoutInMilli) logs.WithF(data).Debug("Command timeout") after = errs.WithF(data, "Exec command timeout") command.Process.Kill() }) err := command.Wait() timer.Stop() if logs.IsTraceEnabled() { logs.WithField("cmd", cmd).WithField("output", string(b.Bytes())).Trace("Command output") } if err != nil { return errs.WithEF(err, data.WithField("cmd", cmd). WithField("output", string(b.Bytes())), "Command failed"). WithErr(after) } return nil }
func RouterFromJson(content []byte, s *Synapse) (Router, error) { t := &RouterCommon{} if err := json.Unmarshal([]byte(content), t); err != nil { return nil, errs.WithE(err, "Failed to unmarshall check type") } fields := data.WithField("type", t.Type) var typedRouter Router switch t.Type { case "console": typedRouter = NewRouterConsole() case "haproxy": typedRouter = NewRouterHaProxy() case "template": typedRouter = NewRouterTemplate() default: return nil, errs.WithF(fields, "Unsupported router type") } if err := json.Unmarshal([]byte(content), &typedRouter); err != nil { return nil, errs.WithEF(err, fields, "Failed to unmarshall router") } if err := typedRouter.Init(s); err != nil { return nil, errs.WithEF(err, fields, "Failed to init router") } return typedRouter, nil }
func CheckerFromJson(data []byte, s *Service) (Checker, error) { t := &CheckCommon{} if err := json.Unmarshal([]byte(data), t); err != nil { return nil, errs.WithE(err, "Failed to unmarshall check type") } fields := s.fields.WithField("type", t.Type) var typedCheck Checker switch t.Type { case "http": typedCheck = NewCheckHttp() case "proxyhttp": typedCheck = NewCheckProxyHttp() case "tcp": typedCheck = NewCheckTcp() case "sql": typedCheck = NewCheckSql() case "amqp": typedCheck = NewCheckAmqp() case "exec": typedCheck = NewCheckExec() default: return nil, errs.WithF(fields, "Unsupported check type") } if err := json.Unmarshal([]byte(data), &typedCheck); err != nil { return nil, errs.WithEF(err, fields, "Failed to unmarshall check") } if err := typedCheck.Init(s); err != nil { return nil, errs.WithEF(err, fields, "Failed to init check") } return typedCheck, nil }
func ReporterFromJson(data []byte, s *Service) (Reporter, error) { t := &ReporterCommon{} if err := json.Unmarshal([]byte(data), t); err != nil { return nil, errs.WithE(err, "Failed to unmarshall reporter type") } fields := s.fields.WithField("type", t.Type) var typedReporter Reporter switch t.Type { case "file": typedReporter = NewReporterFile() case "console": typedReporter = NewReporterConsole() case "zookeeper": typedReporter = NewReporterZookeeper() default: return nil, errs.WithF(fields, "Unsupported reporter type") } if err := json.Unmarshal([]byte(data), &typedReporter); err != nil { return nil, errs.WithEF(err, fields, "Failed to unmarshall reporter") } if err := typedReporter.getCommon().Init(s); err != nil { return nil, errs.WithEF(err, fields, "Failed to init common reporter") } if err := typedReporter.Init(s); err != nil { return nil, errs.WithEF(err, fields, "Failed to init reporter") } return typedReporter, nil }
func (n *Nerve) getService(name string) (*Service, error) { for _, s := range n.Services { if s.Name == name { return s, nil } } return nil, errs.WithF(n.fields.WithField("name", name), "No service found with this name") }
func (n *ReportSortType) UnmarshalJSON(d []byte) error { var s string if err := json.Unmarshal(d, &s); err != nil { return errs.WithF(data.WithField("value", string(d)), "Failed to unmarsal serverSort") } switch strings.ToLower(s) { case string(SORT_RANDOM): *n = SORT_RANDOM case string(SORT_NAME): *n = SORT_NAME case string(SORT_DATE): *n = SORT_DATE default: return errs.WithF(data.WithField("value", s), "Unknown serverSort") } return nil }
func (r *RouterCommon) GetService(name string) (*Service, error) { for _, s := range r.Services { if s.Name == name { return s, nil } } return nil, errs.WithF(r.fields.WithField("name", name), "Cannot found service with this name") }
func (r *RouterHaProxy) Init(s *Synapse) error { if err := r.commonInit(r, s); err != nil { return errs.WithEF(err, r.RouterCommon.fields, "Failed to init common router") } if err := r.HaProxyClient.Init(); err != nil { return errs.WithEF(err, r.RouterCommon.fields, "Failed to init haproxy client") } r.synapse.routerUpdateFailures.WithLabelValues(r.Type + PrometheusLabelSocketSuffix).Set(0) r.synapse.routerUpdateFailures.WithLabelValues(r.Type).Set(0) if r.ConfigPath == "" { return errs.WithF(r.RouterCommon.fields, "ConfigPath is required for haproxy router") } if len(r.ReloadCommand) == 0 { return errs.WithF(r.RouterCommon.fields, "ReloadCommand is required for haproxy router") } return nil }
func (p *Pod) fillRuntimeAppFromDependencies(e *common.RuntimeApp) error { fields := p.fields.WithField("aci", e.Name) if len(e.Dependencies) > 1 && len(e.App.Exec) == 0 { return errs.WithF(fields, "There is more than 1 dependency, manifest aci must be set explicitly") } if len(e.Dependencies) == 1 { Home.Rkt.Fetch(e.Dependencies[0].String()) manifestStr, err := Home.Rkt.CatManifest(e.Dependencies[0].String()) if err != nil { return errs.WithEF(err, fields.WithField("dependency", e.Dependencies[0].String()), "Failed to get dependency manifest") } manifest := schema.ImageManifest{} if err := json.Unmarshal([]byte(manifestStr), &manifest); err != nil { return errs.WithEF(err, fields.WithField("content", manifestStr), "Failed to unmarshal stage1 manifest received from rkt") } if len(e.App.Exec) == 0 { e.App.Exec = manifest.App.Exec } if e.App.User == "" { e.App.User = manifest.App.User } if e.App.Group == "" { e.App.Group = manifest.App.Group } if e.App.WorkingDirectory == "" { e.App.WorkingDirectory = manifest.App.WorkingDirectory } if len(e.App.SupplementaryGIDs) == 0 { e.App.SupplementaryGIDs = manifest.App.SupplementaryGIDs } if len(e.App.Isolators) == 0 { e.App.Isolators = manifest.App.Isolators } if len(e.App.Ports) == 0 { e.App.Ports = manifest.App.Ports } if len(e.App.MountPoints) == 0 { e.App.MountPoints = manifest.App.MountPoints } if len(e.App.Environment) == 0 { e.App.Environment = manifest.App.Environment } anns := e.Annotations e.Annotations = manifest.Annotations for _, ann := range anns { e.Annotations.Set(ann.Name, ann.Value) } } return nil }
func (b BuilderCommand) CommandManifestKey() (string, error) { switch b { case CommandBuild: return "blablacar.github.io/dgr/stage1/build", nil case CommandInit: return "blablacar.github.io/dgr/stage1/init", nil case CommandTry: return "blablacar.github.io/dgr/stage1/try", nil default: return "", errs.WithF(data.WithField("command", b), "Unimplemented command manifest key") } }
func (n *Nerve) ServicesWeight(ctx *macaron.Context) { weight := uint8(ctx.ParamsInt(":weight")) if weight <= 0 || weight > 255 { ctx.Resp.WriteHeader(400) ctx.Write([]byte(errs.WithF(n.fields.WithField("weight", weight), "Invalid weight value").Error())) return } for _, service := range n.Services { service.Weight = weight service.runNotify() } n.ServicesStatus(ctx) }
func (r *RouterTemplate) Init(s *Synapse) error { if err := r.commonInit(r, s); err != nil { return errs.WithEF(err, r.fields, "Failed to init common router") } if r.DestinationFile == "" { return errs.WithF(r.fields, "DestinationFile is mandatory") } r.fields = r.fields.WithField("file", r.DestinationFile) if r.DestinationFileMode == 0 { r.DestinationFileMode = 0644 } if r.Template == "" && r.TemplateFile == "" { return errs.WithF(r.fields, "Template or TemplateFile are mandatory") } if r.Template != "" && r.TemplateFile != "" { return errs.WithF(r.fields, "use Template or TemplateFile") } if r.PostTemplateCommandTimeoutInMilli == 0 { r.PostTemplateCommandTimeoutInMilli = 2000 } if r.TemplateFile != "" { content, err := ioutil.ReadFile(r.TemplateFile) if err != nil { return errs.WithEF(err, r.fields.WithField("template", r.TemplateFile), "Failed to read template file") } r.Template = string(content) } tmpl, err := template.NewTemplating(nil, r.DestinationFile, r.Template) if err != nil { return err } r.tmpl = tmpl return nil }
func (aci *Aci) Push() error { defer aci.giveBackUserRightsToTarget() if Home.Config.Push.Type == "" { return errs.WithF(aci.fields, "Cannot push, push is not configured in dgr global configuration file") } if err := aci.EnsureBuilt(); err != nil { return err } if aci.args.Test { aci.args.Test = false if err := aci.Test(); err != nil { return err } } logs.WithF(aci.fields).Info("Gzipping aci before upload") im, err := common.ExtractManifestFromAci(aci.target + pathImageAci) if err != nil { return errs.WithEF(err, aci.fields.WithField("file", pathImageAci), "Failed to extract manifest from aci file") } val, ok := im.Labels.Get("version") if !ok { return errs.WithEF(err, aci.fields.WithField("file", pathImageAci), "Failed to get version from aci manifest") } if err := aci.zipAci(); err != nil { return errs.WithEF(err, aci.fields, "Failed to zip aci") } logs.WithF(aci.fields).Info("Uploading aci") if err := common.ExecCmd("curl", "-f", "-i", "-F", "r=releases", "-F", "hasPom=false", "-F", "e=aci", "-F", "g=com.blablacar.aci.linux.amd64", "-F", "p=aci", "-F", "v="+val, "-F", "a="+strings.Split(string(im.Name), "/")[1], "-F", "file=@"+aci.target+pathImageGzAci, "-u", Home.Config.Push.Username+":"+Home.Config.Push.Password, Home.Config.Push.Url+"/service/local/artifact/maven/content"); err != nil { return errs.WithEF(err, aci.fields, "Failed to push aci") } return nil }
func (r *ReporterFile) Init(s *Service) error { if r.Path == "" { return errs.WithF(s.fields, "Reporter file need a path") } r.fields = r.fields.WithField("path", r.Path) if err := os.MkdirAll(path.Dir(r.Path), 0755); err != nil { return errs.WithEF(err, r.fields.WithField("path", path.Dir(r.Path)), "Failed to create directories") } file, err := r.openReport() if err != nil { return err } defer file.Close() return nil }
func (m *AciManifest) GetFroms() ([]ACFullname, error) { var froms []ACFullname switch v := m.From.(type) { case string: froms = []ACFullname{*NewACFullName(m.From.(string))} case []interface{}: for _, from := range m.From.([]interface{}) { froms = append(froms, *NewACFullName(from.(string))) } case nil: return froms, nil default: return nil, errs.WithF(data.WithField("type", v), "Invalid from type format") } return froms, nil }
func (r *ReporterZookeeper) Init(s *Service) error { if r.Path == "" { return errs.WithF(r.fields, "Zookeeper reporter require a path to report to") } r.fields = r.fields.WithField("path", r.Path) r.fullPath = r.Path + "/" + s.Name + "_" + s.Host r.currentNode = r.fullPath conn, err := NewSharedZkConnection(r.Hosts, time.Duration(r.ConnectionTimeoutInMilli)*time.Millisecond) if err != nil { return errs.WithEF(err, r.fields, "Failed to prepare connection to zookeeper") } r.connection = conn return nil }
func (b *Builder) writeManifest() error { upperId, err := b.upperTreeStoreId() if err != nil { return err } attrMerger, err := merger.NewAttributesMerger(b.stage1Rootfs + PATH_DGR + PATH_BUILDER + PATH_ATTRIBUTES) if err != nil { logs.WithE(err).Warn("Failed to prepare attributes") } attributes := attrMerger.Merge() logs.WithFields(b.fields).WithField("attributes", attributes).Debug("Merged attributes for manifest templating") content, err := ioutil.ReadFile(b.aciTargetPath + common.PathManifestYmlTmpl) if err != nil { return errs.WithEF(err, b.fields.WithField("file", b.aciTargetPath+common.PathManifestYmlTmpl), "Failed to read manifest template") } aciManifest, err := common.ProcessManifestTemplate(string(content), attributes, true) if err != nil { return errs.WithEF(err, b.fields.WithField("content", string(content)), "Failed to process manifest template") } target := b.pod.Root + PATH_OVERLAY + "/" + upperId + PATH_UPPER + common.PathManifest dgrVersion, ok := manifestApp(b.pod).App.Environment.Get(common.EnvDgrVersion) if !ok { return errs.WithF(b.fields, "Cannot find dgr version") } froms, err := aciManifest.GetFroms() if len(froms) != 0 { if froms[0].String() != "" { aciManifest.Aci.Dependencies = append(froms, aciManifest.Aci.Dependencies...) } } if aciManifest.NameAndVersion.Version() == "" { aciManifest.NameAndVersion = *common.NewACFullName(aciManifest.NameAndVersion.Name() + ":" + common.GenerateVersion(b.aciTargetPath)) } if err := common.WriteAciManifest(aciManifest, target, aciManifest.NameAndVersion.Name(), dgrVersion); err != nil { return errs.WithEF(err, b.fields.WithField("file", target), "Failed to write manifest") } return nil }
func (cfg *Config) GetSignKeyring(domain string) (*Sign, error) { var keyring *Sign for _, sign := range *cfg.Signs { if len(sign.Domains) == 0 { keyring = &sign } else { for _, signDomain := range sign.Domains { if signDomain == domain { return &sign, nil } } } } if keyring == nil { return nil, errs.WithF(data.WithField("domain", domain), "Cannot found keyring for this domain on dgr configuration") } return keyring, nil }
func (n *Nerve) Start(startStatus chan error) { logs.Info("Starting nerve") if len(n.Services) == 0 { if startStatus != nil { startStatus <- errs.WithF(n.fields, "No service specified") } return } for _, service := range n.Services { go service.Start(n.serviceStopper, &n.servicesStopWait) } res := n.startApi() if startStatus != nil { startStatus <- res } }
func renderServerOptionsTemplate(report Report, serverOptions HapServerOptionsTemplate) (string, error) { if serverOptions.Template == nil { return "", nil } var buff bytes.Buffer if err := serverOptions.Execute(&buff, struct { Name string }{ Name: report.Name, }); err != nil { return "", errs.WithE(err, "Failed to template serverOptions") } res := buff.String() if strings.Contains(res, "<no value>") { return "", errs.WithF(data.WithField("content", res), "serverOption templating has <no value>") } return res, nil }
func (n *Nerve) ServiceWeight(ctx *macaron.Context) { weight := uint8(ctx.ParamsInt(":weight")) if weight <= 0 || weight > 255 { ctx.Resp.WriteHeader(400) ctx.Write([]byte(errs.WithF(n.fields.WithField("weight", weight), "Invalid weight value").Error())) return } service, err := n.getService(ctx.Params(":service")) if err != nil { ctx.Resp.WriteHeader(404) ctx.Write([]byte(errs.WithEF(err, n.fields, "Not found").Error())) } service.Weight = weight service.runNotify() n.ServiceStatus(ctx) }
func (rkt *RktClient) Version() (Version, error) { output, err := ExecCmdGetOutput(rkt.globalArgs[0], "version") if err != nil { return "", errs.WithEF(err, rkt.fields, "Failed to get rkt Version") } scanner := bufio.NewScanner(strings.NewReader(output)) for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "rkt Version:") { var versionString string if read, err := fmt.Sscanf(line, "rkt Version: %s", &versionString); read != 1 || err != nil { return "", errs.WithEF(err, rkt.fields.WithField("cpntent", line), "Failed to read rkt version") } version := Version(versionString) return version, nil } } return "", errs.WithF(rkt.fields.WithField("content", output), "Cannot found rkt version from rkt call") }
func ProcessManifestTemplate(manifestContent string, data2 interface{}, checkNoValue bool) (*AciManifest, error) { manifest := AciManifest{Aci: AciDefinition{}} fields := data.WithField("source", manifestContent) template, err := template.NewTemplating(nil, "", manifestContent) if err != nil { return nil, errs.WithEF(err, fields, "Failed to load templating of manifest") } var b bytes.Buffer writer := bufio.NewWriter(&b) if err := template.Execute(writer, data2); err != nil { return nil, errs.WithEF(err, fields, "Failed to template manifest") } if err := writer.Flush(); err != nil { return nil, errs.WithEF(err, fields, "Failed to flush buffer") } templated := b.Bytes() if logs.IsDebugEnabled() { logs.WithField("content", string(templated)).Debug("Templated manifest") } if checkNoValue { scanner := bufio.NewScanner(bytes.NewReader(templated)) scanner.Split(bufio.ScanLines) for i := 1; scanner.Scan(); i++ { text := scanner.Text() if bytes.Contains([]byte(text), []byte("<no value>")) { return nil, errs.WithF(fields.WithField("line", i).WithField("text", text), "Templating result of manifest have <no value>") } } } err = yaml.Unmarshal(templated, &manifest) if err != nil { return nil, errs.WithEF(err, fields, "Cannot unmarshall manifest") } return &manifest, nil }
func (x *CheckProxyHttp) Check() error { result := make(chan error) for _, url := range x.Urls { go func(url string) { var res error resp, err := x.client.Get(url) if err != nil || (resp.StatusCode >= 500 && resp.StatusCode < 600) { ff := x.fields.WithField("url", url) if err == nil { ff = ff.WithField("status_code", resp.StatusCode) if content, err := ioutil.ReadAll(resp.Body); err == nil { ff = ff.WithField("content", string(content)) } resp.Body.Close() } res = errs.WithEF(err, ff, "Url check failed") logs.WithEF(err, x.fields).Trace("Url check failed") } if err == nil { resp.Body.Close() } result <- res }(url) } errors := errs.WithF(x.fields, "Url(s) unreachable") for i := 0; i < len(x.Urls); i++ { res := <-result if res != nil { errors.WithErr(res) } } if (x.FailOnAnyUnreachable && len(errors.Errs) > 0) || (!x.FailOnAnyUnreachable && len(errors.Errs) == len(x.Urls)) { logs.WithEF(errors, x.fields).Trace("Enough failed received") return errs.WithEF(errors, x.fields, "Enough failed received") } return nil }
func NewRktClient(config RktConfig) (*RktClient, error) { if len(config.InsecureOptions) == 0 { config.InsecureOptions = []string{"ondisk", "image"} } rkt := &RktClient{ fields: data.WithField("config", config), config: config, globalArgs: config.prepareGlobalArgs(config.InsecureOptions), } v, err := rkt.Version() if err != nil { return nil, err } if v.LessThan(rktSupportedVersion) { return nil, errs.WithF(rkt.fields.WithField("current", v).WithField("required", ">="+rktSupportedVersion), "Unsupported version of rkt") } logs.WithField("version", v).WithField("args", rkt.globalArgs).Debug("New rkt client") return rkt, nil }
func (f *TemplateFile) runTemplate(dst string, attributes map[string]interface{}) error { if logs.IsTraceEnabled() { logs.WithF(f.fields).WithField("attributes", attributes).Trace("templating with attributes") } fields := f.fields.WithField("dst", dst) logs.WithF(fields).Info("Templating file") out, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, f.srcMode) if err != nil { return errs.WithEF(err, fields, "Cannot open destination file") } defer func() { out.Close() }() buff := bytes.Buffer{} writer := bufio.NewWriter(&buff) if err := f.template.Execute(writer, attributes); err != nil { return errs.WithEF(err, fields, "Templating execution failed") } if err := writer.Flush(); err != nil { return errs.WithEF(err, fields, "Failed to flush buffer") } b := buff.Bytes() if logs.IsTraceEnabled() { logs.WithF(f.fields).WithField("result", string(b)).Trace("templating done") } if bytes.Contains(b, []byte("<no value>")) { return errs.WithF(fields, "Templating result have <no value>") } out.Write(b) if err = out.Sync(); err != nil { return errs.WithEF(err, fields, "Failed to sync output file") } return nil }
func (b *Builder) getCommandPath() (string, error) { command, ok := manifestApp(b.pod).App.Environment.Get(common.EnvBuilderCommand) if !ok { return string(common.CommandBuild), errs.WithF(b.fields.WithField("env_name", common.EnvBuilderCommand), "No command sent to builder using environment var") } key, err := common.BuilderCommand(command).CommandManifestKey() if err != nil { return "", errs.WithEF(err, b.fields, "Unknown command") } stage1Manifest, err := b.getStage1Manifest() if err != nil { return "", err } commandPath, ok := stage1Manifest.Annotations.Get(key) if !ok { return "", errs.WithEF(err, b.fields.WithField("key", key), "Stage1 image manifest does not have command annotation") } return string(commandPath), nil }