cmd/k8s-operator: add Connector CRD to Helm chart and static manifests (#10775)
cmd/k8s-operator: add CRD to chart and static manifest Add functionality to insert CRD to chart at package time. Insert CRD to static manifests as this is where they are currently consumed from. Signed-off-by: Irbe Krumina <irbe@tailscale.com>
This commit is contained in:
@@ -18,15 +18,49 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
operatorDeploymentFilesPath = "cmd/k8s-operator/deploy"
|
||||
crdPath = operatorDeploymentFilesPath + "/crds/tailscale.com_connectors.yaml"
|
||||
helmTemplatesPath = operatorDeploymentFilesPath + "/chart/templates"
|
||||
crdTemplatePath = helmTemplatesPath + "/connectors.yaml"
|
||||
|
||||
helmConditionalStart = "{{ if .Values.installCRDs -}}\n"
|
||||
helmConditionalEnd = "{{- end -}}"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
log.Fatalf("usage ./generate [staticmanifests|helmcrd]")
|
||||
}
|
||||
repoRoot := "../../"
|
||||
cmd := exec.Command("./tool/helm", "template", "operator", "./cmd/k8s-operator/deploy/chart",
|
||||
switch os.Args[1] {
|
||||
case "helmcrd": // insert CRD to Helm templates behind a installCRDs=true conditional check
|
||||
log.Print("Adding Connector CRD to Helm templates")
|
||||
if err := generate("./"); err != nil {
|
||||
log.Fatalf("error adding Connector CRD to Helm templates: %v", err)
|
||||
}
|
||||
return
|
||||
case "staticmanifests": // generate static manifests from Helm templates (including the CRD)
|
||||
default:
|
||||
log.Fatalf("unknown option %s, known options are 'staticmanifests', 'helmcrd'", os.Args[1])
|
||||
}
|
||||
log.Printf("Inserting CRD into the Helm templates")
|
||||
if err := generate(repoRoot); err != nil {
|
||||
log.Fatalf("error adding Connector CRD to Helm templates: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := cleanup(repoRoot); err != nil {
|
||||
log.Fatalf("error cleaning up generated resources")
|
||||
}
|
||||
}()
|
||||
log.Print("Templating Helm chart contents")
|
||||
helmTmplCmd := exec.Command("./tool/helm", "template", "operator", "./cmd/k8s-operator/deploy/chart",
|
||||
"--namespace=tailscale")
|
||||
cmd.Dir = repoRoot
|
||||
helmTmplCmd.Dir = repoRoot
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
helmTmplCmd.Stdout = &out
|
||||
helmTmplCmd.Stderr = os.Stderr
|
||||
if err := helmTmplCmd.Run(); err != nil {
|
||||
log.Fatalf("error templating helm manifests: %v", err)
|
||||
}
|
||||
|
||||
@@ -54,7 +88,6 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatalf("failed read from input data: %v", err)
|
||||
}
|
||||
|
||||
bytes, err := yaml.Marshal(document)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to marshal YAML document: %v", err)
|
||||
@@ -72,3 +105,35 @@ func main() {
|
||||
log.Fatalf("error writing new file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func generate(baseDir string) error {
|
||||
log.Print("Placing Connector CRD into Helm templates..")
|
||||
chartBytes, err := os.ReadFile(filepath.Join(baseDir, crdPath))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading CRD contents: %w", err)
|
||||
}
|
||||
// Place a new temporary Helm template file with the templated CRD
|
||||
// contents into Helm templates.
|
||||
file, err := os.Create(filepath.Join(baseDir, crdTemplatePath))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating CRD template file: %w", err)
|
||||
}
|
||||
if _, err := file.Write([]byte(helmConditionalStart)); err != nil {
|
||||
return fmt.Errorf("error writing helm if statement start: %w", err)
|
||||
}
|
||||
if _, err := file.Write(chartBytes); err != nil {
|
||||
return fmt.Errorf("error writing chart bytes: %w", err)
|
||||
}
|
||||
if _, err := file.Write([]byte(helmConditionalEnd)); err != nil {
|
||||
return fmt.Errorf("error writing helm if-statement end: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanup(baseDir string) error {
|
||||
log.Print("Cleaning up CRD from Helm templates")
|
||||
if err := os.Remove(filepath.Join(baseDir, crdTemplatePath)); err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("error cleaning up CRD template: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !plan9 && !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_generate(t *testing.T) {
|
||||
base, err := os.Getwd()
|
||||
base = filepath.Join(base, "../../../")
|
||||
if err != nil {
|
||||
t.Fatalf("error getting current working directory: %v", err)
|
||||
}
|
||||
defer cleanup(base)
|
||||
if err := generate(base); err != nil {
|
||||
t.Fatalf("CRD template generation: %v", err)
|
||||
}
|
||||
|
||||
tempDir := t.TempDir()
|
||||
helmCLIPath := filepath.Join(base, "tool/helm")
|
||||
helmChartTemplatesPath := filepath.Join(base, "cmd/k8s-operator/deploy/chart")
|
||||
helmPackageCmd := exec.Command(helmCLIPath, "package", helmChartTemplatesPath, "--destination", tempDir, "--version", "0.0.1")
|
||||
helmPackageCmd.Stderr = os.Stderr
|
||||
helmPackageCmd.Stdout = os.Stdout
|
||||
if err := helmPackageCmd.Run(); err != nil {
|
||||
t.Fatalf("error packaging Helm chart: %v", err)
|
||||
}
|
||||
helmPackagePath := filepath.Join(tempDir, "tailscale-operator-0.0.1.tgz")
|
||||
helmLintCmd := exec.Command(helmCLIPath, "lint", helmPackagePath)
|
||||
helmLintCmd.Stderr = os.Stderr
|
||||
helmLintCmd.Stdout = os.Stdout
|
||||
if err := helmLintCmd.Run(); err != nil {
|
||||
t.Fatalf("Helm chart linter failed: %v", err)
|
||||
}
|
||||
|
||||
// Test that default Helm install contains the CRD
|
||||
installContentsWithCRD := bytes.NewBuffer([]byte{})
|
||||
helmTemplateWithCRDCmd := exec.Command(helmCLIPath, "template", helmPackagePath)
|
||||
helmTemplateWithCRDCmd.Stderr = os.Stderr
|
||||
helmTemplateWithCRDCmd.Stdout = installContentsWithCRD
|
||||
if err := helmTemplateWithCRDCmd.Run(); err != nil {
|
||||
t.Fatalf("templating Helm chart with CRDs failed: %v", err)
|
||||
}
|
||||
if !strings.Contains(installContentsWithCRD.String(), "name: connectors.tailscale.com") {
|
||||
t.Errorf("CRD not found in default chart install")
|
||||
}
|
||||
|
||||
// Test that CRD can be excluded from Helm chart install
|
||||
installContentsWithoutCRD := bytes.NewBuffer([]byte{})
|
||||
helmTemplateWithoutCRDCmd := exec.Command(helmCLIPath, "template", helmPackagePath, "--set", "installCRDs=false")
|
||||
helmTemplateWithoutCRDCmd.Stderr = os.Stderr
|
||||
helmTemplateWithoutCRDCmd.Stdout = installContentsWithoutCRD
|
||||
if err := helmTemplateWithoutCRDCmd.Run(); err != nil {
|
||||
t.Fatalf("templating Helm chart without CRDs failed: %v", err)
|
||||
}
|
||||
if strings.Contains(installContentsWithoutCRD.String(), "name: connectors.tailscale.com") {
|
||||
t.Errorf("CRD found in chart install that should not contain a CRD")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user