// prepareUpdate builds an updated release for an update operation. func (s *releaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*release.Release, *release.Release, error) { if req.Name == "" { return nil, nil, errMissingRelease } if req.Chart == nil { return nil, nil, errMissingChart } // finds the non-deleted release with the given name currentRelease, err := s.env.Releases.Deployed(req.Name) if err != nil { return nil, nil, err } // If new values were not supplied in the upgrade, re-use the existing values. s.reuseValues(req, currentRelease) ts := timeconv.Now() options := chartutil.ReleaseOptions{ Name: req.Name, Time: ts, Namespace: currentRelease.Namespace, } valuesToRender, err := chartutil.ToRenderValues(req.Chart, req.Values, options) if err != nil { return nil, nil, err } hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender) if err != nil { return nil, nil, err } // Store an updated release. updatedRelease := &release.Release{ Name: req.Name, Namespace: currentRelease.Namespace, Chart: req.Chart, Config: req.Values, Info: &release.Info{ FirstDeployed: currentRelease.Info.FirstDeployed, LastDeployed: ts, Status: &release.Status{Code: release.Status_UNKNOWN}, }, Version: currentRelease.Version + 1, Manifest: manifestDoc.String(), Hooks: hooks, } if len(notesTxt) > 0 { updatedRelease.Info.Status.Notes = notesTxt } return currentRelease, updatedRelease, nil }
// prepareRelease builds a release for an install operation. func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*release.Release, error) { if req.Chart == nil { return nil, errMissingChart } name, err := s.uniqName(req.Name, req.ReuseName) if err != nil { return nil, err } ts := timeconv.Now() options := chartutil.ReleaseOptions{Name: name, Time: ts, Namespace: req.Namespace} valuesToRender, err := chartutil.ToRenderValues(req.Chart, req.Values, options) if err != nil { return nil, err } hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender) if err != nil { return nil, err } // Store a release. rel := &release.Release{ Name: name, Namespace: req.Namespace, Chart: req.Chart, Config: req.Values, Info: &release.Info{ FirstDeployed: ts, LastDeployed: ts, Status: &release.Status{Code: release.Status_UNKNOWN}, }, Manifest: manifestDoc.String(), Hooks: hooks, Version: 1, } if len(notesTxt) > 0 { rel.Info.Status.Notes = notesTxt } return rel, nil }
// prepareRelease builds a release for an install operation. func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*release.Release, error) { if req.Chart == nil { return nil, errMissingChart } name, err := s.uniqName(req.Name, req.ReuseName) if err != nil { return nil, err } revision := 1 ts := timeconv.Now() options := chartutil.ReleaseOptions{ Name: name, Time: ts, Namespace: req.Namespace, Revision: revision, IsInstall: true, } valuesToRender, err := chartutil.ToRenderValues(req.Chart, req.Values, options) if err != nil { return nil, err } hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender) if err != nil { // Return a release with partial data so that client can show debugging // information. rel := &release.Release{ Name: name, Namespace: req.Namespace, Chart: req.Chart, Config: req.Values, Info: &release.Info{ FirstDeployed: ts, LastDeployed: ts, Status: &release.Status{Code: release.Status_UNKNOWN}, }, Version: 0, } if manifestDoc != nil { rel.Manifest = manifestDoc.String() } return rel, err } // Store a release. rel := &release.Release{ Name: name, Namespace: req.Namespace, Chart: req.Chart, Config: req.Values, Info: &release.Info{ FirstDeployed: ts, LastDeployed: ts, Status: &release.Status{Code: release.Status_UNKNOWN}, }, Manifest: manifestDoc.String(), Hooks: hooks, Version: int32(revision), } if len(notesTxt) > 0 { rel.Info.Status.Notes = notesTxt } return rel, nil }
// Templates lints the templates in the Linter. func Templates(linter *support.Linter) { templatesPath := filepath.Join(linter.ChartDir, "templates") templatesDirExist := linter.RunLinterRule(support.WarningSev, validateTemplatesDir(templatesPath)) // Templates directory is optional for now if !templatesDirExist { return } // Load chart and parse templates, based on tiller/release_server chart, err := chartutil.Load(linter.ChartDir) chartLoaded := linter.RunLinterRule(support.ErrorSev, validateNoError(err)) if !chartLoaded { return } options := chartutil.ReleaseOptions{Name: "testRelease", Time: timeconv.Now(), Namespace: "testNamespace"} valuesToRender, err := chartutil.ToRenderValues(chart, chart.Values, options) if err != nil { // FIXME: This seems to generate a duplicate, but I can't find where the first // error is coming from. //linter.RunLinterRule(support.ErrorSev, err) return } renderedContentMap, err := engine.New().Render(chart, valuesToRender) renderOk := linter.RunLinterRule(support.ErrorSev, validateNoError(err)) if !renderOk { return } /* Iterate over all the templates to check: - It is a .yaml file - All the values in the template file is defined - {{}} include | quote - Generated content is a valid Yaml file - Metadata.Namespace is not set */ for _, template := range chart.Templates { fileName, preExecutedTemplate := template.Name, template.Data linter.RunLinterRule(support.ErrorSev, validateAllowedExtension(fileName)) // We only apply the following lint rules to yaml files if filepath.Ext(fileName) != ".yaml" { continue } // Check that all the templates have a matching value linter.RunLinterRule(support.WarningSev, validateNonMissingValues(fileName, templatesPath, valuesToRender, preExecutedTemplate)) linter.RunLinterRule(support.WarningSev, validateQuotes(fileName, string(preExecutedTemplate))) renderedContent := renderedContentMap[fileName] var yamlStruct K8sYamlStruct // Even though K8sYamlStruct only defines Metadata namespace, an error in any other // key will be raised as well err := yaml.Unmarshal([]byte(renderedContent), &yamlStruct) validYaml := linter.RunLinterRule(support.ErrorSev, validateYamlContent(fileName, err)) if !validYaml { continue } linter.RunLinterRule(support.ErrorSev, validateNoNamespace(fileName, yamlStruct)) } }
func (s *releaseServer) InstallRelease(c ctx.Context, req *services.InstallReleaseRequest) (*services.InstallReleaseResponse, error) { if req.Chart == nil { return nil, errMissingChart } name, err := s.uniqName(req.Name) if err != nil { return nil, err } ts := timeconv.Now() options := chartutil.ReleaseOptions{Name: name, Time: ts, Namespace: s.env.Namespace} valuesToRender, err := chartutil.ToRenderValues(req.Chart, req.Values, options) if err != nil { return nil, err } renderer := s.engine(req.Chart) files, err := renderer.Render(req.Chart, valuesToRender) if err != nil { return nil, err } b := bytes.NewBuffer(nil) for name, file := range files { // Ignore templates that starts with underscore to handle them as partials if strings.HasPrefix(path.Base(name), "_") { continue } // Ignore empty documents because the Kubernetes library can't handle // them. if len(file) > 0 { b.WriteString("\n---\n# Source: " + name + "\n") b.WriteString(file) } } // Store a release. r := &release.Release{ Name: name, Chart: req.Chart, Config: req.Values, Info: &release.Info{ FirstDeployed: ts, LastDeployed: ts, Status: &release.Status{Code: release.Status_UNKNOWN}, }, Manifest: b.String(), } res := &services.InstallReleaseResponse{Release: r} if req.DryRun { log.Printf("Dry run for %s", name) return res, nil } if err := s.env.KubeClient.Create(s.env.Namespace, b); err != nil { r.Info.Status.Code = release.Status_FAILED log.Printf("warning: Release %q failed: %s", name, err) if err := s.env.Releases.Create(r); err != nil { log.Printf("warning: Failed to record release %q: %s", name, err) } return res, fmt.Errorf("release %s failed: %s", name, err) } // This is a tricky case. The release has been created, but the result // cannot be recorded. The truest thing to tell the user is that the // release was created. However, the user will not be able to do anything // further with this release. // // One possible strategy would be to do a timed retry to see if we can get // this stored in the future. if err := s.env.Releases.Create(r); err != nil { log.Printf("warning: Failed to record release %q: %s", name, err) return res, nil } r.Info.Status.Code = release.Status_DEPLOYED return res, nil }