diff --git a/README.md b/README.md index 531a8425..14723e38 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,12 @@ This can be useful in several ways: `./idpbuilder create --buildName localdev` +You can also define the kubernetes version to image and which corresponds to the kind pre-built [image](https://github.com/kubernetes-sigs/kind/releases). +`./idpbuilder create --kubeVersion v1.27.3` + +If it is needed to expose some extra Ports between the docker container and the kubernetes host, they can be declared as such +`./idpbuilder create --extraPorts 22:32222` + ### Use Kubernetes: `kubectl get pods` diff --git a/go.mod b/go.mod index caaa742a..507b2feb 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/docker/go-connections v0.4.0 github.com/google/go-cmp v0.5.9 github.com/spf13/cobra v1.7.0 + github.com/stretchr/testify v1.8.4 k8s.io/api v0.26.2 k8s.io/apiextensions-apiserver v0.24.2 k8s.io/apimachinery v0.26.2 @@ -103,6 +104,7 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.16.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect diff --git a/pkg/apps/srv/nginx-ingress/ingress-nginx.yaml b/pkg/apps/srv/nginx-ingress/ingress-nginx.yaml index 91f558d1..cc3fb389 100644 --- a/pkg/apps/srv/nginx-ingress/ingress-nginx.yaml +++ b/pkg/apps/srv/nginx-ingress/ingress-nginx.yaml @@ -501,17 +501,9 @@ spec: readOnly: true dnsPolicy: ClusterFirst nodeSelector: - ingress-ready: "true" kubernetes.io/os: linux serviceAccountName: ingress-nginx terminationGracePeriodSeconds: 0 - tolerations: - - effect: NoSchedule - key: node-role.kubernetes.io/master - operator: Equal - - effect: NoSchedule - key: node-role.kubernetes.io/control-plane - operator: Equal volumes: - name: webhook-cert secret: diff --git a/pkg/build/build.go b/pkg/build/build.go index 5d2be830..dce68c9b 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -21,24 +21,28 @@ var ( ) type Build struct { - name string - kubeConfigPath string - scheme *runtime.Scheme - CancelFunc context.CancelFunc + name string + kubeConfigPath string + kubeVersion string + extraPortsMapping string + scheme *runtime.Scheme + CancelFunc context.CancelFunc } -func NewBuild(name, kubeConfigPath string, scheme *runtime.Scheme, ctxCancel context.CancelFunc) *Build { +func NewBuild(name, kubeVersion, kubeConfigPath, extraPortsMapping string, scheme *runtime.Scheme, ctxCancel context.CancelFunc) *Build { return &Build{ - name: name, - kubeConfigPath: kubeConfigPath, - scheme: scheme, - CancelFunc: ctxCancel, + name: name, + kubeConfigPath: kubeConfigPath, + kubeVersion: kubeVersion, + extraPortsMapping: extraPortsMapping, + scheme: scheme, + CancelFunc: ctxCancel, } } func (b *Build) ReconcileKindCluster(ctx context.Context, recreateCluster bool) error { // Initialize Kind Cluster - cluster, err := kind.NewCluster(b.name, b.kubeConfigPath) + cluster, err := kind.NewCluster(b.name, b.kubeVersion, b.kubeConfigPath, b.extraPortsMapping) if err != nil { setupLog.Error(err, "Error Creating kind cluster") return err diff --git a/pkg/cmd/create/root.go b/pkg/cmd/create/root.go index 2892a43a..6b19fb1c 100644 --- a/pkg/cmd/create/root.go +++ b/pkg/cmd/create/root.go @@ -18,20 +18,24 @@ import ( var ( // Flags - recreateCluster bool - buildName string + recreateCluster bool + buildName string + kubeVersion string + extraPortsMapping string ) var CreateCmd = &cobra.Command{ Use: "create", - Short: "(Re)Create a UCP cluster", + Short: "(Re)Create an IDP cluster", Long: ``, RunE: create, } func init() { CreateCmd.PersistentFlags().BoolVar(&recreateCluster, "recreate", false, "Delete cluster first if it already exists.") - CreateCmd.PersistentFlags().StringVar(&buildName, "buildName", "localdev", "Name for build (Prefix for kind cluster name, pod names, etc)") + CreateCmd.PersistentFlags().StringVar(&buildName, "buildName", "localdev", "Name for build (Prefix for kind cluster name, pod names, etc).") + CreateCmd.PersistentFlags().StringVar(&kubeVersion, "kubeVersion", "v1.26.333", "Version of the kind kubernetes cluster to create.") + CreateCmd.PersistentFlags().StringVar(&extraPortsMapping, "extraPorts", "", "List of extra ports to expose on the docker container and kubernetes cluster as nodePort (e.g. \"22:32222,9090:39090,etc\").") zapfs := flag.NewFlagSet("zap", flag.ExitOnError) opts := zap.Options{ @@ -54,7 +58,7 @@ func create(cmd *cobra.Command, args []string) error { os.Exit(1) } - b := build.NewBuild(buildName, kubeConfigPath, k8s.GetScheme(), ctxCancel) + b := build.NewBuild(buildName, kubeVersion, kubeConfigPath, extraPortsMapping, k8s.GetScheme(), ctxCancel) if err := b.Run(ctx, recreateCluster); err != nil { return err diff --git a/pkg/kind/cluster.go b/pkg/kind/cluster.go index 203b1271..89038249 100644 --- a/pkg/kind/cluster.go +++ b/pkg/kind/cluster.go @@ -6,26 +6,54 @@ import ( "embed" "fmt" "io/fs" + "strings" "text/template" "sigs.k8s.io/kind/pkg/cluster" ) type Cluster struct { - provider *cluster.Provider - name string - kubeConfigPath string + provider *cluster.Provider + name string + kubeVersion string + kubeConfigPath string + extraPortsMapping string +} + +type PortMapping struct { + HostPort string + ContainerPort string } //go:embed resources/kind.yaml var configFS embed.FS +func SplitFunc(input, sep string) []string { + return strings.Split(input, sep) +} func (c *Cluster) getConfig() ([]byte, error) { rawConfigTempl, err := fs.ReadFile(configFS, "resources/kind.yaml") if err != nil { return []byte{}, err } + var portMappingPairs []PortMapping + if len(c.extraPortsMapping) > 0 { + // Split pairs of ports "11=1111","22=2222",etc + pairs := strings.Split(c.extraPortsMapping, ",") + // Create a slice to store PortMapping pairs. + portMappingPairs = make([]PortMapping, len(pairs)) + // Parse each pair into PortPair objects. + for i, pair := range pairs { + parts := strings.Split(pair, ":") + if len(parts) == 2 { + portMappingPairs[i] = PortMapping{parts[0], parts[1]} + } + } + } else { + portMappingPairs = nil + } + template, err := template.New("kind.yaml").Parse(string(rawConfigTempl)) if err != nil { return []byte{}, err @@ -36,23 +64,29 @@ func (c *Cluster) getConfig() ([]byte, error) { RegistryHostname string ExposedRegistryPort uint16 InternalRegistryPort uint16 + KubernetesVersion string + ExtraPortsMapping []PortMapping }{ RegistryHostname: c.getRegistryContainerName(), ExposedRegistryPort: ExposedRegistryPort, InternalRegistryPort: InternalRegistryPort, + KubernetesVersion: c.kubeVersion, + ExtraPortsMapping: portMappingPairs, }); err != nil { return []byte{}, err } return retBuff.Bytes(), nil } -func NewCluster(name string, kubeConfigPath string) (*Cluster, error) { +func NewCluster(name, kubeVersion, kubeConfigPath, extraPortsMapping string) (*Cluster, error) { provider := cluster.NewProvider(cluster.ProviderWithDocker()) return &Cluster{ - provider: provider, - name: name, - kubeConfigPath: kubeConfigPath, + provider: provider, + name: name, + kubeVersion: kubeVersion, + kubeConfigPath: kubeConfigPath, + extraPortsMapping: extraPortsMapping, }, nil } diff --git a/pkg/kind/cluster_test.go b/pkg/kind/cluster_test.go index 86b39aeb..5df7cb51 100644 --- a/pkg/kind/cluster_test.go +++ b/pkg/kind/cluster_test.go @@ -1,13 +1,12 @@ package kind import ( + "github.com/stretchr/testify/assert" "testing" - - "github.com/google/go-cmp/cmp" ) func TestGetConfig(t *testing.T) { - cluster, err := NewCluster("testcase", "") + cluster, err := NewCluster("testcase", "v1.26.3", "", "") if err != nil { t.Fatalf("Initializing cluster resource: %v", err) } @@ -17,43 +16,72 @@ func TestGetConfig(t *testing.T) { t.Errorf("Error getting kind config: %v", err) } - expectConfig := `# two node (one workers) cluster config - # Kind kubernetes release images https://github.com/kubernetes-sigs/kind/releases - kind: Cluster - apiVersion: kind.x-k8s.io/v1alpha4 - containerdConfigPatches: - - |- - [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5000"] - endpoint = ["http://idpbuilder-registry:5000"] - nodes: - - role: control-plane - image: "kindest/node:v1.25.3@sha256:f52781bc0d7a19fb6c405c2af83abfeb311f130707a0e219175677e366cc45d1" - kubeadmConfigPatches: - - | - kind: InitConfiguration - nodeRegistration: - kubeletExtraArgs: - system-reserved: memory=4Gi - node-labels: "ingress-ready=true" - extraPortMappings: - - containerPort: 80 - hostPort: 8880 - protocol: TCP - - containerPort: 443 - hostPort: 8443 - protocol: TCP - - - - role: worker - image: "kindest/node:v1.25.3@sha256:f52781bc0d7a19fb6c405c2af83abfeb311f130707a0e219175677e366cc45d1" - kubeadmConfigPatches: - - | - kind: JoinConfiguration - nodeRegistration: - kubeletExtraArgs: - system-reserved: memory=4Gi` - - t.Errorf("Got config: %s", string(cfg)) - if diff := cmp.Diff(expectConfig, string(cfg)); diff != "" { - t.Errorf("Expected config mismatch (-want +got):\n%s", diff) + expectConfig := `# Kind kubernetes release images https://github.com/kubernetes-sigs/kind/releases +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +containerdConfigPatches: +- |- + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5001"] + endpoint = ["http://idpbuilder-testcase-registry:5000"] +nodes: +- role: control-plane + image: "kindest/node:v1.26.3" + kubeadmConfigPatches: + - | + kind: InitConfiguration + nodeRegistration: + kubeletExtraArgs: + system-reserved: memory=4Gi + node-labels: "ingress-ready=true" + extraPortMappings: + - containerPort: 80 + hostPort: 8880 + protocol: TCP + - containerPort: 443 + hostPort: 8443 + protocol: TCP + ` + assert.Equal(t, expectConfig, string(cfg)) +} + +func TestExtraPortMappings(t *testing.T) { + cluster, err := NewCluster("testcase", "v1.26.3", "", "22:32222") + if err != nil { + t.Fatalf("Initializing cluster resource: %v", err) + } + + cfg, err := cluster.getConfig() + if err != nil { + t.Errorf("Error getting kind config: %v", err) } + + expectConfig := `# Kind kubernetes release images https://github.com/kubernetes-sigs/kind/releases +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +containerdConfigPatches: +- |- + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5001"] + endpoint = ["http://idpbuilder-testcase-registry:5000"] +nodes: +- role: control-plane + image: "kindest/node:v1.26.3" + kubeadmConfigPatches: + - | + kind: InitConfiguration + nodeRegistration: + kubeletExtraArgs: + system-reserved: memory=4Gi + node-labels: "ingress-ready=true" + extraPortMappings: + - containerPort: 80 + hostPort: 8880 + protocol: TCP + - containerPort: 443 + hostPort: 8443 + protocol: TCP + - containerPort: 32222 + hostPort: 22 + protocol: TCP` + + assert.Equal(t, expectConfig, string(cfg)) } diff --git a/pkg/kind/registry_test.go b/pkg/kind/registry_test.go index ffedc851..4beb9146 100644 --- a/pkg/kind/registry_test.go +++ b/pkg/kind/registry_test.go @@ -20,7 +20,7 @@ func TestReconcileRegistry(t *testing.T) { defer dockerCli.Close() // Create cluster - cluster, err := NewCluster("testcase", "") + cluster, err := NewCluster("testcase", "v1.26.3", "", "") if err != nil { t.Fatalf("Initializing cluster resource: %v", err) } diff --git a/pkg/kind/resources/kind.yaml b/pkg/kind/resources/kind.yaml index a65f4dc1..944b57f4 100644 --- a/pkg/kind/resources/kind.yaml +++ b/pkg/kind/resources/kind.yaml @@ -1,4 +1,3 @@ -# two node (one workers) cluster config # Kind kubernetes release images https://github.com/kubernetes-sigs/kind/releases kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 @@ -8,7 +7,7 @@ containerdConfigPatches: endpoint = ["http://{{ .RegistryHostname }}:{{ .InternalRegistryPort }}"] nodes: - role: control-plane - image: "kindest/node:v1.26.3" + image: "kindest/node:{{ .KubernetesVersion }}" kubeadmConfigPatches: - | kind: InitConfiguration @@ -23,12 +22,6 @@ nodes: - containerPort: 443 hostPort: 8443 protocol: TCP - - -- role: worker - image: "kindest/node:v1.26.3" - kubeadmConfigPatches: - - | - kind: JoinConfiguration - nodeRegistration: - kubeletExtraArgs: - system-reserved: memory=4Gi \ No newline at end of file + {{ range .ExtraPortsMapping }}- containerPort: {{ .ContainerPort }} + hostPort: {{ .HostPort }} + protocol: TCP{{ end }} \ No newline at end of file