Skip to content

Commit

Permalink
Merge pull request #4872 from geoberle/helm
Browse files Browse the repository at this point in the history
ARO-11084: Helm chart generator
  • Loading branch information
openshift-merge-bot[bot] authored Oct 28, 2024
2 parents 0f7bc58 + a45df44 commit a95fc46
Show file tree
Hide file tree
Showing 9 changed files with 388 additions and 61 deletions.
4 changes: 4 additions & 0 deletions cmd/install/assets/hypershift_operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ type HyperShiftOperatorDeployment struct {
EnableCPOOverrides bool
AROHCPKeyVaultUsersClientID string
TechPreviewNoUpgrade bool
RegistryOverrides string
}

// String returns a string containing all enabled feature gates, formatted as "key1=value1,key2=value2,...".
Expand Down Expand Up @@ -408,6 +409,9 @@ func (o HyperShiftOperatorDeployment) Build() *appsv1.Deployment {
if o.TechPreviewNoUpgrade {
args = append(args, fmt.Sprintf("--feature-gates=%s", featureGateString()))
}
if o.RegistryOverrides != "" {
args = append(args, fmt.Sprintf("--registry-overrides=%s", o.RegistryOverrides))
}

var volumeMounts []corev1.VolumeMount
var initVolumeMounts []corev1.VolumeMount
Expand Down
10 changes: 9 additions & 1 deletion cmd/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ type Options struct {
EnableCPOOverrides bool
AroHCPKeyVaultUsersClientID string
TechPreviewNoUpgrade bool
RegistryOverrides string
RenderNamespace bool
}

func (o *Options) Validate() error {
Expand Down Expand Up @@ -166,6 +168,7 @@ func (o *Options) Validate() error {
}

func (o *Options) ApplyDefaults() {
o.RenderNamespace = true
switch {
case o.Development:
o.HyperShiftOperatorReplicas = 0
Expand Down Expand Up @@ -241,6 +244,7 @@ func NewCommand() *cobra.Command {
cmd.PersistentFlags().BoolVar(&opts.EnableCPOOverrides, "enable-cpo-overrides", opts.EnableCPOOverrides, "If true, the HyperShift operator uses a set of static overrides for the CPO image given specific release versions")
cmd.PersistentFlags().StringVar(&opts.AroHCPKeyVaultUsersClientID, "aro-hcp-key-vault-users-client-id", opts.AroHCPKeyVaultUsersClientID, "The client ID of the managed identity which can access the Azure Key Vaults, in an AKS management cluster, to retrieve secrets and certificates.")
cmd.PersistentFlags().BoolVar(&opts.TechPreviewNoUpgrade, "tech-preview-no-upgrade", opts.TechPreviewNoUpgrade, "If true, the HyperShift operator runs with TechPreviewNoUpgrade features enabled")
cmd.PersistentFlags().StringVar(&opts.RegistryOverrides, "registry-overrides", "", "registry-overrides contains the source registry string as a key and the destination registry string as value. Images before being applied are scanned for the source registry string and if found the string is replaced with the destination registry string. Format is: sr1=dr1,sr2=dr2")

cmd.RunE = func(cmd *cobra.Command, args []string) error {
opts.ApplyDefaults()
Expand Down Expand Up @@ -280,6 +284,7 @@ func NewCommand() *cobra.Command {
}

cmd.AddCommand(NewRenderCommand(&opts))
cmd.AddCommand(NewHelmRenderCommand(&opts))

return cmd
}
Expand Down Expand Up @@ -478,7 +483,9 @@ func hyperShiftOperatorManifests(opts Options) ([]crclient.Object, []crclient.Ob
Name: opts.Namespace,
EnableOCPClusterMonitoring: opts.PlatformMonitoring.IsEnabled(),
}.Build()
objects = append(objects, operatorNamespace)
if opts.RenderNamespace {
objects = append(objects, operatorNamespace)
}

// Setup RBAC resources
operatorServiceAccount, rbacObjs := setupRBAC(opts, operatorNamespace)
Expand Down Expand Up @@ -710,6 +717,7 @@ func setupOperatorResources(opts Options, userCABundleCM *corev1.ConfigMap, trus
EnableCPOOverrides: opts.EnableCPOOverrides,
AROHCPKeyVaultUsersClientID: opts.AroHCPKeyVaultUsersClientID,
TechPreviewNoUpgrade: opts.TechPreviewNoUpgrade,
RegistryOverrides: opts.RegistryOverrides,
}.Build()
operatorService := assets.HyperShiftOperatorService{
Namespace: operatorNamespace,
Expand Down
155 changes: 155 additions & 0 deletions cmd/install/install_helm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package install

import (
"fmt"
"os"
"strings"

"github.com/openshift/hypershift/pkg/version"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
)

var helmTemplateParams = TemplateParams{
Namespace: ".Release.Namespace",
HyperShiftImage: ".Values.image",
HyperShiftImageTag: ".Values.imagetag",
OIDCS3Name: ".Values.oidc.s3.name",
OIDCS3Region: ".Values.oidc.s3.region",
OIDCS3CredsSecret: ".Values.oidc.s3.credsSecret",
OIDCS3CredsSecretKey: ".Values.oidc.s3.credsSecretKey",
AWSPrivateRegion: ".Values.aws.private.region",
AWSPrivateCredsSecret: ".Values.aws.private.credsSecret",
AWSPrivateCredsSecretKey: ".Values.aws.private.credsSecretKey",
ExternalDNSCredsSecret: ".Values.externaldns.credsSecret",
ExternalDNSDomainFilter: ".Values.externaldns.domainFilter",
ExternalDNSTxtOwnerID: ".Values.externaldns.txtOwnerId",
ExternalDNSImage: ".Values.externaldns.image",
RegistryOverrides: ".Values.registryOverrides",
AROHCPKeyVaultUsersClientID: ".Values.azure.keyVault.clientId",
TemplateNamespace: false,
TemplateParamWrapper: func(name string) string {
return fmt.Sprintf("{{ %s }}", name)
},
}

func NewHelmRenderCommand(opts *Options) *cobra.Command {
cmd := &cobra.Command{
Use: "helm",
Short: "Generate a Helm chart for the HyperShift Operator",
SilenceUsage: true,
}

cmd.Flags().StringVar(&opts.OutputFile, "output-dir", "", "Directory to write the rendered helm chart to")

cmd.RunE = func(cmd *cobra.Command, args []string) error {
opts.ApplyDefaults()

crds, manifests, err := hyperShiftOperatorTemplateManifest(opts, helmTemplateParams)
if err != nil {
return err
}

if opts.OutputFile == "" {
opts.OutputFile = "./chart"
}
err = writeManifestsToDir(crds, fmt.Sprintf("%s/crds", opts.OutputFile))
if err != nil {
return err
}
err = writeManifestsToDir(manifests, fmt.Sprintf("%s/templates", opts.OutputFile))
if err != nil {
return err
}
err = WriteChartYaml(opts.OutputFile)
if err != nil {
return err
}
err = WriteValuesFile(opts.OutputFile)
if err != nil {
return err
}
return nil
}

return cmd
}

func WriteChartYaml(dir string) error {
data := map[string]interface{}{
"apiVersion": "v2",
"name": "hypershift-operator",
"description": "A Helm chart for the HyperShift Operator",
"type": "application",
"version": "0.1.0",
"appVersion": version.GetRevision(),
}
return writeYamlFile(fmt.Sprintf("%s/Chart.yaml", dir), data)
}

func WriteValuesFile(dir string) error {
data := map[string]interface{}{
"image": "",
"imagetag": "",
"registryOverrides": "",
"azure": map[string]interface{}{
"keyVault": map[string]interface{}{
"clientId": "",
},
},
"oidc": map[string]interface{}{
"s3": map[string]interface{}{
"name": "",
"region": "",
"credsSecret": "",
"credsSecretKey": "",
},
},
"aws": map[string]interface{}{
"private": map[string]interface{}{
"region": "",
"credsSecret": "",
"credsSecretKey": "",
},
},
}
return writeYamlFile(fmt.Sprintf("%s/values.yaml", dir), data)
}

func writeYamlFile(path string, data map[string]interface{}) error {
yamlData, err := yaml.Marshal(data)
if err != nil {
return err
}
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
_, err = file.Write(yamlData)
if err != nil {
return err
}
return nil
}

func writeManifestsToDir(manifests []crclient.Object, dir string) error {
err := os.MkdirAll(dir, os.ModePerm)
if err != nil {
return err
}

for _, manifest := range manifests {
file, err := os.Create(fmt.Sprintf("%s/%s-%s.yaml", dir, strings.ToLower(manifest.GetObjectKind().GroupVersionKind().Kind), manifest.GetName()))
if err != nil {
return err
}
defer file.Close()
err = render([]crclient.Object{manifest}, RenderFormatYaml, file)
if err != nil {
return err
}
}
return nil
}
75 changes: 75 additions & 0 deletions cmd/install/install_helm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package install

import (
"bytes"
"io"
"os"
"testing"

"github.com/openshift/hypershift/support/testutil"
)

func ExecuteTestHelmCommand(args []string) ([]byte, error) {
// append helm to args
args = append([]string{"helm"}, args...)
cmd := NewCommand()
cmd.SetArgs(args)
b := bytes.NewBufferString("")
cmd.SetOut(b)
err := cmd.Execute()
if err != nil {
return []byte{}, err
}
return io.ReadAll(b)
}

func TestHelmCommand(t *testing.T) {
// create a folder to hold test data and delete it afterwards
tmpDir, err := os.MkdirTemp("", "test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)

_, err = ExecuteTestHelmCommand([]string{"--output-dir", tmpDir})
if err != nil {
t.Fatal(err)
}

// check if the output directory exists
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
t.Fatalf("Output directory %s does not exist", tmpDir)
}

// check if the crds directory exists ...
for _, dir := range []string{"crds", "templates"} {
dirPath := tmpDir + "/" + dir
if _, err := os.Stat(dirPath); os.IsNotExist(err) {
t.Fatalf("%s directory %s does not exist", dir, dirPath)
}
files, err := os.ReadDir(dirPath)
if err != nil {
t.Fatal(err)
}
if len(files) == 0 {
t.Fatalf("%s directory is empty", dirPath)
}
}

// check if the Chart.yaml file exists
chartPath := tmpDir + "/Chart.yaml"
chartFileContent, err := os.ReadFile(chartPath)
if err != nil {
t.Fatalf("Chart.yaml file %s does not exist", chartPath)
}
testutil.CompareWithFixture(t, chartFileContent, testutil.WithSuffix("_chart"))

// check if the values.yaml file exists
valuesPath := tmpDir + "/values.yaml"
valuesFileContent, err := os.ReadFile(valuesPath)
if err != nil {
t.Fatalf("values.yaml file %s does not exist", valuesPath)
}
testutil.CompareWithFixture(t, valuesFileContent, testutil.WithSuffix("_values"))

}
Loading

0 comments on commit a95fc46

Please sign in to comment.