diff --git a/charts/spoke-cluster-proxy/Chart.yaml b/charts/spoke-cluster-proxy/Chart.yaml
new file mode 100644
index 00000000..932a89f5
--- /dev/null
+++ b/charts/spoke-cluster-proxy/Chart.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+description: Spoke Cluster Proxy
+name: spoke-cluster-proxy
+version: v2024.2.25
+appVersion: v0.0.1
+home: https://github.com/kluster-manager/cluster-proxy
+icon: https://cdn.appscode.com/images/products/searchlight/icons/android-icon-192x192.png
+sources:
+- https://github.com/kluster-manager/cluster-proxy
+maintainers:
+- name: appscode
+ email: support@appscode.com
diff --git a/charts/spoke-cluster-proxy/README.md b/charts/spoke-cluster-proxy/README.md
new file mode 100644
index 00000000..6772c2b8
--- /dev/null
+++ b/charts/spoke-cluster-proxy/README.md
@@ -0,0 +1,67 @@
+# Spoke Cluster Proxy
+
+[Spoke Cluster Proxy](https://github.com/kluster-manager/cluster-proxy) - Spoke Cluster Proxy
+
+## TL;DR;
+
+```bash
+$ helm repo add appscode https://charts.appscode.com/stable
+$ helm repo update
+$ helm search repo appscode/spoke-cluster-proxy --version=v2024.2.25
+$ helm upgrade -i spoke-cluster-proxy appscode/spoke-cluster-proxy -n c1 --create-namespace --version=v2024.2.25
+```
+
+## Introduction
+
+This chart deploys a Spoke Cluster Proxy on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
+
+## Prerequisites
+
+- Kubernetes 1.21+
+
+## Installing the Chart
+
+To install/upgrade the chart with the release name `spoke-cluster-proxy`:
+
+```bash
+$ helm upgrade -i spoke-cluster-proxy appscode/spoke-cluster-proxy -n c1 --create-namespace --version=v2024.2.25
+```
+
+The command deploys a Spoke Cluster Proxy on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
+
+> **Tip**: List all releases using `helm list`
+
+## Uninstalling the Chart
+
+To uninstall the `spoke-cluster-proxy`:
+
+```bash
+$ helm uninstall spoke-cluster-proxy -n c1
+```
+
+The command removes all the Kubernetes components associated with the chart and deletes the release.
+
+## Configuration
+
+The following table lists the configurable parameters of the `spoke-cluster-proxy` chart and their default values.
+
+| Parameter | Description | Default |
+|----------------------|-------------|----------------------------------------------------|
+| nameOverride | | ""
|
+| fullnameOverride | | ""
|
+| kubeconfigSecretName | | ""
|
+| kubectl.image | | ghcr.io/appscode/kubectl-nonroot:1.25
|
+
+
+Specify each parameter using the `--set key=value[,key=value]` argument to `helm upgrade -i`. For example:
+
+```bash
+$ helm upgrade -i spoke-cluster-proxy appscode/spoke-cluster-proxy -n c1 --create-namespace --version=v2024.2.25 --set kubectl.image=ghcr.io/appscode/kubectl-nonroot:1.25
+```
+
+Alternatively, a YAML file that specifies the values for the parameters can be provided while
+installing the chart. For example:
+
+```bash
+$ helm upgrade -i spoke-cluster-proxy appscode/spoke-cluster-proxy -n c1 --create-namespace --version=v2024.2.25 --values values.yaml
+```
diff --git a/charts/spoke-cluster-proxy/common/addon/managedclusteraddon.yaml b/charts/spoke-cluster-proxy/common/addon/managedclusteraddon.yaml
new file mode 100644
index 00000000..dbad164b
--- /dev/null
+++ b/charts/spoke-cluster-proxy/common/addon/managedclusteraddon.yaml
@@ -0,0 +1,7 @@
+apiVersion: addon.open-cluster-management.io/v1alpha1
+kind: ManagedClusterAddOn
+metadata:
+ name: cluster-proxy
+ namespace: {{ .Release.Namespace }}
+spec:
+ installNamespace: open-cluster-management-cluster-proxy
diff --git a/charts/spoke-cluster-proxy/crds/addon.open-cluster-management.io_managedclusteraddons.yaml b/charts/spoke-cluster-proxy/crds/addon.open-cluster-management.io_managedclusteraddons.yaml
new file mode 100644
index 00000000..94b582de
--- /dev/null
+++ b/charts/spoke-cluster-proxy/crds/addon.open-cluster-management.io_managedclusteraddons.yaml
@@ -0,0 +1,400 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: managedclusteraddons.addon.open-cluster-management.io
+spec:
+ group: addon.open-cluster-management.io
+ names:
+ kind: ManagedClusterAddOn
+ listKind: ManagedClusterAddOnList
+ plural: managedclusteraddons
+ shortNames:
+ - mca
+ - mcas
+ singular: managedclusteraddon
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - jsonPath: .status.conditions[?(@.type=="Available")].status
+ name: Available
+ type: string
+ - jsonPath: .status.conditions[?(@.type=="Degraded")].status
+ name: Degraded
+ type: string
+ - jsonPath: .status.conditions[?(@.type=="Progressing")].status
+ name: Progressing
+ type: string
+ name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: ManagedClusterAddOn is the Custom Resource object which holds
+ the current state of an add-on. This object is used by add-on operators
+ to convey their state. This resource should be created in the ManagedCluster
+ namespace.
+ 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: spec holds configuration that could apply to any operator.
+ properties:
+ configs:
+ description: configs is a list of add-on configurations. In scenario
+ where the current add-on has its own configurations. An empty list
+ means there are no default configurations for add-on. The default
+ is an empty list
+ items:
+ properties:
+ group:
+ default: ""
+ description: group of the add-on configuration.
+ type: string
+ name:
+ description: name of the add-on configuration.
+ minLength: 1
+ type: string
+ namespace:
+ description: namespace of the add-on configuration. If this
+ field is not set, the configuration is in the cluster scope.
+ type: string
+ resource:
+ description: resource of the add-on configuration.
+ minLength: 1
+ type: string
+ required:
+ - name
+ - resource
+ type: object
+ type: array
+ installNamespace:
+ default: open-cluster-management-agent-addon
+ description: installNamespace is the namespace on the managed cluster
+ to install the addon agent. If it is not set, open-cluster-management-agent-addon
+ namespace is used to install the addon agent.
+ maxLength: 63
+ pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+ type: string
+ type: object
+ status:
+ description: status holds the information about the state of an operator. It
+ is consistent with status information across the Kubernetes ecosystem.
+ properties:
+ addOnConfiguration:
+ description: 'Deprecated: Use configReferences instead. addOnConfiguration
+ is a reference to configuration information for the add-on. This
+ resource is used to locate the configuration resource for the add-on.'
+ properties:
+ crName:
+ description: crName is the name of the CR used to configure instances
+ of the managed add-on. This field should be configured if add-on
+ CR have a consistent name across the all of the ManagedCluster
+ instaces.
+ type: string
+ crdName:
+ description: crdName is the name of the CRD used to configure
+ instances of the managed add-on. This field should be configured
+ if the add-on have a CRD that controls the configuration of
+ the add-on.
+ type: string
+ lastObservedGeneration:
+ description: lastObservedGeneration is the observed generation
+ of the custom resource for the configuration of the addon.
+ format: int64
+ type: integer
+ type: object
+ addOnMeta:
+ description: addOnMeta is a reference to the metadata information
+ for the add-on. This should be same as the addOnMeta for the corresponding
+ ClusterManagementAddOn resource.
+ properties:
+ description:
+ description: description represents the detailed description of
+ the add-on.
+ type: string
+ displayName:
+ description: displayName represents the name of add-on that will
+ be displayed.
+ type: string
+ type: object
+ conditions:
+ description: conditions describe the state of the managed and monitored
+ components for the operator.
+ items:
+ description: "Condition contains details for one aspect of the current
+ state of this API Resource. --- This struct is intended for direct
+ use as an array at the field path .status.conditions. For example,
+ \n type FooStatus struct{ // Represents the observations of a
+ foo's current state. // Known .status.conditions.type are: \"Available\",
+ \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+ // +listType=map // +listMapKey=type Conditions []metav1.Condition
+ `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+ protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+ properties:
+ lastTransitionTime:
+ description: lastTransitionTime is the last time the condition
+ transitioned from one status to another. This should be when
+ the underlying condition changed. If that is not known, then
+ using the time when the API field changed is acceptable.
+ format: date-time
+ type: string
+ message:
+ description: message is a human readable message indicating
+ details about the transition. This may be an empty string.
+ maxLength: 32768
+ type: string
+ observedGeneration:
+ description: observedGeneration represents the .metadata.generation
+ that the condition was set based upon. For instance, if .metadata.generation
+ is currently 12, but the .status.conditions[x].observedGeneration
+ is 9, the condition is out of date with respect to the current
+ state of the instance.
+ format: int64
+ minimum: 0
+ type: integer
+ reason:
+ description: reason contains a programmatic identifier indicating
+ the reason for the condition's last transition. Producers
+ of specific condition types may define expected values and
+ meanings for this field, and whether the values are considered
+ a guaranteed API. The value should be a CamelCase string.
+ This field may not be empty.
+ maxLength: 1024
+ minLength: 1
+ pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+ type: string
+ status:
+ description: status of the condition, one of True, False, Unknown.
+ enum:
+ - "True"
+ - "False"
+ - Unknown
+ type: string
+ type:
+ description: type of condition in CamelCase or in foo.example.com/CamelCase.
+ --- Many .condition.type values are consistent across resources
+ like Available, but because arbitrary conditions can be useful
+ (see .node.status.conditions), the ability to deconflict is
+ important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+ maxLength: 316
+ pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+ type: string
+ required:
+ - lastTransitionTime
+ - message
+ - reason
+ - status
+ - type
+ type: object
+ type: array
+ configReferences:
+ description: configReferences is a list of current add-on configuration
+ references. This will be overridden by the clustermanagementaddon
+ configuration references.
+ items:
+ description: ConfigReference is a reference to the current add-on
+ configuration. This resource is used to locate the configuration
+ resource for the current add-on.
+ properties:
+ desiredConfig:
+ description: desiredConfig record the desired config spec hash.
+ properties:
+ name:
+ description: name of the add-on configuration.
+ minLength: 1
+ type: string
+ namespace:
+ description: namespace of the add-on configuration. If this
+ field is not set, the configuration is in the cluster
+ scope.
+ type: string
+ specHash:
+ description: spec hash for an add-on configuration.
+ type: string
+ required:
+ - name
+ type: object
+ group:
+ default: ""
+ description: group of the add-on configuration.
+ type: string
+ lastAppliedConfig:
+ description: lastAppliedConfig record the config spec hash when
+ the corresponding ManifestWork is applied successfully.
+ properties:
+ name:
+ description: name of the add-on configuration.
+ minLength: 1
+ type: string
+ namespace:
+ description: namespace of the add-on configuration. If this
+ field is not set, the configuration is in the cluster
+ scope.
+ type: string
+ specHash:
+ description: spec hash for an add-on configuration.
+ type: string
+ required:
+ - name
+ type: object
+ lastObservedGeneration:
+ description: 'Deprecated: Use LastAppliedConfig instead lastObservedGeneration
+ is the observed generation of the add-on configuration.'
+ format: int64
+ type: integer
+ name:
+ description: name of the add-on configuration.
+ minLength: 1
+ type: string
+ namespace:
+ description: namespace of the add-on configuration. If this
+ field is not set, the configuration is in the cluster scope.
+ type: string
+ resource:
+ description: resource of the add-on configuration.
+ minLength: 1
+ type: string
+ required:
+ - name
+ - resource
+ type: object
+ type: array
+ healthCheck:
+ description: healthCheck indicates how to check the healthiness status
+ of the current addon. It should be set by each addon implementation,
+ by default, the lease mode will be used.
+ properties:
+ mode:
+ default: Lease
+ description: mode indicates which mode will be used to check the
+ healthiness status of the addon.
+ enum:
+ - Lease
+ - Customized
+ type: string
+ type: object
+ namespace:
+ description: namespace is the namespace on the managedcluster to put
+ registration secret or lease for the addon. It is required when
+ registration is set or healthcheck mode is Lease.
+ type: string
+ registrations:
+ description: registrations is the configurations for the addon agent
+ to register to hub. It should be set by each addon controller on
+ hub to define how the addon agent on managedcluster is registered.
+ With the registration defined, The addon agent can access to kube
+ apiserver with kube style API or other endpoints on hub cluster
+ with client certificate authentication. A csr will be created per
+ registration configuration. If more than one registrationConfig
+ is defined, a csr will be created for each registration configuration.
+ It is not allowed that multiple registrationConfigs have the same
+ signer name. After the csr is approved on the hub cluster, the klusterlet
+ agent will create a secret in the installNamespace for the registrationConfig.
+ If the signerName is "kubernetes.io/kube-apiserver-client", the
+ secret name will be "{addon name}-hub-kubeconfig" whose contents
+ includes key/cert and kubeconfig. Otherwise, the secret name will
+ be "{addon name}-{signer name}-client-cert" whose contents includes
+ key/cert.
+ items:
+ description: RegistrationConfig defines the configuration of the
+ addon agent to register to hub. The Klusterlet agent will create
+ a csr for the addon agent with the registrationConfig.
+ properties:
+ signerName:
+ description: signerName is the name of signer that addon agent
+ will use to create csr.
+ maxLength: 571
+ minLength: 5
+ type: string
+ subject:
+ description: 'subject is the user subject of the addon agent
+ to be registered to the hub. If it is not set, the addon agent
+ will have the default subject "subject": { "user": "system:open-cluster-management:cluster:{clusterName}:addon:{addonName}:agent:{agentName}",
+ "groups: ["system:open-cluster-management:cluster:{clusterName}:addon:{addonName}",
+ "system:open-cluster-management:addon:{addonName}", "system:authenticated"]
+ }'
+ properties:
+ groups:
+ description: groups is the user group of the addon agent.
+ items:
+ type: string
+ type: array
+ organizationUnit:
+ description: organizationUnit is the ou of the addon agent
+ items:
+ type: string
+ type: array
+ user:
+ description: user is the user name of the addon agent.
+ type: string
+ type: object
+ type: object
+ type: array
+ relatedObjects:
+ description: 'relatedObjects is a list of objects that are "interesting"
+ or related to this operator. Common uses are: 1. the detailed resource
+ driving the operator 2. operator namespaces 3. operand namespaces
+ 4. related ClusterManagementAddon resource'
+ items:
+ description: ObjectReference contains enough information to let
+ you inspect or modify the referred object.
+ properties:
+ group:
+ description: group of the referent.
+ type: string
+ name:
+ description: name of the referent.
+ type: string
+ namespace:
+ description: namespace of the referent.
+ type: string
+ resource:
+ description: resource of the referent.
+ type: string
+ required:
+ - group
+ - name
+ - resource
+ type: object
+ type: array
+ supportedConfigs:
+ description: SupportedConfigs is a list of configuration types that
+ are allowed to override the add-on configurations defined in ClusterManagementAddOn
+ spec. The default is an empty list, which means the add-on configurations
+ can not be overridden.
+ items:
+ description: ConfigGroupResource represents the GroupResource of
+ the add-on configuration
+ properties:
+ group:
+ default: ""
+ description: group of the add-on configuration.
+ type: string
+ resource:
+ description: resource of the add-on configuration.
+ minLength: 1
+ type: string
+ required:
+ - resource
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - group
+ - resource
+ x-kubernetes-list-type: map
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/charts/spoke-cluster-proxy/doc.yaml b/charts/spoke-cluster-proxy/doc.yaml
new file mode 100644
index 00000000..5ea9b9e3
--- /dev/null
+++ b/charts/spoke-cluster-proxy/doc.yaml
@@ -0,0 +1,18 @@
+project:
+ name: Spoke Cluster Proxy
+ shortName: Spoke Cluster Proxy
+ url: https://github.com/kluster-manager/cluster-proxy
+ description: Spoke Cluster Proxy
+ app: a Spoke Cluster Proxy
+repository:
+ url: https://charts.appscode.com/stable
+ name: appscode
+chart:
+ name: spoke-cluster-proxy
+ values: -- generate from values file --
+ valuesExample: -- generate from values file --
+prerequisites:
+- Kubernetes 1.21+
+release:
+ name: spoke-cluster-proxy
+ namespace: c1
diff --git a/charts/spoke-cluster-proxy/templates/_helpers.tpl b/charts/spoke-cluster-proxy/templates/_helpers.tpl
new file mode 100644
index 00000000..36a00858
--- /dev/null
+++ b/charts/spoke-cluster-proxy/templates/_helpers.tpl
@@ -0,0 +1,69 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "spoke-cluster-proxy.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "spoke-cluster-proxy.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "spoke-cluster-proxy.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "spoke-cluster-proxy.labels" -}}
+helm.sh/chart: {{ include "spoke-cluster-proxy.chart" . }}
+{{ include "spoke-cluster-proxy.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "spoke-cluster-proxy.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "spoke-cluster-proxy.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "spoke-cluster-proxy.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "spoke-cluster-proxy.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
+
+{{/*
+Addon manager namespace
+*/}}
+{{- define "spoke-cluster-proxy.namespace" -}}
+{{ ternary .Release.Namespace (required "A valid .Values.addonManagerNamespace is required!" .Values.addonManagerNamespace) (empty .Values.kubeconfigSecretName) }}
+{{- end }}
diff --git a/charts/spoke-cluster-proxy/templates/k8s/addon.yaml b/charts/spoke-cluster-proxy/templates/k8s/addon.yaml
new file mode 100644
index 00000000..0256bdb5
--- /dev/null
+++ b/charts/spoke-cluster-proxy/templates/k8s/addon.yaml
@@ -0,0 +1,6 @@
+{{- if not .Values.kubeconfigSecretName }}
+
+{{- $restpl := $.Files.Get "common/addon/managedclusteraddon.yaml" }}
+{{ tpl $restpl $ }}
+
+{{- end }}
diff --git a/charts/spoke-cluster-proxy/templates/ocm-mc/addon.yaml b/charts/spoke-cluster-proxy/templates/ocm-mc/addon.yaml
new file mode 100644
index 00000000..50746bc7
--- /dev/null
+++ b/charts/spoke-cluster-proxy/templates/ocm-mc/addon.yaml
@@ -0,0 +1,43 @@
+{{- if .Values.kubeconfigSecretName }}
+
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: spoke-cluster-proxy-configure-addon
+ namespace: {{ .Release.Namespace }}
+ annotations:
+ "helm.sh/hook-weight": "2"
+ "helm.sh/hook": post-install,post-upgrade,post-rollback
+ "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed
+spec:
+ ttlSecondsAfterFinished: 0
+ backoffLimit: 3
+ template:
+ spec:
+ automountServiceAccountToken: false
+ containers:
+ - name: kubectl
+ image: {{ .Values.kubectl.image }}
+ workingDir: /var/run/secrets/ocm
+ command:
+ - sh
+ - -c
+ - |
+ sleep 2; \
+ kubectl --kubeconfig=auth/kubeconfig create ns {{ $.Release.Namespace }} || true; \
+ kubectl --kubeconfig=auth/kubeconfig apply -f - <