func (r *Releaser) releaseActionFindPodController(service flux.ServiceID) ReleaseAction { return ReleaseAction{ Description: fmt.Sprintf("Load the resource definition file for service %s", service), Do: func(rc *ReleaseContext) (res string, err error) { defer func(begin time.Time) { r.metrics.ActionDuration.With( "action", "find_pod_controller", "success", fmt.Sprint(err == nil), ).Observe(time.Since(begin).Seconds()) }(time.Now()) resourcePath := rc.ConfigPath() if fi, err := os.Stat(resourcePath); err != nil || !fi.IsDir() { return "", fmt.Errorf("the resource path (%s) is not valid", resourcePath) } namespace, serviceName := service.Components() files, err := kubernetes.FilesFor(resourcePath, namespace, serviceName) if err != nil { return "", errors.Wrapf(err, "finding resource definition file for %s", service) } if len(files) <= 0 { // fine; we'll just skip it return fmt.Sprintf("no resource definition file found for %s; skipping", service), nil } if len(files) > 1 { return "", fmt.Errorf("multiple resource definition files found for %s: %s", service, strings.Join(files, ", ")) } def, err := ioutil.ReadFile(files[0]) // TODO(mb) not multi-doc safe if err != nil { return "", err } rc.PodControllers[service] = def return "Found pod controller OK.", nil }, } }
func (r *Releaser) releaseActionUpdatePodController(service flux.ServiceID, regrades []containerRegrade) ReleaseAction { var actions []string for _, regrade := range regrades { actions = append(actions, fmt.Sprintf("%s (%s -> %s)", regrade.container, regrade.current, regrade.target)) } actionList := strings.Join(actions, ", ") return ReleaseAction{ Description: fmt.Sprintf("Update %d images(s) in the resource definition file for %s: %s.", len(regrades), service, actionList), Do: func(rc *ReleaseContext) (res string, err error) { defer func(begin time.Time) { r.metrics.ActionDuration.With( "action", "update_pod_controller", "success", fmt.Sprint(err == nil), ).Observe(time.Since(begin).Seconds()) }(time.Now()) resourcePath := rc.ConfigPath() if fi, err := os.Stat(resourcePath); err != nil || !fi.IsDir() { return "", fmt.Errorf("the resource path (%s) is not valid", resourcePath) } namespace, serviceName := service.Components() files, err := kubernetes.FilesFor(resourcePath, namespace, serviceName) if err != nil { return "", errors.Wrapf(err, "finding resource definition file for %s", service) } if len(files) <= 0 { return fmt.Sprintf("no resource definition file found for %s; skipping", service), nil } if len(files) > 1 { return "", fmt.Errorf("multiple resource definition files found for %s: %s", service, strings.Join(files, ", ")) } def, err := ioutil.ReadFile(files[0]) if err != nil { return "", err } fi, err := os.Stat(files[0]) if err != nil { return "", err } for _, regrade := range regrades { // Note 1: UpdatePodController parses the target (new) image // name, extracts the repository, and only mutates the line(s) // in the definition that match it. So for the time being we // ignore the current image. UpdatePodController could be // updated, if necessary. // // Note 2: we keep overwriting the same def, to handle multiple // images in a single file. def, err = kubernetes.UpdatePodController(def, string(regrade.target), ioutil.Discard) if err != nil { return "", errors.Wrapf(err, "updating pod controller for %s", regrade.target) } } // Write the file back, so commit/push works. if err := ioutil.WriteFile(files[0], def, fi.Mode()); err != nil { return "", err } // Put the def in the map, so release works. rc.PodControllers[service] = def return "Update pod controller OK.", nil }, } }