From 723686dad07a65f5fea5018d19499765db0510bf Mon Sep 17 00:00:00 2001 From: Paolo Dettori Date: Wed, 1 May 2024 22:04:59 -0500 Subject: [PATCH 1/2] start adding containerHost parameter Signed-off-by: Paolo Dettori --- Makefile | 2 +- api/v1alpha1/zz_generated.deepcopy.go | 1 - chart/values.yaml | 3 +- cmd/cmupdate/main.go | 21 +++++++++----- cmd/kflex/main.go | 2 ++ ...y.kflex.kubestellar.org_controlplanes.yaml | 28 ++++++++++++------- ...kflex.kubestellar.org_postcreatehooks.yaml | 28 ++++++++++++------- config/manager/config.yaml | 3 +- config/rbac/role.yaml | 1 - pkg/reconcilers/ocm/reconciler.go | 2 +- pkg/reconcilers/shared/job.go | 22 +++++++++------ pkg/reconcilers/shared/postcreate_hook.go | 2 +- pkg/reconcilers/shared/reconciler.go | 16 ++++++----- pkg/reconcilers/vcluster/reconciler.go | 2 +- 14 files changed, 83 insertions(+), 50 deletions(-) diff --git a/Makefile b/Makefile index 0dd061e..e248382 100644 --- a/Makefile +++ b/Makefile @@ -209,7 +209,7 @@ ENVTEST ?= $(LOCALBIN)/setup-envtest ## Tool Versions KUSTOMIZE_VERSION ?= v5.1.0 -CONTROLLER_TOOLS_VERSION ?= v0.11.3 +CONTROLLER_TOOLS_VERSION ?= v0.15.0 KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" .PHONY: kustomize diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 11159f8..fddaad0 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright 2023 The KubeStellar Authors. diff --git a/chart/values.yaml b/chart/values.yaml index 64f48cc..f5f6b07 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -5,4 +5,5 @@ domain: localtest.me externalPort: "9443" isOpenShift: "false" -installPostgreSQL: true \ No newline at end of file +installPostgreSQL: true +hostContainer: kubeflex-control-plane \ No newline at end of file diff --git a/cmd/cmupdate/main.go b/cmd/cmupdate/main.go index 1177518..2d6a452 100644 --- a/cmd/cmupdate/main.go +++ b/cmd/cmupdate/main.go @@ -40,13 +40,13 @@ import ( ) const ( - configMapName = "cluster-info" - keyToUpdate = "kubeconfig" - kubePublicNamespace = "kube-public" - clusterName = "" - baseURL = "https://kubeflex-control-plane" - BootstrapConfigMap = "cluster-info" - GeneratedCLusterInfoKey = "kubestellar.io/generated" + configMapName = "cluster-info" + keyToUpdate = "kubeconfig" + kubePublicNamespace = "kube-public" + clusterName = "" + defaultHostContainerName = "kubeflex-control-plane" + BootstrapConfigMap = "cluster-info" + GeneratedCLusterInfoKey = "kubestellar.io/generated" ) // The CM update updates the cluster-info config map in a OCM control plane @@ -59,6 +59,13 @@ func main() { } else { log.Printf("Current Namespace: %s", namespace) } + hostContainer := os.Getenv("HOST_CONTAINER") + if hostContainer == "" { + hostContainer = defaultHostContainerName + } + log.Printf("Using hostContainer: %s", hostContainer) + baseURL := fmt.Sprintf("https://%s", hostContainer) + externalURL := os.Getenv("EXTERNAL_URL") if externalURL != "" { log.Printf("Using external URL: %s", externalURL) diff --git a/cmd/kflex/main.go b/cmd/kflex/main.go index ddfddcb..a6ff828 100644 --- a/cmd/kflex/main.go +++ b/cmd/kflex/main.go @@ -50,6 +50,7 @@ var domain string var externalPort int var chattyStatus bool var hookVars []string +var hostContainer string // defaults const BKTypeDefault = string(tenancyv1alpha1.BackendDBTypeShared) @@ -186,6 +187,7 @@ func init() { initCmd.Flags().IntVarP(&verbosity, "verbosity", "v", 0, "log level") // TODO - figure out how to inject verbosity initCmd.Flags().BoolVarP(&createkind, "create-kind", "c", false, "Create and configure a kind cluster for installing Kubeflex") initCmd.Flags().StringVarP(&domain, "domain", "d", "localtest.me", "domain for FQDN") + initCmd.Flags().StringVarP(&hostContainer, "hostContainerName", "n", "kubeflex-control-plane", "Name of the hosting cluster container (kind or k3d only)") initCmd.Flags().IntVarP(&externalPort, "externalPort", "p", 9443, "external port used by ingress") initCmd.Flags().BoolVarP(&chattyStatus, "chatty-status", "s", true, "chatty status indicator") diff --git a/config/crd/bases/tenancy.kflex.kubestellar.org_controlplanes.yaml b/config/crd/bases/tenancy.kflex.kubestellar.org_controlplanes.yaml index 8b6efb9..a7b30a4 100644 --- a/config/crd/bases/tenancy.kflex.kubestellar.org_controlplanes.yaml +++ b/config/crd/bases/tenancy.kflex.kubestellar.org_controlplanes.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.3 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.15.0 name: controlplanes.tenancy.kflex.kubestellar.org spec: group: tenancy.kflex.kubestellar.org @@ -37,14 +36,19 @@ spec: description: ControlPlane is the Schema for the controlplanes API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -119,10 +123,14 @@ spec: description: Required type: string name: - description: '`name` is the name of the secret. Required' + description: |- + `name` is the name of the secret. + Required type: string namespace: - description: '`namespace` is the namespace of the secret. Required' + description: |- + `namespace` is the namespace of the secret. + Required type: string required: - inClusterKey diff --git a/config/crd/bases/tenancy.kflex.kubestellar.org_postcreatehooks.yaml b/config/crd/bases/tenancy.kflex.kubestellar.org_postcreatehooks.yaml index 5538fa6..75cebae 100644 --- a/config/crd/bases/tenancy.kflex.kubestellar.org_postcreatehooks.yaml +++ b/config/crd/bases/tenancy.kflex.kubestellar.org_postcreatehooks.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.3 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.15.0 name: postcreatehooks.tenancy.kflex.kubestellar.org spec: group: tenancy.kflex.kubestellar.org @@ -37,14 +36,19 @@ spec: description: PostCreateHook is the Schema for the controlplanes API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -104,10 +108,14 @@ spec: description: Required type: string name: - description: '`name` is the name of the secret. Required' + description: |- + `name` is the name of the secret. + Required type: string namespace: - description: '`namespace` is the namespace of the secret. Required' + description: |- + `namespace` is the namespace of the secret. + Required type: string required: - inClusterKey diff --git a/config/manager/config.yaml b/config/manager/config.yaml index 214f27d..1e5bede 100644 --- a/config/manager/config.yaml +++ b/config/manager/config.yaml @@ -6,4 +6,5 @@ metadata: data: domain: "{{ .Values.domain }}" externalPort: "{{ .Values.externalPort }}" - isOpenShift: "{{ .Values.isOpenShift }}" \ No newline at end of file + isOpenShift: "{{ .Values.isOpenShift }}" + hostContainer: "{{ .Values.hostContainer }}" \ No newline at end of file diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 5814f9a..69377ee 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -2,7 +2,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: manager-role rules: - nonResourceURLs: diff --git a/pkg/reconcilers/ocm/reconciler.go b/pkg/reconcilers/ocm/reconciler.go index a80281b..6981e3d 100644 --- a/pkg/reconcilers/ocm/reconciler.go +++ b/pkg/reconcilers/ocm/reconciler.go @@ -99,7 +99,7 @@ func (r *OCMReconciler) Reconcile(ctx context.Context, hcp *tenancyv1alpha1.Cont return r.UpdateStatusForSyncingError(hcp, err) } - if err := r.ReconcileUpdateClusterInfoJob(ctx, hcp, cfg.ExternalURL, r.Version); err != nil { + if err := r.ReconcileUpdateClusterInfoJob(ctx, hcp, cfg, r.Version); err != nil { return r.UpdateStatusForSyncingError(hcp, err) } diff --git a/pkg/reconcilers/shared/job.go b/pkg/reconcilers/shared/job.go index 9450873..1ce6aa4 100644 --- a/pkg/reconcilers/shared/job.go +++ b/pkg/reconcilers/shared/job.go @@ -34,11 +34,12 @@ import ( ) const ( - jobName = "update-cluster-info" - baseImage = "ghcr.io/kubestellar/kubeflex/cmupdate" + jobName = "update-cluster-info" + //baseImage = "ghcr.io/kubestellar/kubeflex/cmupdate" + baseImage = "ko.local/cmupdate" ) -func (r *BaseReconciler) ReconcileUpdateClusterInfoJob(ctx context.Context, hcp *tenancyv1alpha1.ControlPlane, externalURL, version string) error { +func (r *BaseReconciler) ReconcileUpdateClusterInfoJob(ctx context.Context, hcp *tenancyv1alpha1.ControlPlane, cfg *SharedConfig, version string) error { _ = clog.FromContext(ctx) namespace := util.GenerateNamespaceFromControlPlaneName(hcp.Name) @@ -56,7 +57,7 @@ func (r *BaseReconciler) ReconcileUpdateClusterInfoJob(ctx context.Context, hcp err := r.Client.Get(context.TODO(), client.ObjectKeyFromObject(job), job, &client.GetOptions{}) if err != nil { if apierrors.IsNotFound(err) { - job := generateClusterInfoJob(jobName, namespace, externalURL, kubeconfigSecret, kubeconfigSecretKey, r.Version) + job := generateClusterInfoJob(jobName, namespace, kubeconfigSecret, kubeconfigSecretKey, r.Version, cfg) if err := controllerutil.SetControllerReference(hcp, job, r.Scheme); err != nil { return nil } @@ -70,7 +71,7 @@ func (r *BaseReconciler) ReconcileUpdateClusterInfoJob(ctx context.Context, hcp return nil } -func generateClusterInfoJob(name, namespace, externalURL, kubeconfigSecret, kubeconfigSecretKey, version string) *batchv1.Job { +func generateClusterInfoJob(name, namespace, kubeconfigSecret, kubeconfigSecretKey, version string, cfg *SharedConfig) *batchv1.Job { job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -102,6 +103,10 @@ func generateClusterInfoJob(name, namespace, externalURL, kubeconfigSecret, kube Name: "KUBECONFIG_SECRET_KEY", Value: kubeconfigSecretKey, }, + { + Name: "HOST_CONTAINER", + Value: cfg.HostContainer, + }, }, }, }, @@ -110,10 +115,10 @@ func generateClusterInfoJob(name, namespace, externalURL, kubeconfigSecret, kube }, }, } - if externalURL != "" { + if cfg.ExternalURL != "" { env := corev1.EnvVar{ Name: "EXTERNAL_URL", - Value: externalURL, + Value: cfg.ExternalURL, } job.Spec.Template.Spec.Containers[0].Env = append(job.Spec.Template.Spec.Containers[0].Env, env) } @@ -121,7 +126,8 @@ func generateClusterInfoJob(name, namespace, externalURL, kubeconfigSecret, kube } func buildImageRef(version string) string { - tag := "latest" + //tag := "latest" + tag := "v0.5.1-12-g4542b38" if version != "" { tag = util.ParseVersionNumber(version) } diff --git a/pkg/reconcilers/shared/postcreate_hook.go b/pkg/reconcilers/shared/postcreate_hook.go index 943c46d..743d833 100644 --- a/pkg/reconcilers/shared/postcreate_hook.go +++ b/pkg/reconcilers/shared/postcreate_hook.go @@ -170,7 +170,7 @@ func setTrackingLabelsAndAnnotations(obj *unstructured.Unstructured, cpName stri func propagateLabels(hook *v1alpha1.PostCreateHook, hcp *v1alpha1.ControlPlane, c client.Client) error { hookLabels := hook.GetLabels() - if hookLabels == nil || hookLabels != nil && len(hookLabels) == 0 { + if len(hookLabels) == 0 { return nil } diff --git a/pkg/reconcilers/shared/reconciler.go b/pkg/reconcilers/shared/reconciler.go index b7c9262..387ba8c 100644 --- a/pkg/reconcilers/shared/reconciler.go +++ b/pkg/reconcilers/shared/reconciler.go @@ -49,10 +49,11 @@ type BaseReconciler struct { } type SharedConfig struct { - ExternalPort int - Domain string - IsOpenShift bool - ExternalURL string + ExternalPort int + Domain string + HostContainer string + IsOpenShift bool + ExternalURL string } func (r *BaseReconciler) UpdateStatusForSyncingError(hcp *tenancyv1alpha1.ControlPlane, e error) (ctrl.Result, error) { @@ -94,9 +95,10 @@ func (r *BaseReconciler) GetConfig(ctx context.Context) (*SharedConfig, error) { return nil, err } return &SharedConfig{ - Domain: cmap.Data["domain"], - ExternalPort: port, - IsOpenShift: isOpenShift, + Domain: cmap.Data["domain"], + HostContainer: cmap.Data["hostContainer"], + ExternalPort: port, + IsOpenShift: isOpenShift, }, nil } diff --git a/pkg/reconcilers/vcluster/reconciler.go b/pkg/reconcilers/vcluster/reconciler.go index d65282f..c7ba298 100644 --- a/pkg/reconcilers/vcluster/reconciler.go +++ b/pkg/reconcilers/vcluster/reconciler.go @@ -109,7 +109,7 @@ func (r *VClusterReconciler) Reconcile(ctx context.Context, hcp *tenancyv1alpha1 return r.UpdateStatusForSyncingError(hcp, err) } - if err := r.ReconcileUpdateClusterInfoJob(ctx, hcp, cfg.ExternalURL, r.Version); err != nil { + if err := r.ReconcileUpdateClusterInfoJob(ctx, hcp, cfg, r.Version); err != nil { return r.UpdateStatusForSyncingError(hcp, err) } From 158a56f3d3d07595d32e0c1e8fd240e1cf18ff42 Mon Sep 17 00:00:00 2001 From: Paolo Dettori Date: Thu, 2 May 2024 10:46:51 -0500 Subject: [PATCH 2/2] add docs for new hostContainer name flag Signed-off-by: Paolo Dettori --- chart/crds/crds.yaml | 548 +++++++++++++++-------------- chart/templates/builtin-hooks.yaml | 2 +- chart/templates/operator.yaml | 3 +- cmd/kflex/init/init.go | 7 +- cmd/kflex/main.go | 2 +- docs/users.md | 25 +- pkg/reconcilers/shared/job.go | 8 +- 7 files changed, 316 insertions(+), 279 deletions(-) diff --git a/chart/crds/crds.yaml b/chart/crds/crds.yaml index debdef1..31dfefc 100644 --- a/chart/crds/crds.yaml +++ b/chart/crds/crds.yaml @@ -1,266 +1,282 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.11.3 - creationTimestamp: null - name: controlplanes.tenancy.kflex.kubestellar.org -spec: - group: tenancy.kflex.kubestellar.org - names: - kind: ControlPlane - listKind: ControlPlaneList - plural: controlplanes - shortNames: - - cp - - cps - singular: controlplane - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=='Synced')].status - name: SYNCED - type: string - - jsonPath: .status.conditions[?(@.type=='Ready')].status - name: READY - type: string - - jsonPath: .spec.type - name: TYPE - type: string - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: ControlPlane is the Schema for the controlplanes API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: ControlPlaneSpec defines the desired state of ControlPlane - properties: - backend: - enum: - - shared - - dedicated - type: string - postCreateHook: - type: string - postCreateHookVars: - additionalProperties: - type: string - type: object - type: - enum: - - k8s - - ocm - - vcluster - - host - type: string - type: object - status: - description: ControlPlaneStatus defines the observed state of ControlPlane - properties: - conditions: - items: - description: ControlPlaneCondition describes the state of a control - plane at a certain point. - properties: - lastTransitionTime: - format: date-time - type: string - lastUpdateTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - lastTransitionTime - - lastUpdateTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - format: int64 - type: integer - postCreateHooks: - additionalProperties: - type: boolean - type: object - secretRef: - description: SecretRef contains a referece to the secret containing - the Kubeconfig for the control plane - properties: - inClusterKey: - description: Required - type: string - key: - description: Required - type: string - name: - description: '`name` is the name of the secret. Required' - type: string - namespace: - description: '`namespace` is the namespace of the secret. Required' - type: string - required: - - inClusterKey - - key - - name - - namespace - type: object - required: - - conditions - - observedGeneration - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.11.3 - creationTimestamp: null - name: postcreatehooks.tenancy.kflex.kubestellar.org -spec: - group: tenancy.kflex.kubestellar.org - names: - kind: PostCreateHook - listKind: PostCreateHookList - plural: postcreatehooks - shortNames: - - pch - - pchs - singular: postcreatehook - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=='Synced')].status - name: SYNCED - type: string - - jsonPath: .status.conditions[?(@.type=='Ready')].status - name: READY - type: string - - jsonPath: .spec.type - name: TYPE - type: string - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: PostCreateHook is the Schema for the controlplanes API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: PostCreateHookSpec defines the desired state of PostCreateHook - properties: - templates: - items: - description: Manifest represents a resource to be deployed - type: object - x-kubernetes-embedded-resource: true - x-kubernetes-preserve-unknown-fields: true - type: array - type: object - status: - description: PostCreateHookStatus defines the observed state of PostCreateHook - properties: - conditions: - items: - description: ControlPlaneCondition describes the state of a control - plane at a certain point. - properties: - lastTransitionTime: - format: date-time - type: string - lastUpdateTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - lastTransitionTime - - lastUpdateTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - format: int64 - type: integer - secretRef: - description: SecretRef contains a referece to the secret containing - the Kubeconfig for the control plane - properties: - inClusterKey: - description: Required - type: string - key: - description: Required - type: string - name: - description: '`name` is the name of the secret. Required' - type: string - namespace: - description: '`namespace` is the namespace of the secret. Required' - type: string - required: - - inClusterKey - - key - - name - - namespace - type: object - required: - - conditions - - observedGeneration - type: object - type: object - served: true - storage: true - subresources: - status: {} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: controlplanes.tenancy.kflex.kubestellar.org +spec: + group: tenancy.kflex.kubestellar.org + names: + kind: ControlPlane + listKind: ControlPlaneList + plural: controlplanes + shortNames: + - cp + - cps + singular: controlplane + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Synced')].status + name: SYNCED + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: READY + type: string + - jsonPath: .spec.type + name: TYPE + type: string + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: ControlPlane is the Schema for the controlplanes API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ControlPlaneSpec defines the desired state of ControlPlane + properties: + backend: + enum: + - shared + - dedicated + type: string + postCreateHook: + type: string + postCreateHookVars: + additionalProperties: + type: string + type: object + type: + enum: + - k8s + - ocm + - vcluster + - host + type: string + type: object + status: + description: ControlPlaneStatus defines the observed state of ControlPlane + properties: + conditions: + items: + description: ControlPlaneCondition describes the state of a control + plane at a certain point. + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - lastTransitionTime + - lastUpdateTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + postCreateHooks: + additionalProperties: + type: boolean + type: object + secretRef: + description: SecretRef contains a referece to the secret containing + the Kubeconfig for the control plane + properties: + inClusterKey: + description: Required + type: string + key: + description: Required + type: string + name: + description: |- + `name` is the name of the secret. + Required + type: string + namespace: + description: |- + `namespace` is the namespace of the secret. + Required + type: string + required: + - inClusterKey + - key + - name + - namespace + type: object + required: + - conditions + - observedGeneration + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: postcreatehooks.tenancy.kflex.kubestellar.org +spec: + group: tenancy.kflex.kubestellar.org + names: + kind: PostCreateHook + listKind: PostCreateHookList + plural: postcreatehooks + shortNames: + - pch + - pchs + singular: postcreatehook + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Synced')].status + name: SYNCED + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: READY + type: string + - jsonPath: .spec.type + name: TYPE + type: string + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: PostCreateHook is the Schema for the controlplanes API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: PostCreateHookSpec defines the desired state of PostCreateHook + properties: + templates: + items: + description: Manifest represents a resource to be deployed + type: object + x-kubernetes-embedded-resource: true + x-kubernetes-preserve-unknown-fields: true + type: array + type: object + status: + description: PostCreateHookStatus defines the observed state of PostCreateHook + properties: + conditions: + items: + description: ControlPlaneCondition describes the state of a control + plane at a certain point. + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - lastTransitionTime + - lastUpdateTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + format: int64 + type: integer + secretRef: + description: SecretRef contains a referece to the secret containing + the Kubeconfig for the control plane + properties: + inClusterKey: + description: Required + type: string + key: + description: Required + type: string + name: + description: |- + `name` is the name of the secret. + Required + type: string + namespace: + description: |- + `namespace` is the namespace of the secret. + Required + type: string + required: + - inClusterKey + - key + - name + - namespace + type: object + required: + - conditions + - observedGeneration + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/chart/templates/builtin-hooks.yaml b/chart/templates/builtin-hooks.yaml index 6fa8236..8c3a9ac 100644 --- a/chart/templates/builtin-hooks.yaml +++ b/chart/templates/builtin-hooks.yaml @@ -1,6 +1,6 @@ apiVersion: v1 data: - hooks.yaml: YXBpVmVyc2lvbjogdGVuYW5jeS5rZmxleC5rdWJlc3RlbGxhci5vcmcvdjFhbHBoYTEKa2luZDogUG9zdENyZWF0ZUhvb2sKbWV0YWRhdGE6CiAgbmFtZTogb3BlbnNoaWZ0LWNyZHMKICBsYWJlbHM6CiAgICBrZmxleC5rdWJlc3RlbGxhci5pby9mbGF2b3I6IG9wZW5zaGlmdApzcGVjOgogIHRlbXBsYXRlczoKICAtIGFwaVZlcnNpb246IGJhdGNoL3YxCiAgICBraW5kOiBKb2IKICAgIG1ldGFkYXRhOgogICAgICBuYW1lOiAie3suSG9va05hbWV9fSIKICAgIHNwZWM6CiAgICAgIHRlbXBsYXRlOgogICAgICAgIHNwZWM6CiAgICAgICAgICBjb250YWluZXJzOgogICAgICAgICAgLSBuYW1lOiAie3suSG9va05hbWV9fSIKICAgICAgICAgICAgaW1hZ2U6IHF1YXkuaW8vcGRldHRvcmkvaGVsbTp2My4xMy4yCiAgICAgICAgICAgIGFyZ3M6CiAgICAgICAgICAgICAgLSB1cGdyYWRlCiAgICAgICAgICAgICAgLSAtLWluc3RhbGwKICAgICAgICAgICAgICAtICJ7ey5Ib29rTmFtZX19IgogICAgICAgICAgICAgIC0gb2NpOi8vcXVheS5pby9wZGV0dG9yaS9vcGVuc2hpZnQtY3JkcwogICAgICAgICAgICAgIC0gLS12ZXJzaW9uCiAgICAgICAgICAgICAgLSAiMC4xLjAiCiAgICAgICAgICAgIGVudjoKICAgICAgICAgICAgLSBuYW1lOiBLVUJFQ09ORklHCiAgICAgICAgICAgICAgdmFsdWU6ICIvZXRjL2t1YmUva3ViZWNvbmZpZy1pbmNsdXN0ZXIiICAgIAogICAgICAgICAgICB2b2x1bWVNb3VudHM6CiAgICAgICAgICAgIC0gbmFtZToga3ViZWNvbmZpZwogICAgICAgICAgICAgIG1vdW50UGF0aDogIi9ldGMva3ViZSIKICAgICAgICAgICAgICByZWFkT25seTogdHJ1ZSAgCiAgICAgICAgICB2b2x1bWVzOgogICAgICAgICAgLSBuYW1lOiBrdWJlY29uZmlnCiAgICAgICAgICAgIHNlY3JldDoKICAgICAgICAgICAgICBzZWNyZXROYW1lOiBhZG1pbi1rdWJlY29uZmlnCiAgICAgICAgICByZXN0YXJ0UG9saWN5OiBOZXZlcgogICAgICBiYWNrb2ZmTGltaXQ6IDEK + hooks.yaml: YXBpVmVyc2lvbjogdGVuYW5jeS5rZmxleC5rdWJlc3RlbGxhci5vcmcvdjFhbHBoYTEKa2luZDogUG9zdENyZWF0ZUhvb2sKbWV0YWRhdGE6CiAgbmFtZTogb3BlbnNoaWZ0LWNyZHMKICBsYWJlbHM6CiAgICBrZmxleC5rdWJlc3RlbGxhci5pby9mbGF2b3I6IG9wZW5zaGlmdApzcGVjOgogIHRlbXBsYXRlczoKICAtIGFwaVZlcnNpb246IGJhdGNoL3YxCiAgICBraW5kOiBKb2IKICAgIG1ldGFkYXRhOgogICAgICBuYW1lOiAie3suSG9va05hbWV9fSIKICAgIHNwZWM6CiAgICAgIHRlbXBsYXRlOgogICAgICAgIHNwZWM6CiAgICAgICAgICBjb250YWluZXJzOgogICAgICAgICAgLSBuYW1lOiAie3suSG9va05hbWV9fSIKICAgICAgICAgICAgaW1hZ2U6IHF1YXkuaW8va3ViZXN0ZWxsYXIvaGVsbTozLjE0LjAKICAgICAgICAgICAgYXJnczoKICAgICAgICAgICAgICAtIHVwZ3JhZGUKICAgICAgICAgICAgICAtIC0taW5zdGFsbAogICAgICAgICAgICAgIC0gInt7Lkhvb2tOYW1lfX0iCiAgICAgICAgICAgICAgLSBvY2k6Ly9xdWF5LmlvL3BkZXR0b3JpL29wZW5zaGlmdC1jcmRzCiAgICAgICAgICAgICAgLSAtLXZlcnNpb24KICAgICAgICAgICAgICAtICIwLjEuMCIKICAgICAgICAgICAgZW52OgogICAgICAgICAgICAtIG5hbWU6IEtVQkVDT05GSUcKICAgICAgICAgICAgICB2YWx1ZTogIi9ldGMva3ViZS9rdWJlY29uZmlnLWluY2x1c3RlciIKICAgICAgICAgICAgdm9sdW1lTW91bnRzOgogICAgICAgICAgICAtIG5hbWU6IGt1YmVjb25maWcKICAgICAgICAgICAgICBtb3VudFBhdGg6ICIvZXRjL2t1YmUiCiAgICAgICAgICAgICAgcmVhZE9ubHk6IHRydWUKICAgICAgICAgIHZvbHVtZXM6CiAgICAgICAgICAtIG5hbWU6IGt1YmVjb25maWcKICAgICAgICAgICAgc2VjcmV0OgogICAgICAgICAgICAgIHNlY3JldE5hbWU6IGFkbWluLWt1YmVjb25maWcKICAgICAgICAgIHJlc3RhcnRQb2xpY3k6IE5ldmVyCiAgICAgIGJhY2tvZmZMaW1pdDogMQo= kind: Secret metadata: creationTimestamp: null diff --git a/chart/templates/operator.yaml b/chart/templates/operator.yaml index d25f0ad..b0e5481 100644 --- a/chart/templates/operator.yaml +++ b/chart/templates/operator.yaml @@ -1,4 +1,3 @@ ---- apiVersion: v1 kind: ServiceAccount metadata: @@ -60,7 +59,6 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: kubeflex-manager-role rules: - nonResourceURLs: @@ -518,6 +516,7 @@ apiVersion: v1 data: domain: '{{ .Values.domain }}' externalPort: '{{ .Values.externalPort }}' + hostContainer: '{{ .Values.hostContainer }}' isOpenShift: '{{ .Values.isOpenShift }}' kind: ConfigMap metadata: diff --git a/cmd/kflex/init/init.go b/cmd/kflex/init/init.go index bd1651c..1d8848b 100644 --- a/cmd/kflex/init/init.go +++ b/cmd/kflex/init/init.go @@ -33,7 +33,7 @@ import ( "github.com/kubestellar/kubeflex/pkg/util" ) -func Init(ctx context.Context, kubeconfig, version, buildDate string, domain, externalPort string, chattyStatus, isOCP bool) { +func Init(ctx context.Context, kubeconfig, version, buildDate string, domain, externalPort, hostContainer string, chattyStatus, isOCP bool) { done := make(chan bool) var wg sync.WaitGroup @@ -63,7 +63,7 @@ func Init(ctx context.Context, kubeconfig, version, buildDate string, domain, ex done <- true util.PrintStatus("Installing kubeflex operator...", done, &wg, chattyStatus) - ensureKFlexOperator(ctx, version, domain, externalPort, isOCP) + ensureKFlexOperator(ctx, version, domain, externalPort, hostContainer, isOCP) done <- true util.PrintStatus("Waiting for kubeflex operator to become ready...", done, &wg, chattyStatus) @@ -116,12 +116,13 @@ func ensureSystemDB(ctx context.Context, isOCP bool) { } } -func ensureKFlexOperator(ctx context.Context, fullVersion, domain, externalPort string, isOCP bool) { +func ensureKFlexOperator(ctx context.Context, fullVersion, domain, externalPort, hostContainer string, isOCP bool) { version := util.ParseVersionNumber(fullVersion) vars := []string{ fmt.Sprintf("version=%s", version), fmt.Sprintf("domain=%s", domain), fmt.Sprintf("externalPort=%s", externalPort), + fmt.Sprintf("hostContainer=%s", hostContainer), fmt.Sprintf("isOpenShift=%s", strconv.FormatBool(isOCP)), "installPostgreSQL=false", } diff --git a/cmd/kflex/main.go b/cmd/kflex/main.go index a6ff828..7e2f9b8 100644 --- a/cmd/kflex/main.go +++ b/cmd/kflex/main.go @@ -108,7 +108,7 @@ var initCmd = &cobra.Command{ } cluster.CreateKindCluster(chattyStatus) } - in.Init(ctx, kubeconfig, Version, BuildDate, domain, strconv.Itoa(externalPort), chattyStatus, isOCP) + in.Init(ctx, kubeconfig, Version, BuildDate, domain, strconv.Itoa(externalPort), hostContainer, chattyStatus, isOCP) wg.Wait() }, } diff --git a/docs/users.md b/docs/users.md index d391b3f..28eb0cc 100644 --- a/docs/users.md +++ b/docs/users.md @@ -45,7 +45,7 @@ kflex init --create-kind ## Install KubeFlex on an existing cluster You can install KubeFlex on an existing cluster with nginx ingress configured for SSL passthru, -or on a OpenShift cluster. At this time, we have only tested this option with Kind and OpenShift. +or on a OpenShift cluster. At this time, we have only tested this option with Kind, k3d and OpenShift. ### Installing on kind @@ -62,6 +62,29 @@ run the command to install KubeFlex: ```shell kflex init ``` + +### Installing on k3d + +These steps have only been tested with k3d v5.6.0. Create a k3d cluster with `traefik` disabled and nginx ingress as follows: + +```shell +k3d cluster create -p "9443:443@loadbalancer" --k3s-arg "--disable=traefik@server:*" kubeflex +helm install ingress-nginx ingress-nginx --repo https://kubernetes.github.io/ingress-nginx --version 4.6.1 --namespace ingress-nginx --create-namespace +``` + +Edit the nginx ingress deployment to enable SSL passthru: + +```shell +kubectl edit deployment ingress-nginx-controller -n ingress-nginx +``` + +and add `--enable-ssl-passthrough` to the list of args for the container named `controller`. Then you can +run the command to install KubeFlex specifying the name of the k3d container hosting kubeflex. + +```shell +kflex init --hostContainerName k3d-kubeflex-server-0 +``` + ### Installing on OpenShift If you are installing on an OpenShift cluster you do not need any special configuration. Just run diff --git a/pkg/reconcilers/shared/job.go b/pkg/reconcilers/shared/job.go index 1ce6aa4..bdefba3 100644 --- a/pkg/reconcilers/shared/job.go +++ b/pkg/reconcilers/shared/job.go @@ -34,9 +34,8 @@ import ( ) const ( - jobName = "update-cluster-info" - //baseImage = "ghcr.io/kubestellar/kubeflex/cmupdate" - baseImage = "ko.local/cmupdate" + jobName = "update-cluster-info" + baseImage = "ghcr.io/kubestellar/kubeflex/cmupdate" ) func (r *BaseReconciler) ReconcileUpdateClusterInfoJob(ctx context.Context, hcp *tenancyv1alpha1.ControlPlane, cfg *SharedConfig, version string) error { @@ -126,8 +125,7 @@ func generateClusterInfoJob(name, namespace, kubeconfigSecret, kubeconfigSecretK } func buildImageRef(version string) string { - //tag := "latest" - tag := "v0.5.1-12-g4542b38" + tag := "latest" if version != "" { tag = util.ParseVersionNumber(version) }