in internal/generators/helm.go [150:235]
func (hg *HelmGenerator) Generate(component *core.Component) (manifest string, err error) {
logger.Info(emoji.Sprintf(":truck: Generating component '%s' with helm with repo %s", component.Name, component.Source))
configYaml, err := yaml.Marshal(&component.Config.Config)
if err != nil {
logger.Error(fmt.Sprintf("Marshalling config yaml for helm generated component '%s' failed with: %s\n", component.Name, err.Error()))
return "", err
}
// Write helm config to temporary file in tmp folder
randomString, err := uuid.NewRandom()
if err != nil {
return "", err
}
overriddenValuesFileName := fmt.Sprintf("%s.yaml", randomString.String())
absOverriddenPath := path.Join(os.TempDir(), overriddenValuesFileName)
defer os.Remove(absOverriddenPath)
logger.Debug(emoji.Sprintf(":pencil: Writing config %s to %s\n", configYaml, absOverriddenPath))
if err = ioutil.WriteFile(absOverriddenPath, configYaml, 0777); err != nil {
return "", err
}
// Default to `default` namespace unless provided
namespace := "default"
if component.Config.Namespace != "" {
namespace = component.Config.Namespace
}
// Run `helm template` on the chart using the config stored in temp dir
chartPath, err := hg.getChartPath(component)
if err != nil {
return "", err
}
logger.Info(emoji.Sprintf(":memo: Running `helm template` on template '%s'", chartPath))
output, err := exec.Command("helm", "template", component.Name, chartPath, "--values", absOverriddenPath, "--namespace", namespace).CombinedOutput()
if err != nil {
logger.Error(fmt.Sprintf("helm template failed with:\n%s: %s", err, output))
return "", err
}
// Remove any empty/non-map entries in manifests
logger.Info(emoji.Sprintf(":scissors: Removing empty entries from generated manifests from chart '%s'", chartPath))
stringManifests, err := cleanK8sManifest(string(output))
if err != nil {
return "", err
}
// helm template does not inject namespace unless chart directly provides support for it: https://github.com/helm/helm/issues/3553
// some helm templates expect Tiller to inject namespace, so enable Fabrikate component designer to
// opt into injecting these namespaces manually. We should reassess if this is necessary after Helm 3 is released and client side
// templating really becomes a first class function in Helm.
if component.Config.InjectNamespace && component.Config.Namespace != "" {
logger.Info(emoji.Sprintf(":syringe: Injecting namespace '%s' into manifests for component '%s'", component.Config.Namespace, component.Name))
var successes []namespaceInjectionResponse
for resp := range addNamespaceToManifests(stringManifests, component.Config.Namespace) {
// If error; return the error immediately
if resp.err != nil {
logger.Error(emoji.Sprintf(":exclamation: Encountered error while injecting namespace '%s' into manifests for component '%s':\n%s", component.Config.Namespace, component.Name, resp.err))
return stringManifests, resp.err
}
// If warning; just log the warning
if resp.warn != nil {
logger.Warn(emoji.Sprintf(":question: Encountered warning while injecting namespace '%s' into manifests for component '%s':\n%s", component.Config.Namespace, component.Name, *resp.warn))
}
// Add the manifest if one was returned
if resp.namespacedManifest != nil {
successes = append(successes, resp)
}
}
sort.Slice(successes, func(i, j int) bool {
return successes[i].index < successes[j].index
})
namespacedManifests := ""
for _, resp := range successes {
namespacedManifests += fmt.Sprintf("---\n%s\n", *resp.namespacedManifest)
}
stringManifests = namespacedManifests
}
return stringManifests, err
}