add createNamespace option to chart render (#603)

Signed-off-by: Zhiwei Yin <zyin@redhat.com>
This commit is contained in:
Zhiwei Yin
2024-08-28 07:17:18 +00:00
committed by GitHub
parent 9cedd4605a
commit 0deb09b92d
4 changed files with 84 additions and 9 deletions
+2
View File
@@ -17,6 +17,8 @@ var ChartFiles embed.FS
const ChartName = "cluster-manager"
type ChartConfig struct {
// CreateNamespace is used in the render function to append the release ns in the objects.
CreateNamespace bool `json:"createNamespace,omitempty"`
// ReplicaCount is the replicas for the clusterManager operator deployment.
ReplicaCount int `json:"replicaCount,omitempty"`
// Images is the configurations for all images used in operator deployment and clusterManager CR.
+2
View File
@@ -17,6 +17,8 @@ var ChartFiles embed.FS
const ChartName = "klusterlet"
type ChartConfig struct {
// CreateNamespace is used in the render function to append the release ns in the objects.
CreateNamespace bool `json:"createNamespace,omitempty"`
// ReplicaCount is the replicas for the klusterlet operator deployment.
ReplicaCount int `json:"replicaCount,omitempty"`
// Images is the configurations for all images used in operator deployment and klusterlet CR.
+47 -4
View File
@@ -11,10 +11,12 @@ import (
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/engine"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/klog/v2"
"sigs.k8s.io/yaml"
clustermanagerchart "open-cluster-management.io/ocm/deploy/cluster-manager/chart"
klusterletchart "open-cluster-management.io/ocm/deploy/klusterlet/chart"
@@ -33,8 +35,24 @@ func NewDefaultKlusterletChartConfig() *klusterletchart.ChartConfig {
}
}
func RenderChart[T *clustermanagerchart.ChartConfig | *klusterletchart.ChartConfig](config T,
namespace string, chartName string, fs embed.FS) ([][]byte, error) {
func RenderClusterManagerChart(config *clustermanagerchart.ChartConfig, namespace string) ([][]byte, error) {
if namespace == "" {
return nil, fmt.Errorf("cluster manager chart namespace is required")
}
return renderChart(config, namespace, config.CreateNamespace,
clustermanagerchart.ChartName, clustermanagerchart.ChartFiles)
}
func RenderKlusterletChart(config *klusterletchart.ChartConfig, namespace string) ([][]byte, error) {
if namespace == "" {
return nil, fmt.Errorf("klusterlet chart namespace is required")
}
return renderChart(config, namespace, config.CreateNamespace,
klusterletchart.ChartName, klusterletchart.ChartFiles)
}
func renderChart[T *clustermanagerchart.ChartConfig | *klusterletchart.ChartConfig](config T,
namespace string, createNamespace bool, chartName string, fs embed.FS) ([][]byte, error) {
// chartName is the prefix of chart path here
operatorChart, err := LoadChart(fs, chartName)
if err != nil {
@@ -63,7 +81,18 @@ func RenderChart[T *clustermanagerchart.ChartConfig | *klusterletchart.ChartConf
return nil, fmt.Errorf("error rendering cluster manager chart: %v", err)
}
return rawObjects, nil
// make sure the ns object is at the top of slice when createNamespace is true.
rstObjects := [][]byte{}
if createNamespace {
nsObj, err := newNamespaceRawObject(namespace)
if err != nil {
return nil, err
}
rstObjects = [][]byte{nsObj}
}
rstObjects = append(rstObjects, rawObjects...)
return rstObjects, nil
}
func getFiles(manifestFS embed.FS) ([]string, error) {
@@ -172,3 +201,17 @@ func renderManifests(chart *chart.Chart, values chartutil.Values) ([][]byte, err
}
return rawObjects, nil
}
func newNamespaceRawObject(namespace string) ([]byte, error) {
ns := &corev1.Namespace{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Namespace",
},
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}
return yaml.Marshal(ns)
}
+33 -5
View File
@@ -84,6 +84,17 @@ func TestClusterManagerConfig(t *testing.T) {
},
expectedObjCnt: 7,
},
{
name: "create namespace",
namespace: "multicluster-engine",
chartConfig: func() *clustermanagerchart.ChartConfig {
config := NewDefaultClusterManagerChartConfig()
config.CreateBootstrapToken = true
config.CreateNamespace = true
return config
},
expectedObjCnt: 10,
},
}
for _, c := range cases {
@@ -99,7 +110,7 @@ func TestClusterManagerConfig(t *testing.T) {
version = config.Images.Tag
}
objects, err := RenderChart(config, c.namespace, clustermanagerchart.ChartName, clustermanagerchart.ChartFiles)
objects, err := RenderClusterManagerChart(config, c.namespace)
if err != nil {
t.Errorf("error rendering chart: %v", err)
}
@@ -115,6 +126,10 @@ func TestClusterManagerConfig(t *testing.T) {
}
outputObjs = append(outputObjs, obj)
switch object := obj.(type) {
case *corev1.Namespace:
if object.Name != c.namespace {
t.Errorf("expected namespace %s, got %s", c.namespace, object.Name)
}
case *appsv1.Deployment:
if object.Namespace != c.namespace {
t.Errorf("expected namespace is %s, but got %s", c.namespace, object.Namespace)
@@ -135,7 +150,6 @@ func TestClusterManagerConfig(t *testing.T) {
t.Errorf("failed to render images")
}
}
}
// output is for debug
@@ -147,7 +161,6 @@ func TestClusterManagerConfig(t *testing.T) {
}
func TestKlusterletConfig(t *testing.T) {
cases := []struct {
name string
namespace string
@@ -213,6 +226,18 @@ func TestKlusterletConfig(t *testing.T) {
},
expectedObjCnt: 2,
},
{
name: "create namespace",
namespace: "open-cluster-management",
chartConfig: func() *klusterletchart.ChartConfig {
config := NewDefaultKlusterletChartConfig()
config.Klusterlet.ClusterName = "testCluster"
config.Klusterlet.Mode = operatorv1.InstallModeSingleton
config.CreateNamespace = true
return config
},
expectedObjCnt: 7,
},
}
for _, c := range cases {
@@ -227,7 +252,7 @@ func TestKlusterletConfig(t *testing.T) {
version = config.Images.Tag
}
objects, err := RenderChart(config, c.namespace, klusterletchart.ChartName, klusterletchart.ChartFiles)
objects, err := RenderKlusterletChart(config, c.namespace)
if err != nil {
t.Errorf("error rendering chart: %v", err)
}
@@ -243,6 +268,10 @@ func TestKlusterletConfig(t *testing.T) {
}
outputObjs = append(outputObjs, obj)
switch object := obj.(type) {
case *corev1.Namespace:
if object.Name != c.namespace {
t.Errorf("expected namespace %s, got %s", c.namespace, object.Name)
}
case *appsv1.Deployment:
if object.Namespace != c.namespace {
t.Errorf("expected namespace is %s, but got %s", c.namespace, object.Namespace)
@@ -306,7 +335,6 @@ func TestKlusterletConfig(t *testing.T) {
fmt.Sprintf("open-cluster-management-%s", object.Spec.ClusterName), object.Spec.Namespace)
}
}
}
}