Feature 11057: Cluster management in Openshift-based infrastructures 27/15227/20
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Wed, 11 Jun 2025 09:11:56 +0000 (11:11 +0200)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Tue, 5 Aug 2025 17:24:44 +0000 (19:24 +0200)
Change-Id: I8bdb1efb3ad1e9c8da688f334b3dcf7f49ad047c
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
25 files changed:
docker/osm-krm-functions/scripts/library/helper-functions.rc
docker/osm-krm-functions/scripts/library/krm-functions.rc
installers/00-default-install-options.rc
installers/01-export-osm-install-options.sh
installers/40-deploy-osm.sh
installers/flux/scripts/create-new-cluster-folder-structure.sh
installers/flux/scripts/mgmt-cluster-bootstrap.sh
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/bootstrap/templates/remote-cluster-bootstrap.yaml
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/apps.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/fleet-repo.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/flux-system/gotk-sync.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/flux-system/kustomization.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/flux-system/scc.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/infra-configs.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/infra-controllers.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/kustomization.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/managed-resources.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/sw-catalogs-repo.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/hostedcluster.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/klusterlet.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/managedcluster.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/nodepool.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/namespaces/namespaces.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/cloud-resources/openshift/templates/openshift01.yaml [new file with mode: 0644]
installers/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-crossplane-cluster-and-bootstrap-wft.yaml

index 03614d1..53115c0 100644 (file)
@@ -13,6 +13,7 @@
 #   limitations under the License.
 #
 
+
 # Convert input string to a safe name for K8s resources
 function safe_name() {
   local INPUT="$1"
index c006729..1fc5a5f 100644 (file)
@@ -17,7 +17,6 @@
 #######################################################################################
 
 
-
 function generator_encrypted_secret_cloud_credentials() {
   local CLOUD_CREDENTIALS_FILENAME="$1"
   local SECRET_NAME="$2"
@@ -228,6 +227,7 @@ EOF
     "${TARGET_FOLDER}"
 }
 
+
 function scale_nodegroup() {
   local NODEGROUP_NAME="$1"
   local NODEGROUP_KUSTOMIZATION_NAME="$2"
@@ -251,7 +251,7 @@ function scale_nodegroup() {
   local BASE_TEMPLATES_PATH="${15:-"cloud-resources"}"
   local MANIFEST_FILENAME="${16:-"${NODEGROUP_NAME}"}"
 
-   # Is the provider type supported?
+  # Is the provider type supported?
   local VALID_PROVIDERS=("eks" "aks" "gke")
   CLUSTER_TYPE="${CLUSTER_TYPE,,}"
   [[ ! ($(echo ${VALID_PROVIDERS[@]} | grep -w "${CLUSTER_TYPE}")) ]] && return 1
@@ -271,6 +271,7 @@ function scale_nodegroup() {
     "${TARGET_FOLDER}"
 }
 
+
 # Delete nodegroup
 function delete_nodegroup() {
   local NODEGROUP_KUSTOMIZATION_NAME="$1"
@@ -278,13 +279,12 @@ function delete_nodegroup() {
   local PROJECT_NAME="${3:-"${MGMT_PROJECT_NAME}"}"
   local FLEET_REPO_DIR="${4:-"${FLEET_REPO_DIR}"}"
   local MGMT_RESOURCES_DIR="${5:-"${MGMT_RESOURCES_DIR}"}"
-
   local NODEGROUP_DIR="${MGMT_RESOURCES_DIR}/${CLUSTER_NAME}/${NODEGROUP_KUSTOMIZATION_NAME}"
-
   # Delete node Kustomizations
   rm -rf "${NODEGROUP_DIR}"
 }
 
+
 # TODO: Deprecated
 # Create AKS cluster (without bootstrap)
 function create_cluster_aks() {
@@ -505,16 +505,15 @@ function generator_base_kustomizations_new_cluster() {
   local SW_CATALOGS_REPO_URL="$3"
   local PROJECT_NAME="${4:-"${MGMT_PROJECT_NAME}"}"
   local SW_CATALOGS_REPO_DIR="${5:-"${SW_CATALOGS_REPO_DIR}"}"
-
+  # Path for the source templates
+  local TEMPLATES="${6:-"${SW_CATALOGS_REPO_DIR}/cloud-resources/flux-remote-bootstrap/cluster-base/templates"}"
+  
   # Optional inputs:
   # Paths for each profile in the Git repo
-  local INFRA_CONTROLLERS_PATH="${6:-"${PROJECT_NAME}/infra-controller-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
-  local INFRA_CONFIGS_PATH="${7:-"${PROJECT_NAME}/infra-config-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
-  local MANAGED_RESOURCES_PATH="${8:-"${PROJECT_NAME}/managed-resources/${CLUSTER_KUSTOMIZATION_NAME}"}"
-  local APPS_PATH="${9:-"${PROJECT_NAME}/app-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
-
-  # Path for the source templates
-  local TEMPLATES="${SW_CATALOGS_REPO_DIR}/cloud-resources/flux-remote-bootstrap/cluster-base/templates"
+  local INFRA_CONTROLLERS_PATH="${7:-"${PROJECT_NAME}/infra-controller-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
+  local INFRA_CONFIGS_PATH="${8:-"${PROJECT_NAME}/infra-config-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
+  local MANAGED_RESOURCES_PATH="${9:-"${PROJECT_NAME}/managed-resources/${CLUSTER_KUSTOMIZATION_NAME}"}"
+  local APPS_PATH="${10:-"${PROJECT_NAME}/app-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
 
   # Generate
   export CLUSTER_KUSTOMIZATION_NAME
@@ -556,6 +555,7 @@ function generator_k8s_age_secret_new_cluster() {
   local PRIVATE_KEY_NEW_CLUSTER="$1"
   local PUBLIC_KEY_MGMT="$2"
   local CLUSTER_AGE_SECRET_NAME="${3:-$(safe_name "sops-age-${CLUSTER_KUSTOMIZATION_NAME}")}"
+  local CLUSTER_AGE_SECRET_NAMESPACE="${4:-"managed-resources"}"
 
   join_lists \
     <(cat) \
@@ -563,7 +563,7 @@ function generator_k8s_age_secret_new_cluster() {
       echo "${PRIVATE_KEY_NEW_CLUSTER}" | \
       grep -v '^#' | \
       kubectl create secret generic "${CLUSTER_AGE_SECRET_NAME}" \
-        --namespace=managed-resources \
+        --namespace="${CLUSTER_AGE_SECRET_NAMESPACE}" \
         --from-file=agekey=/dev/stdin \
         -o yaml --dry-run=client | \
       encrypt_secret_from_stdin \
@@ -580,16 +580,28 @@ function generator_bootstrap_new_cluster() {
   local CLUSTER_KUSTOMIZATION_NAME="${2:-$(safe_name ${CLUSTER_NAME})}"
   local CLUSTER_AGE_SECRET_NAME="${3:-$(safe_name "sops-age-${CLUSTER_KUSTOMIZATION_NAME}")}"
   local SW_CATALOGS_REPO_DIR="${4:-"${SW_CATALOGS_REPO_DIR}"}"
+  local BOOTSTRAP_KUSTOMIZATION_NAMESPACE="${5:-"managed-resources"}"
+  local CLUSTER_KUSTOMIZATION_NAMESPACE="${6:-"managed-resources"}"
+  local BOOTSTRAP_SECRET_NAMESPACE="${7:-"managed-resources"}"
 
   # Paths and names for the templates
-  local MANIFEST_FILENAME="${5:-"cluster-bootstrap-${CLUSTER_KUSTOMIZATION_NAME}.yaml"}"
-  local TEMPLATES="${6:-"${SW_CATALOGS_REPO_DIR}/cloud-resources/flux-remote-bootstrap/bootstrap/templates"}"
-  local TEMPLATE_MANIFEST_FILENAME="${7:-"remote-cluster-bootstrap.yaml"}"
+  local MANIFEST_FILENAME="${7:-"cluster-bootstrap-${CLUSTER_KUSTOMIZATION_NAME}.yaml"}"
+  local TEMPLATES="${8:-"${SW_CATALOGS_REPO_DIR}/cloud-resources/flux-remote-bootstrap/bootstrap/templates"}"
+  local TEMPLATE_MANIFEST_FILENAME="${9:-"remote-cluster-bootstrap.yaml"}"
+
+  # Variables for kubeconfig secret configuration
+  local CLUSTER_KUBECONFIG_SECRET_KEY=${CLUSTER_KUBECONFIG_SECRET_KEY:-"kubeconfig"}
+  local CLUSTER_KUBECONFIG_SECRET_NAME=${CLUSTER_KUBECONFIG_SECRET_NAME:-"kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}"}
 
   # Generate manifests
   export CLUSTER_KUSTOMIZATION_NAME
   export CLUSTER_NAME
   export CLUSTER_AGE_SECRET_NAME
+  export CLUSTER_KUBECONFIG_SECRET_KEY
+  export CLUSTER_KUBECONFIG_SECRET_NAME
+  export BOOTSTRAP_KUSTOMIZATION_NAMESPACE
+  export CLUSTER_KUSTOMIZATION_NAMESPACE
+  export BOOTSTRAP_SECRET_NAMESPACE
 
   join_lists \
     <(cat) \
@@ -600,7 +612,7 @@ function generator_bootstrap_new_cluster() {
         "${TEMPLATE_MANIFEST_FILENAME}" \
         "${MANIFEST_FILENAME}" | \
       replace_env_vars \
-        '${CLUSTER_KUSTOMIZATION_NAME},${CLUSTER_NAME},${CLUSTER_AGE_SECRET_NAME}'
+        '${CLUSTER_KUSTOMIZATION_NAME},${CLUSTER_NAME},${CLUSTER_AGE_SECRET_NAME},${CLUSTER_KUBECONFIG_SECRET_KEY},${CLUSTER_KUBECONFIG_SECRET_NAME},${CLUSTER_KUSTOMIZATION_NAMESPACE},${BOOTSTRAP_KUSTOMIZATION_NAMESPACE},${BOOTSTRAP_SECRET_NAMESPACE}'
       )
 }
 
@@ -670,10 +682,16 @@ function create_bootstrap_for_remote_cluster() {
   local PUBLIC_KEY_NEW_CLUSTER="$9"
   local PRIVATE_KEY_NEW_CLUSTER="${10:-${PRIVATE_KEY_NEW_CLUSTER}}"
   local IMPORTED_CLUSTER="${11:-"false"}"
-
-
-  # Calculates the folder where managed resources area defined
-  local MGMT_RESOURCES_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/managed-resources/_management"
+  local MGMT_CLUSTER_NAME="${12:-"_management"}"
+  local CLUSTER_KUBECONFIG_SECRET_NAME=${13:-"kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}"}
+  local CLUSTER_KUBECONFIG_SECRET_KEY=${14:-"kubeconfig"}
+  local TEMPLATES_DIR="${15:-"${SW_CATALOGS_REPO_DIR}/cloud-resources/flux-remote-bootstrap/cluster-base/templates"}"
+  local BOOTSTRAP_KUSTOMIZATION_NAMESPACE="${16:-"managed-resources"}"
+  local CLUSTER_KUSTOMIZATION_NAMESPACE="${17:-"managed-resources"}"
+  local BOOTSTRAP_SECRET_NAMESPACE="${18:-"${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}"}"
+
+  # Calculates the folder where managed resources are defined
+  local MGMT_RESOURCES_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/managed-resources/${MGMT_CLUSTER_NAME}"
 
   # Create profile folders
   echo "" | \
@@ -692,7 +710,8 @@ function create_bootstrap_for_remote_cluster() {
     "${FLEET_REPO_URL}" \
     "${SW_CATALOGS_REPO_URL}" \
     "${MGMT_PROJECT_NAME}" \
-    "${SW_CATALOGS_REPO_DIR}" | \
+    "${SW_CATALOGS_REPO_DIR}" \
+    "${TEMPLATES_DIR}" | \
   list2folder_cp_over \
     "${CLUSTER_FOLDER}"
 
@@ -715,11 +734,15 @@ function create_bootstrap_for_remote_cluster() {
     "${CLUSTER_NAME}" \
     "${CLUSTER_KUSTOMIZATION_NAME}" \
     "${CLUSTER_AGE_SECRET_NAME}" \
-    "${SW_CATALOGS_REPO_DIR}" | \
+    "${SW_CATALOGS_REPO_DIR}" \
+    "${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}" \
+    "${CLUSTER_KUSTOMIZATION_NAMESPACE}" \
+    "${BOOTSTRAP_SECRET_NAMESPACE}" | \
   generator_k8s_age_secret_new_cluster \
     "${PRIVATE_KEY_NEW_CLUSTER}" \
     "${PUBLIC_KEY_MGMT}" \
-    "${CLUSTER_AGE_SECRET_NAME}" | \
+    "${CLUSTER_AGE_SECRET_NAME}" \
+    "${BOOTSTRAP_SECRET_NAMESPACE}" | \
   prepend_folder_path "${CLUSTER_KUSTOMIZATION_NAME}/" | \
   list2folder_cp_over \
     "${MGMT_RESOURCES_DIR}"
@@ -802,7 +825,6 @@ function create_crossplane_cluster() {
   local TEMPLATE_MANIFEST_FILENAME="${26:-"${CLUSTER_TYPE,,}01.yaml"}"
   local MANIFEST_FILENAME="${27:-"${CLUSTER_TYPE,,}-${CLUSTER_NAME}.yaml"}"
 
-
   # Is the provider type supported?
   local VALID_PROVIDERS=("eks" "aks" "gke")
   CLUSTER_TYPE="${CLUSTER_TYPE,,}"
@@ -983,22 +1005,23 @@ function delete_remote_cluster() {
   local PROJECT_NAME="${2:-"${MGMT_PROJECT_NAME}"}"
   local FLEET_REPO_DIR="${3:-"${FLEET_REPO_DIR}"}"
   local MGMT_RESOURCES_DIR="${4:-"${MGMT_RESOURCES_DIR}"}"
+  local MGMT_CLUSTER_DIR="${5:-"${MGMT_CLUSTER_DIR}"}"
 
   # Optional inputs: Paths for each profile in the Git repo
-  local INFRA_CONTROLLERS_DIR="${5:-"${FLEET_REPO_DIR}/${PROJECT_NAME}/infra-controller-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
-  local INFRA_CONFIGS_DIR="${6:-"${FLEET_REPO_DIR}/${PROJECT_NAME}/infra-config-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
-  local MANAGED_RESOURCES_DIR="${7:-"${FLEET_REPO_DIR}/${PROJECT_NAME}/managed-resources/${CLUSTER_KUSTOMIZATION_NAME}"}"
-  local APPS_DIR="${8:-"${FLEET_REPO_DIR}/${PROJECT_NAME}/app-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
-  local CLUSTER_DIR="${9:-"${FLEET_REPO_DIR}/clusters/${CLUSTER_KUSTOMIZATION_NAME}"}"
+  local INFRA_CONTROLLERS_DIR="${6:-"${FLEET_REPO_DIR}/${PROJECT_NAME}/infra-controller-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
+  local INFRA_CONFIGS_DIR="${7:-"${FLEET_REPO_DIR}/${PROJECT_NAME}/infra-config-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
+  local MANAGED_RESOURCES_DIR="${8:-"${FLEET_REPO_DIR}/${PROJECT_NAME}/managed-resources/${CLUSTER_KUSTOMIZATION_NAME}"}"
+  local MGMT_CLUSTER_DIR="${9:-"${FLEET_REPO_DIR}/${PROJECT_NAME}/managed-resources/${MGMT_CLUSTER_DIR}"}"
+  local APPS_DIR="${10:-"${FLEET_REPO_DIR}/${PROJECT_NAME}/app-profiles/${CLUSTER_KUSTOMIZATION_NAME}"}"
+  local CLUSTER_DIR="${11:-"${FLEET_REPO_DIR}/clusters/${CLUSTER_KUSTOMIZATION_NAME}"}"
 
   # Optional input: Do I need a purge operation first?
-  local PURGE="${10:-"false"}"
+  local PURGE="${12:-"false"}"
 
 
   # Perform the purge if needed
   if [[ "${PURGE,,}" == "true" ]]; then
     echo "Purging the remote Flux instalation..."
-    flux uninstall -s --namespace=flux-system
   fi
 
   echo "Deleting cluster profiles and (when applicable) its cloud resources..."
@@ -1007,6 +1030,7 @@ function delete_remote_cluster() {
   rm -rf "${INFRA_CONTROLLERS_DIR}"
   rm -rf "${INFRA_CONFIGS_DIR}"
   rm -rf "${MANAGED_RESOURCES_DIR}"
+  rm -rf "${MGMT_CLUSTER_DIR}"
   rm -rf "${APPS_DIR}"
 
   # Delete base cluster Kustomizations
@@ -1094,6 +1118,459 @@ function update_crossplane_cluster() {
     "${MANIFEST_FILENAME}"
 }
 
+# Create remote CAPI cluster for Openstack
+function create_capi_openstack_cluster() {
+  local CLUSTER_KUSTOMIZATION_NAME="${1}"
+  local CLUSTER_NAME="${2}"
+  local VM_SIZE="${3}"
+  local VM_SIZE_CONTROL_PLANE="${4:-"${VM_SIZE}"}"
+  local NODE_COUNT="${5}"
+  local NODE_COUNT_CONTROLPLANE="${6:-"1"}"
+  local K8S_VERSION="${7}"
+  # OpenStack specific
+  local OPENSTACK_CLOUD_NAME="${8}"
+  local OPENSTACK_DNS_NAMESERVERS="${9}"
+  local OPENSTACK_EXTERNAL_NETWORK_ID="${10}"
+  local OPENSTACK_FAILURE_DOMAIN="${11}"
+  local OPENSTACK_SSH_KEY_NAME="${12}"
+  local CNI="${13:-"calico"}"
+  local OPENSTACK_WORKER_IMAGE_NAME="${14:-"osm-capo-node-${K8S_VERSION}"}"
+  local OPENSTACK_CONTROL_PLANE_IMAGE_NAME="${15:-"${OPENSTACK_WORKER_IMAGE_NAME}"}"
+  # SOPS-AGE related
+  local PUBLIC_KEY_MGMT="${16:-"${PUBLIC_KEY_MGMT}"}"
+  local PUBLIC_KEY_NEW_CLUSTER="${17:-"${PUBLIC_KEY_NEW_CLUSTER}"}"
+  local PRIVATE_KEY_NEW_CLUSTER="${18:-"${PRIVATE_KEY_NEW_CLUSTER}"}"
+  # GitOps retaled
+  local FLEET_REPO_DIR="${19:-"${FLEET_REPO_DIR}"}"
+  local FLEET_REPO_URL="${20:-"${FLEET_REPO_URL}"}"
+  local SW_CATALOGS_REPO_DIR="${21:-"${SW_CATALOGS_REPO_DIR}"}"
+  local SW_CATALOGS_REPO_URL="${22:-"${SW_CATALOGS_REPO_URL}"}"
+  local SKIP_BOOTSTRAP="${23:-"false"}"
+  local MGMT_PROJECT_NAME="${24:-"osm_admin"}"
+  local MGMT_CLUSTER_NAME="${25:-"_management"}"
+  local BASE_TEMPLATES_PATH="${26:-"cloud-resources/capi"}"
+  local NAMESPACE="${27:-"managed-resources"}"
+
+  # Varibles with valus from convention.
+  local CLUSTER_TYPE="openstack"
+  local TEMPLATE_MANIFEST_FILENAME="capi-cluster.yaml"
+  local MANIFEST_FILENAME="openstack-${CLUSTER_NAME}.yaml"
+  local CLOUD_CREDENTIALS="${OPENSTACK_CLOUD_NAME}-capo-config"
+
+  # Determines the source dir for the templates and the target folder in Fleet
+  local TEMPLATES_DIR="${SW_CATALOGS_REPO_DIR}/${BASE_TEMPLATES_PATH}/openstack-kubeadm/templates"
+  local TARGET_FOLDER="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/managed-resources/${MGMT_CLUSTER_NAME}"
+  export CNI=${CNI,,}
+
+  # Variables for kubeconfig secret reference
+  export CLUSTER_KUBECONFIG_SECRET_NAME="${CLUSTER_KUSTOMIZATION_NAME}-kubeconfig"
+  export CLUSTER_KUBECONFIG_SECRET_KEY="value"
+
+  export CLUSTER_KUSTOMIZATION_NAME
+  export OPENSTACK_CLOUD_NAME
+
+  folder2list \
+    "${TEMPLATES_DIR}" | \
+  replace_env_vars \
+    '${CLUSTER_KUSTOMIZATION_NAME},${CNI},${CLUSTER_KUBECONFIG_SECRET_NAME},${CLUSTER_KUBECONFIG_SECRET_KEY},${OPENSTACK_CLOUD_NAME}' | \
+  patch_replace \
+    ".spec.postBuild.substitute.cluster_name" \
+    "${CLUSTER_NAME}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.cni" \
+    "${CNI}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.control_plane_machine_count" \
+    "${NODE_COUNT_CONTROLPLANE}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.kubernetes_version" \
+    "v${K8S_VERSION}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.namespace" \
+    "${NAMESPACE}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.worker_machine_count" \
+    "${NODE_COUNT}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openstack_cloud" \
+    "${OPENSTACK_CLOUD_NAME}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openstack_cloud_conf" \
+    "${CLOUD_CREDENTIALS}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openstack_control_plane_machine_flavor" \
+    "${VM_SIZE_CONTROL_PLANE}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openstack_dns_nameservers" \
+    "${OPENSTACK_DNS_NAMESERVERS}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openstack_external_network_id" \
+    "${OPENSTACK_EXTERNAL_NETWORK_ID}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openstack_failure_domain" \
+    "${OPENSTACK_FAILURE_DOMAIN}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openstack_worker_image_name" \
+    "${OPENSTACK_WORKER_IMAGE_NAME}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openstack_control_plane_image_name" \
+    "${OPENSTACK_CONTROL_PLANE_IMAGE_NAME}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openstack_node_machine_flavor" \
+    "${VM_SIZE}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openstack_ssh_key_name" \
+    "${OPENSTACK_SSH_KEY_NAME}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  rename_file_in_items \
+    "${TEMPLATE_MANIFEST_FILENAME}" \
+    "${MANIFEST_FILENAME}" | \
+  prepend_folder_path "${CLUSTER_KUSTOMIZATION_NAME}/" | \
+  list2folder_cp_over \
+    "${TARGET_FOLDER}"
+  
+  # Bootstrap (unless asked to skip)
+  if [[ "${SKIP_BOOTSTRAP,,}" == "true" ]]; then
+    return 0
+  fi
+  
+  create_bootstrap_for_remote_cluster \
+    "${CLUSTER_NAME}" \
+    "${CLUSTER_KUSTOMIZATION_NAME}" \
+    "${FLEET_REPO_DIR}" \
+    "${SW_CATALOGS_REPO_DIR}" \
+    "${FLEET_REPO_URL}" \
+    "${SW_CATALOGS_REPO_URL}" \
+    "${MGMT_PROJECT_NAME}" \
+    "${PUBLIC_KEY_MGMT}" \
+    "${PUBLIC_KEY_NEW_CLUSTER}" \
+    "${PRIVATE_KEY_NEW_CLUSTER}" \
+    "false" \
+    '' \
+    "${CLUSTER_KUBECONFIG_SECRET_NAME}" \
+    "${CLUSTER_KUBECONFIG_SECRET_KEY}"
+
+}
+
+# Update remote CAPI cluster for Openstack
+function update_capi_openstack_cluster() {
+  local CLUSTER_KUSTOMIZATION_NAME="${1}"
+  local CLUSTER_NAME="${2}"
+  local VM_SIZE="${3}"
+  local VM_SIZE_CONTROL_PLANE="${4}"
+  local NODE_COUNT="${5}"
+  local NODE_COUNT_CONTROLPLANE="${6}"
+  local K8S_VERSION="${7}"
+  # OpenStack specific
+  local OPENSTACK_CLOUD_NAME="${8}"
+  local OPENSTACK_DNS_NAMESERVERS="${9}"
+  local OPENSTACK_EXTERNAL_NETWORK_ID="${10}"
+  local OPENSTACK_FAILURE_DOMAIN="${11}"
+  local OPENSTACK_SSH_KEY_NAME="${12}"
+  local CNI="${13:-"calico"}"
+  local OPENSTACK_WORKER_IMAGE_NAME="${14:-"osm-capo-node-${K8S_VERSION}"}"
+  local OPENSTACK_CONTROL_PLANE_IMAGE_NAME="${15:-"${OPENSTACK_WORKER_IMAGE_NAME}"}"
+  # SOPS-AGE related
+  local PUBLIC_KEY_MGMT="${16:-"${PUBLIC_KEY_MGMT}"}"
+  local PUBLIC_KEY_NEW_CLUSTER="${17:-"${PUBLIC_KEY_NEW_CLUSTER}"}"
+  local PRIVATE_KEY_NEW_CLUSTER="${18:-"${PRIVATE_KEY_NEW_CLUSTER}"}"
+  # GitOps retaled
+  local FLEET_REPO_DIR="${19:-"${FLEET_REPO_DIR}"}"
+  local FLEET_REPO_URL="${20:-"${FLEET_REPO_URL}"}"
+  local SW_CATALOGS_REPO_DIR="${21:-"${SW_CATALOGS_REPO_DIR}"}"
+  local SW_CATALOGS_REPO_URL="${22:-"${SW_CATALOGS_REPO_URL}"}"
+  local MGMT_PROJECT_NAME="${23:-"osm_admin"}"
+  local MGMT_CLUSTER_NAME="${24:-"_management"}"
+  local BASE_TEMPLATES_PATH="${25:-"cloud-resources/capi"}"
+  local NAMESPACE="${26:-"managed-resources"}"
+  
+  # Determine key folders in Fleet
+  local MGMT_RESOURCES_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/managed-resources/${MGMT_CLUSTER_NAME}"
+
+  # Updating no new cluster
+  local SKIP_BOOTSTRAP="true"
+  
+  create_capi_openstack_cluster \
+    "${CLUSTER_KUSTOMIZATION_NAME}" \
+    "${CLUSTER_NAME}" \
+    "${VM_SIZE}" \
+    "${VM_SIZE_CONTROL_PLANE}" \
+    "${NODE_COUNT}" \
+    "${NODE_COUNT_CONTROLPLANE}" \
+    "${K8S_VERSION}" \
+    "${OPENSTACK_CLOUD_NAME}" \
+    "${OPENSTACK_DNS_NAMESERVERS}" \
+    "${OPENSTACK_EXTERNAL_NETWORK_ID}" \
+    "${OPENSTACK_FAILURE_DOMAIN}" \
+    "${OPENSTACK_SSH_KEY_NAME}" \
+    "${CNI}" \
+    "${OPENSTACK_WORKER_IMAGE_NAME}" \
+    "${OPENSTACK_CONTROL_PLANE_IMAGE_NAME}" \
+    "${PUBLIC_KEY_MGMT}" \
+    "${PUBLIC_KEY_NEW_CLUSTER}" \
+    "${PRIVATE_KEY_NEW_CLUSTER}" \
+    "${FLEET_REPO_DIR}" \
+    "${FLEET_REPO_URL}" \
+    "${SW_CATALOGS_REPO_DIR}" \
+    "${SW_CATALOGS_REPO_URL}" \
+    "${SKIP_BOOTSTRAP}" \
+    "${MGMT_PROJECT_NAME}" \
+    "${MGMT_CLUSTER_NAME}" \
+    "${BASE_TEMPLATES_PATH}" \
+    "${NAMESPACE}"
+}
+
+# Create remote Openshift cluster via ACM
+function create_openshift_cluster {
+  local CLUSTER_KUSTOMIZATION_NAME="${1}"
+  local CLUSTER_NAME="${2}"
+  # This has to be void. Stored in database
+  local K8S_VERSION="${3:-"''"}"
+  # SOPS-AGE related
+  local PUBLIC_KEY_ACM="${4}"
+  local PUBLIC_KEY_NEW_CLUSTER="${5:-"${PUBLIC_KEY_NEW_CLUSTER}"}"
+  local PRIVATE_KEY_NEW_CLUSTER="${6:-"${PRIVATE_KEY_NEW_CLUSTER}"}"
+  # OpenShift
+  local OPENSHIFT_RELEASE="${7}"
+  local INFRA_PUBLIC_SSH_KEY="${8}"
+  local CONTROL_PLANE_AVAILABILITY="${9}"
+  local WORKER_COUNT="${10}"
+  local WORKER_CORES="${11}"
+  local WORKER_MEMORY="${12}"
+  local WORKER_VOLUME_SIZE="${13}"
+  local STORAGE_CLASS="${14}"
+  local BASE_DOMAIN="${15}"
+  local MGMT_CLUSTER_NAME="${16}"
+  local HOSTED_CLUSTERS_PROJECT="${17:-"clusters"}"
+  local ETCD_VOLUME_SIZE="${18:-"8"}"
+  # GitOps retaled
+  local FLEET_REPO_DIR="${19:-"${FLEET_REPO_DIR}"}"
+  local FLEET_REPO_URL="${20:-"${FLEET_REPO_URL}"}"
+  local SW_CATALOGS_REPO_DIR="${21:-"${SW_CATALOGS_REPO_DIR}"}"
+  local SW_CATALOGS_REPO_URL="${22:-"${SW_CATALOGS_REPO_URL}"}"
+  local SKIP_BOOTSTRAP="${23:-"false"}"
+   # Only change if absolutely needeed
+  local MGMT_PROJECT_NAME="${24:-"osm_admin"}"
+  local BASE_TEMPLATES_PATH="${25:-"cloud-resources"}"
+  local TEMPLATE_MANIFEST_FILENAME="${26:-"openshift01.yaml"}"
+  local MANIFEST_FILENAME="${27:-"openshift-${CLUSTER_NAME}.yaml"}"
+  
+  local TEMPLATES_DIR="${SW_CATALOGS_REPO_DIR}/cloud-resources/openshift/templates"
+  local TARGET_FOLDER="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/managed-resources/${MGMT_CLUSTER_NAME}"
+
+  # Internally ACM creates several projects for each cluster.
+  # Specifically the klusterletaddonconfig must land in a project with the same name as the cluster.
+  # This will be specifically controlled by the variable `CLUSTER_PROJECT`.
+  #
+  # It must be notes that CLUSTER_NAME, CLUSTER_KUSTOMIZATION_NAME and CLUSTER_PROJECT have the same value,
+  # but they are conceptually different.
+  local CLUSTER_PROJECT="${CLUSTER_KUSTOMIZATION_NAME}"
+
+  export CLUSTER_KUSTOMIZATION_NAME
+
+  folder2list \
+    "${TEMPLATES_DIR}" | \
+  replace_env_vars \
+    '${CLUSTER_KUSTOMIZATION_NAME}' | \
+  patch_replace \
+    ".spec.postBuild.substitute.base_domain" \
+    "${BASE_DOMAIN}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.cluster_name" \
+    "${CLUSTER_NAME}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.cluster_project" \
+    "${CLUSTER_PROJECT}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.hosted_cluster_project" \
+    "${HOSTED_CLUSTERS_PROJECT}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.etcd_volume_size" \
+    "${ETCD_VOLUME_SIZE}Gi" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.openshift_release" \
+    "${OPENSHIFT_RELEASE}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.storage_class" \
+    "${STORAGE_CLASS}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.control_plane_availability" \
+    "${CONTROL_PLANE_AVAILABILITY}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.worker_count" \
+    "${WORKER_COUNT}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.worker_cores" \
+    "${WORKER_CORES}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.worker_memory" \
+    "${WORKER_MEMORY}Gi" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.worker_volume_size" \
+    "${WORKER_VOLUME_SIZE}Gi" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}\")" | \
+  patch_replace \
+    ".spec.postBuild.substitute.cluster_project" \
+    "${CLUSTER_PROJECT}" \
+    "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${CLUSTER_KUSTOMIZATION_NAME}-ns\")" | \
+  rename_file_in_items \
+    "${TEMPLATE_MANIFEST_FILENAME}" \
+    "${MANIFEST_FILENAME}" | \
+  prepend_folder_path "${CLUSTER_KUSTOMIZATION_NAME}/" | \
+  list2folder_cp_over \
+    "${TARGET_FOLDER}"
+
+  echo "" | \
+  make_generator \
+    "pull-secret.yaml" \
+    kubectl_encrypt \
+      "${PUBLIC_KEY_ACM}" \
+      create \
+      secret \
+      generic \
+      "pullsecret-cluster-${CLUSTER_NAME}" \
+      --namespace="${HOSTED_CLUSTERS_PROJECT}" \
+      --from-file=".dockerconfigjson"=<(echo "${DOCKERCONFIGJSON}") \
+      -o=yaml \
+      --dry-run=client | \
+  make_generator \
+    "ssh-key-secret.yaml" \
+    kubectl_encrypt \
+      "${PUBLIC_KEY_ACM}" \
+      create \
+      secret \
+      generic \
+      "sshkey-cluster-${CLUSTER_NAME}" \
+      --namespace="${HOSTED_CLUSTERS_PROJECT}" \
+      --from-file='id_rsa.pub'=<(echo "${INFRA_PUBLIC_SSH_KEY}") \
+      -o=yaml \
+      --dry-run=client | \
+  list2folder_cp_over \
+    "${TARGET_FOLDER}/${CLUSTER_KUSTOMIZATION_NAME}"
+
+  # Bootstrap (unless asked to skip)
+  if [[ "${SKIP_BOOTSTRAP,,}" == "true" ]]; then
+    return 0
+  fi
+
+  local CLUSTER_KUBECONFIG_SECRET_NAME="${CLUSTER_KUSTOMIZATION_NAME}-admin-kubeconfig"
+  local CLUSTER_KUBECONFIG_SECRET_KEY="kubeconfig"
+  local BOOTSTRAP_KUSTOMIZATION_NAMESPACE="${HOSTED_CLUSTERS_PROJECT}"
+  local CLUSTER_KUSTOMIZATION_NAMESPACE="managed-resources"
+  local BOOTSTRAP_SECRET_NAMESPACE="managed-resources"
+
+  create_bootstrap_for_remote_cluster \
+    "${CLUSTER_NAME}" \
+    "${CLUSTER_KUSTOMIZATION_NAME}" \
+    "${FLEET_REPO_DIR}" \
+    "${SW_CATALOGS_REPO_DIR}" \
+    "${FLEET_REPO_URL}" \
+    "${SW_CATALOGS_REPO_URL}" \
+    "${MGMT_PROJECT_NAME}" \
+    "${PUBLIC_KEY_ACM}" \
+    "${PUBLIC_KEY_NEW_CLUSTER}" \
+    "${PRIVATE_KEY_NEW_CLUSTER}" \
+    "false" \
+    "${MGMT_CLUSTER_NAME}" \
+    "${CLUSTER_KUBECONFIG_SECRET_NAME}" \
+    "${CLUSTER_KUBECONFIG_SECRET_KEY}" \
+    "${SW_CATALOGS_REPO_DIR}/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates" \
+    "${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}" \
+    "${CLUSTER_KUSTOMIZATION_NAMESPACE}" \
+    "${BOOTSTRAP_SECRET_NAMESPACE}"
+
+}
+
+# Update remote Openshift cluster via ACM
+function update_openshift_cluster {
+  local CLUSTER_KUSTOMIZATION_NAME="${1}"
+  local CLUSTER_NAME="${2}"
+  # This has to be void. Stored in database
+  local K8S_VERSION="${3:-"''"}"
+  # SOPS-AGE related
+  local PUBLIC_KEY_ACM="${4}"
+  local PUBLIC_KEY_NEW_CLUSTER="${5:-"${PUBLIC_KEY_NEW_CLUSTER}"}"
+  local PRIVATE_KEY_NEW_CLUSTER="${6:-"${PRIVATE_KEY_NEW_CLUSTER}"}"
+  # OpenShift specific
+  local OPENSHIFT_RELEASE="${7}"
+  local INFRA_PUBLIC_SSH_KEY="${8}"
+  local CONTROL_PLANE_AVAILABILITY="${9}"
+  local WORKER_COUNT="${10}"
+  local WORKER_CORES="${11}"
+  local WORKER_MEMORY="${12}"
+  local WORKER_VOLUME_SIZE="${13}"
+  local STORAGE_CLASS="${14}"
+  local BASE_DOMAIN="${15}"
+  local MGMT_CLUSTER_NAME="${16}"
+  local HOSTED_CLUSTERS_PROJECT="${17:-"clusters"}"
+  local ETCD_VOLUME_SIZE="${18:-"8"}"
+  # GitOps retaled
+  local FLEET_REPO_DIR="${19:-"${FLEET_REPO_DIR}"}"
+  local FLEET_REPO_URL="${20:-"${FLEET_REPO_URL}"}"
+  local SW_CATALOGS_REPO_DIR="${21:-"${SW_CATALOGS_REPO_DIR}"}"
+  local SW_CATALOGS_REPO_URL="${22:-"${SW_CATALOGS_REPO_URL}"}"
+  local SKIP_BOOTSTRAP="${23:-"false"}"
+   # Only change if absolutely needeed
+  local MGMT_PROJECT_NAME="${24:-"osm_admin"}"
+  
+  # Determine key folders in Fleet
+  local MGMT_RESOURCES_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/managed-resources/${MGMT_CLUSTER_NAME}"
+
+  # Updating no new cluster
+  local SKIP_BOOTSTRAP="true"
+
+  create_openshift_cluster \
+    "${CLUSTER_KUSTOMIZATION_NAME}" \
+    "${CLUSTER_NAME}" \
+    "${K8S_VERSION}" \
+    "${PUBLIC_KEY_ACM}" \
+    "${PUBLIC_KEY_NEW_CLUSTER}" \
+    "${PRIVATE_KEY_NEW_CLUSTER}" \
+    "${OPENSHIFT_RELEASE}" \
+    "${INFRA_PUBLIC_SSH_KEY}" \
+    "${CONTROL_PLANE_AVAILABILITY}" \
+    "${WORKER_COUNT}" \
+    "${WORKER_CORES}" \
+    "${WORKER_MEMORY}" \
+    "${WORKER_VOLUME_SIZE}" \
+    "${STORAGE_CLASS}" \
+    "${BASE_DOMAIN}" \
+    "${MGMT_CLUSTER_NAME}" \
+    "${HOSTED_CLUSTERS_PROJECT}" \
+    "${ETCD_VOLUME_SIZE}" \
+    "${FLEET_REPO_DIR}" \
+    "${FLEET_REPO_URL}" \
+    "${SW_CATALOGS_REPO_DIR}" \
+    "${SW_CATALOGS_REPO_URL}" \
+    "${SKIP_BOOTSTRAP}" \
+    "${MGMT_PROJECT_NAME}"
+}
 
 # ----- Helper functions for adding/removing a profile from a cluster -----
 
@@ -2186,6 +2663,91 @@ function update_crossplane_providerconfig() {
 }
 
 
+# Create a CloudConfig for CAPI provider
+function create_capi_openstack_cloudconf() {
+  local OPENSTACK_CLOUD_NAME="${1}"
+  local PUBLIC_KEY="${2:-"${PUBLIC_KEY_MGMT}"}"
+  local CONFIG_DIR="${3:-"${MGMT_ADDON_CONFIG_DIR}"}"
+
+  local NAMESPACE="managed-resources"
+
+  local CLOUDS_YAML="${OPENSTACK_CLOUDS_YAML}"
+  local CACERT="${OPENSTACK_CACERT}"
+
+  local CLOUD_CREDENTIALS_SECRET_NAME="${OPENSTACK_CLOUD_NAME}-capo-config"
+  local CLOUD_CREDENTIALS_CLOUDS_KEY="clouds.yaml"
+  local CLOUD_CREDENTIALS_CACERT_KEY="cacert"
+  local CLOUD_CREDENTIALS_FILENAME="credentials-secret.yaml"
+  
+  local CLOUD_CREDENTIALS_TOML_SECRET_NAME="${OPENSTACK_CLOUD_NAME}-capo-config-toml"
+  local CLOUD_CREDENTIALS_TOML_FILENAME="credentials-toml-secret.yaml"
+
+  local TARGET_FOLDER="${CONFIG_DIR}/capi-providerconfigs/capo/${OPENSTACK_CLOUD_NAME}-config"
+  mkdir -p "${TARGET_FOLDER}"
+
+  echo "" | \
+  make_generator \
+    "${CLOUD_CREDENTIALS_FILENAME}" \
+    kubectl_encrypt \
+      "${PUBLIC_KEY}" \
+      create \
+      secret \
+      generic \
+      "${CLOUD_CREDENTIALS_SECRET_NAME}" \
+      --namespace="${NAMESPACE}" \
+      --from-file="${CLOUD_CREDENTIALS_CLOUDS_KEY}"=<(echo "${CLOUDS_YAML}") \
+      --from-file="${CLOUD_CREDENTIALS_CACERT_KEY}"=<(echo "${CACERT}") \
+      -o=yaml \
+      --dry-run=client | \
+  make_generator \
+    "${CLOUD_CREDENTIALS_TOML_FILENAME}" \
+    kubectl_encrypt \
+      "${PUBLIC_KEY}" \
+      create \
+      secret \
+      generic \
+      "${CLOUD_CREDENTIALS_TOML_SECRET_NAME}" \
+      --namespace="${NAMESPACE}" \
+      --from-file="os_auth_url"=<(echo "${OS_AUTH_URL}") \
+      --from-file="os_region_name"=<(echo "${OS_REGION_NAME}") \
+      --from-file="os_username"=<(echo "${OS_USERNAME}") \
+      --from-file="os_password"=<(echo "${OS_PASSWORD}") \
+      --from-file="os_project_id"=<(echo "${OS_PROJECT_ID}") \
+      --from-file="os_project_domain_id"=<(echo "${OS_PROJECT_DOMAIN_ID}") \
+      -o=yaml \
+      --dry-run=client | \
+  list2folder_cp_over \
+    "${TARGET_FOLDER}"
+}
+
+# Update a CloudConfig for CAPI provider
+function update_capi_openstack_cloudconf() {
+  local CLOUD_CONFIG_NAME="${1}"
+  local PUBLIC_KEY="${2:-"${PUBLIC_KEY_MGMT}"}"
+  local CONFIG_DIR="${3:-"${MGMT_ADDON_CONFIG_DIR}"}"
+
+  delete_capi_openstack_cloudconf \
+    "${CLOUD_CONFIG_NAME}" \
+    "${CONFIG_DIR}"
+  
+  create_capi_openstack_cloudconf \
+    "${CLOUD_CONFIG_NAME}" \
+    "${PUBLIC_KEY}" \
+    "${CONFIG_DIR}"
+}
+
+
+# Delete a CloudConfig for CAPI provider
+function delete_capi_openstack_cloudconf() {
+  local OPENSTACK_CLOUD_NAME="$1"
+  local CONFIG_DIR="${2:-"${MGMT_ADDON_CONFIG_DIR}"}"
+
+  local TARGET_FOLDER="${CONFIG_DIR}/capi-providerconfigs/capo/${OPENSTACK_CLOUD_NAME}-config"
+  
+  # Delete the encrypted secrets files.
+  rm -rf "${TARGET_FOLDER}"
+}
+
 # Helper function to return the relative path of a location in SW Catalogs for an OKA
 function path_to_catalog() {
   local OKA_TYPE="$1"
index fa1fb0a..9afcf70 100644 (file)
@@ -44,3 +44,6 @@ export KUBECONFIG_AUX_CLUSTER=
 export KUBECONFIG_MGMT_CLUSTER=
 export KUBECONFIG_OSM_CLUSTER=
 export OSM_BEHIND_PROXY=
+export OPENSHIFT_MGMT_CLUSTER=
+export MGMT_CLUSTER_CA_FILE=
+export OSM_K8S_NGINX_IPADDRESS=
\ No newline at end of file
index 963c924..2aca744 100755 (executable)
@@ -60,6 +60,9 @@ export KUBECONFIG_AUX_CLUSTER=${KUBECONFIG_AUX_CLUSTER}
 export KUBECONFIG_MGMT_CLUSTER=${KUBECONFIG_MGMT_CLUSTER}
 export KUBECONFIG_OSM_CLUSTER=${KUBECONFIG_OSM_CLUSTER}
 export OSM_BEHIND_PROXY=${OSM_BEHIND_PROXY}
+export OPENSHIFT_MGMT_CLUSTER=${OPENSHIFT_MGMT_CLUSTER}
+export MGMT_CLUSTER_CA_FILE=${MGMT_CLUSTER_CA_FILE}
+export OSM_K8S_NGINX_IPADDRESS=${OSM_K8S_NGINX_IPADDRESS}
 EOF
 
 cat "${OSM_HOME_DIR}/user-install-options.rc"
index 8e1d1ea..34d7d06 100755 (executable)
@@ -26,7 +26,6 @@ source "${HERE}/00-default-install-options.rc"
 source "${CREDENTIALS_DIR}/git_environment.rc"
 
 OSM_HELM_WORK_DIR="/etc/osm/helm"
-OSM_K8S_EXTERNAL_IP=${OSM_K8S_EXTERNAL_IP:-""}
 KUBECONFIG_AUX_CLUSTER_FILE="${OSM_HOME_DIR}/clusters/kubeconfig-aux-svc.yaml"
 KUBECONFIG_MGMT_CLUSTER_FILE="${OSM_HOME_DIR}/clusters/kubeconfig-mgmt.yaml"
 [ "${HERE}" == "/usr/share/osm-devops/installers" ] || OSM_HELM_UPDATE_DEPENDENCIES="y"
@@ -41,19 +40,30 @@ else
 fi
 
 export KUBECONFIG="${OSM_HOME_DIR}/clusters/kubeconfig-osm.yaml"
+if [ -z "${OSM_K8S_NGINX_IPADDRESS}" ]; then
+    echo "OSM_K8S_NGINX_IPADDRESS is not set, will try to get it from the cluster"
+    OSM_K8S_NGINX_IPADDRESS=$(kubectl get svc ingress-nginx-controller -n ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null)
+fi
+echo "Using OSM_K8S_NGINX_IPADDRESS=${OSM_K8S_NGINX_IPADDRESS}"
 
 # Create folder to store helm values
 sudo mkdir -p ${OSM_HELM_WORK_DIR}
 
 # Saving secrets
 echo "Creating namespace ${OSM_NAMESPACE}"
-kubectl create ns ${OSM_NAMESPACE}
+kubectl get ns "${OSM_NAMESPACE}" >/dev/null 2>&1 || kubectl create ns "${OSM_NAMESPACE}"
 echo "Saving age keys in OSM cluster"
+kubectl -n ${OSM_NAMESPACE} get secret mgmt-cluster-age-keys >/dev/null 2>&1 || \
 kubectl -n ${OSM_NAMESPACE} create secret generic mgmt-cluster-age-keys --from-file=privkey="${CREDENTIALS_DIR}/age.mgmt.key" --from-file=pubkey="${CREDENTIALS_DIR}/age.mgmt.pub"
 echo "Creating secrets with kubeconfig files"
-kubectl -n ${OSM_NAMESPACE} create secret generic auxcluster-secret --from-file=kubeconfig="${KUBECONFIG_AUX_CLUSTER_FILE}"
-kubectl -n ${OSM_NAMESPACE} create secret generic mgmtcluster-secret --from-file=kubeconfig="${KUBECONFIG_MGMT_CLUSTER_FILE}"
-
+if [ -f "${KUBECONFIG_AUX_CLUSTER_FILE}" ]; then
+    kubectl -n ${OSM_NAMESPACE} get secret auxcluster-secret >/dev/null 2>&1 || \
+    kubectl -n ${OSM_NAMESPACE} create secret generic auxcluster-secret --from-file=kubeconfig="${KUBECONFIG_AUX_CLUSTER_FILE}"
+fi
+if [ -f "${KUBECONFIG_MGMT_CLUSTER_FILE}" ]; then
+    kubectl -n ${OSM_NAMESPACE} get secret mgmtcluster-secret >/dev/null 2>&1 || \
+    kubectl -n ${OSM_NAMESPACE} create secret generic mgmtcluster-secret --from-file=kubeconfig="${KUBECONFIG_MGMT_CLUSTER_FILE}"
+fi
 # Update helm dependencies
 [ -n "${OSM_HELM_UPDATE_DEPENDENCIES}" ] && \
     echo "Updating helm dependencies" && \
@@ -69,10 +79,11 @@ OSM_HELM_OPTS="${OSM_HELM_OPTS} --set global.image.repositoryBase=${DOCKER_REGIS
 [ ! "$OSM_DOCKER_TAG" == "testing-daily" ] && OSM_HELM_OPTS="${OSM_HELM_OPTS} --set-string global.image.tag=${OSM_DOCKER_TAG}"
 [ ! "$OSM_DOCKER_TAG" == "testing-daily" ] && OSM_HELM_OPTS="${OSM_HELM_OPTS} --set prometheus.server.sidecarContainers.prometheus-config-sidecar.image=${DOCKER_REGISTRY_URL}${DOCKER_USER}/prometheus:${OSM_DOCKER_TAG}"
 
-OSM_HELM_OPTS="${OSM_HELM_OPTS} --set global.hostname=${OSM_K8S_EXTERNAL_IP}.nip.io"
-OSM_HELM_OPTS="${OSM_HELM_OPTS} --set grafana.ingress.hosts={grafana.${OSM_K8S_EXTERNAL_IP}.nip.io}"
-OSM_HELM_OPTS="${OSM_HELM_OPTS} --set prometheus.server.ingress.hosts={prometheus.${OSM_K8S_EXTERNAL_IP}.nip.io}"
-# OSM_HELM_OPTS="${OSM_HELM_OPTS} --set prometheus.alertmanager.ingress.hosts={alertmanager.${OSM_K8S_EXTERNAL_IP}.nip.io}"
+OSM_BASE_DOMAIN="${OSM_BASE_DOMAIN:-"${OSM_K8S_NGINX_IPADDRESS}.nip.io"}"
+OSM_HELM_OPTS="${OSM_HELM_OPTS} --set global.hostname=${OSM_BASE_DOMAIN}"
+OSM_HELM_OPTS="${OSM_HELM_OPTS} --set grafana.ingress.hosts={grafana.${OSM_BASE_DOMAIN}}"
+OSM_HELM_OPTS="${OSM_HELM_OPTS} --set prometheus.server.ingress.hosts={prometheus.${OSM_BASE_DOMAIN}}"
+# OSM_HELM_OPTS="${OSM_HELM_OPTS} --set prometheus.alertmanager.ingress.hosts={alertmanager.${OSM_BASE_DOMAIN}}"
 if [ -z "${OSM_GITOPS_ENABLED}" ]; then
     OSM_HELM_OPTS="${OSM_HELM_OPTS} --set global.gitops.enabled=false"
 else
@@ -117,7 +128,7 @@ set -e
 
 echo -e "Saving OSM enviroment to credentials folder..."
 OSM_HOSTNAME=$(kubectl get --namespace osm -o jsonpath="{.spec.rules[0].host}" ingress nbi-ingress)
-# OSM_HOSTNAME="nbi.${OSM_K8S_EXTERNAL_IP}.nip.io:443"
+# OSM_HOSTNAME="nbi.${OSM_BASE_DOMAIN}:443"
 echo -e "OSM HOSTNAME: ${OSM_HOSTNAME}"
 
 cat << EOF > "${CREDENTIALS_DIR}/osm_environment.rc"
index ef1b0cb..1ea1ded 100755 (executable)
@@ -111,17 +111,31 @@ envsubst < "${TEMPLATES_DIR}/sw-catalogs-repo.yaml" > "${CLUSTER_DIR}/sw-catalog
 # Secrets to access both Git repos
 # (NOTE: these are the last secrets to be added imperatively)
 kubectl delete secret fleet-repo --namespace flux-system 2> /dev/null || true
-kubectl create secret generic fleet-repo \
-    --namespace flux-system \
-    --from-literal=username="${FLEET_REPO_GIT_USERNAME}" \
-    --from-literal=password="${FLEET_REPO_GIT_USER_PASS}"
-
+if [ -n "${MGMT_CLUSTER_CA_FILE}" ]; then
+    kubectl create secret generic fleet-repo \
+        --namespace flux-system \
+        --from-literal=username="${FLEET_REPO_GIT_USERNAME}" \
+        --from-literal=password="${FLEET_REPO_GIT_USER_PASS}" \
+        --from-file=ca.crt="${MGMT_CLUSTER_CA_FILE}"
+else
+    kubectl create secret generic fleet-repo \
+        --namespace flux-system \
+        --from-literal=username="${FLEET_REPO_GIT_USERNAME}" \
+        --from-literal=password="${FLEET_REPO_GIT_USER_PASS}"
+fi
 kubectl delete secret sw-catalogs --namespace flux-system 2> /dev/null || true
-kubectl create secret generic sw-catalogs \
-    --namespace flux-system \
-    --from-literal=username="${SW_CATALOGS_REPO_GIT_USERNAME}" \
-    --from-literal=password="${SW_CATALOGS_REPO_GIT_USER_PASS}"
-
+if [ -n "${MGMT_CLUSTER_CA_FILE}" ]; then
+    kubectl create secret generic sw-catalogs \
+        --namespace flux-system \
+        --from-literal=username="${SW_CATALOGS_REPO_GIT_USERNAME}" \
+        --from-literal=password="${SW_CATALOGS_REPO_GIT_USER_PASS}" \
+        --from-file=ca.crt="${MGMT_CLUSTER_CA_FILE}"
+else
+    kubectl create secret generic sw-catalogs \
+        --namespace flux-system \
+        --from-literal=username="${SW_CATALOGS_REPO_GIT_USERNAME}" \
+        --from-literal=password="${SW_CATALOGS_REPO_GIT_USER_PASS}"
+fi
 # Render Flux `Kustomizations` to sync with default profiles
 envsubst < "${TEMPLATES_DIR}/infra-controllers.yaml" > "${CLUSTER_DIR}/infra-controllers.yaml"
 envsubst < "${TEMPLATES_DIR}/infra-configs.yaml" > "${CLUSTER_DIR}/infra-configs.yaml"
index c4aa0fc..2917a5a 100755 (executable)
@@ -23,17 +23,49 @@ source "${HERE}/library/functions.sh"
 source "${HERE}/library/trap.sh"
 
 
+# Preparation for Openshift
+if [ -n "${OPENSHIFT_MGMT_CLUSTER}" ]; then
+  m "Detected OpenShift management cluster, initilializing flux with SCC..." "${GREEN}"
+  # Preparation for Openshift
+  pushd "${FLEET_REPO_DIR}" > /dev/null
+  FLUX_SYSTEM_DIR="clusters/_management/flux-system"
+  FLUX_SYSTEM_SW_CATALOG_DIR="${HERE}/../templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/flux-system"
+  mkdir -p "${FLUX_SYSTEM_DIR}"
+  touch "${FLUX_SYSTEM_DIR}/gotk-components.yaml"
+  touch "${FLUX_SYSTEM_DIR}/gotk-sync.yaml"
+  cp "${FLUX_SYSTEM_SW_CATALOG_DIR}/scc.yaml" "${FLUX_SYSTEM_DIR}"
+  cp "${FLUX_SYSTEM_SW_CATALOG_DIR}/kustomization.yaml" "${FLUX_SYSTEM_DIR}"
+  # git status
+  git add -A
+  git commit -m "init flux"
+  git pull origin main
+  git push -u origin main
+  popd > /dev/null
+fi
+
 # Bootstrap
 GIT_PATH=./clusters/_management
 GIT_BRANCH=main
-flux bootstrap git \
-    --url=${FLEET_REPO_HTTP_URL} \
-    --allow-insecure-http=true \
-    --username=${FLEET_REPO_GIT_USERNAME} \
-    --password="${FLEET_REPO_GIT_USER_PASS}" \
-    --token-auth=true \
-    --branch=${GIT_BRANCH} \
-    --path=${GIT_PATH}
+if [ -n "${MGMT_CLUSTER_CA_FILE}" ]; then
+    flux bootstrap git \
+        --url=${FLEET_REPO_HTTP_URL} \
+        --allow-insecure-http=true \
+        --username=${FLEET_REPO_GIT_USERNAME} \
+        --password="${FLEET_REPO_GIT_USER_PASS}" \
+        --token-auth=true \
+        --branch=${GIT_BRANCH} \
+        --ca-file=${MGMT_CLUSTER_CA_FILE} \
+        --path=${GIT_PATH}
+else
+    flux bootstrap git \
+        --url=${FLEET_REPO_HTTP_URL} \
+        --allow-insecure-http=true \
+        --username=${FLEET_REPO_GIT_USERNAME} \
+        --password="${FLEET_REPO_GIT_USER_PASS}" \
+        --token-auth=true \
+        --branch=${GIT_BRANCH} \
+        --path=${GIT_PATH}
+fi
 
 # Check if successful
 flux check
index d138660..e533cfa 100644 (file)
@@ -28,7 +28,7 @@ apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
 kind: Kustomization
 metadata:
   name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-ns
-  namespace: managed-resources
+  namespace: ${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}
   labels:
     cluster: ${CLUSTER_KUSTOMIZATION_NAME}
 spec:
@@ -38,6 +38,7 @@ spec:
   timeout: 5m
   dependsOn:
     - name: ${CLUSTER_KUSTOMIZATION_NAME}
+      namespace: ${CLUSTER_KUSTOMIZATION_NAMESPACE}
   prune: true
   # wait: true
   # force: true
@@ -48,8 +49,8 @@ spec:
   path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/namespaces
   kubeConfig:
     secretRef:
-      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
-      key: kubeconfig
+      name: ${CLUSTER_KUBECONFIG_SECRET_NAME}
+      key: ${CLUSTER_KUBECONFIG_SECRET_KEY}
 
 ---
 # Creates remote `flux-system.flux-system` secret
@@ -57,7 +58,7 @@ apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
 kind: Kustomization
 metadata:
   name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-flux
-  namespace: managed-resources
+  namespace: ${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}
   labels:
     cluster: ${CLUSTER_KUSTOMIZATION_NAME}
 spec:
@@ -77,8 +78,8 @@ spec:
   path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
   kubeConfig:
     secretRef:
-      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
-      key: kubeconfig
+      name: ${CLUSTER_KUBECONFIG_SECRET_NAME}
+      key: ${CLUSTER_KUBECONFIG_SECRET_KEY}
   patches:
     - patch: |-
         apiVersion: v1
@@ -98,13 +99,60 @@ spec:
       - kind: Secret
         name: flux-system
 
+---
+# Creates remote `flux-system.managed-resources` secret
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-managedresources-flux
+  namespace: ${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  # interval: 1h
+  interval: 5m
+  retryInterval: 1m
+  timeout: 5m
+  dependsOn:
+    - name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-ns
+  prune: true
+  # wait: true
+  force: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
+  kubeConfig:
+    secretRef:
+      name: ${CLUSTER_KUBECONFIG_SECRET_NAME}
+      key: ${CLUSTER_KUBECONFIG_SECRET_KEY}
+  patches:
+    - patch: |-
+        apiVersion: v1
+        kind: Secret
+        metadata:
+          name: ${secret_name}
+          namespace: ${secret_namespace}
+        stringData:
+          username: ${username}
+          password: ${password}
+  # Inputs:
+  postBuild:
+    substitute:
+      secret_name: flux-system
+      secret_namespace: ${BOOTSTRAP_SECRET_NAMESPACE}
+    substituteFrom:
+      - kind: Secret
+        name: flux-system
+
 ---
 # Creates remote `sops-age` secret
 apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
 kind: Kustomization
 metadata:
   name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-sops
-  namespace: managed-resources
+  namespace: ${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}
   labels:
     cluster: ${CLUSTER_KUSTOMIZATION_NAME}
 spec:
@@ -124,8 +172,8 @@ spec:
   path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
   kubeConfig:
     secretRef:
-      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
-      key: kubeconfig
+      name: ${CLUSTER_KUBECONFIG_SECRET_NAME}
+      key: ${CLUSTER_KUBECONFIG_SECRET_KEY}
   patches:
     - patch: |-
         apiVersion: v1
@@ -150,7 +198,7 @@ apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
 kind: Kustomization
 metadata:
   name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-fleet
-  namespace: managed-resources
+  namespace: ${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}
   labels:
     cluster: ${CLUSTER_KUSTOMIZATION_NAME}
 spec:
@@ -170,8 +218,8 @@ spec:
   path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
   kubeConfig:
     secretRef:
-      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
-      key: kubeconfig
+      name: ${CLUSTER_KUBECONFIG_SECRET_NAME}
+      key: ${CLUSTER_KUBECONFIG_SECRET_KEY}
   patches:
     - patch: |-
         apiVersion: v1
@@ -191,13 +239,60 @@ spec:
       - kind: Secret
         name: fleet-repo
 
+---
+# Creates remote `fleet-repo.managed-resources` secret
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-managedresources-fleet
+  namespace: ${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  # interval: 1h
+  interval: 5m
+  retryInterval: 1m
+  timeout: 5m
+  dependsOn:
+    - name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-ns
+  prune: true
+  # wait: true
+  force: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
+  kubeConfig:
+    secretRef:
+      name: ${CLUSTER_KUBECONFIG_SECRET_NAME}
+      key: ${CLUSTER_KUBECONFIG_SECRET_KEY}
+  patches:
+    - patch: |-
+        apiVersion: v1
+        kind: Secret
+        metadata:
+          name: ${secret_name}
+          namespace: ${secret_namespace}
+        stringData:
+          username: ${username}
+          password: ${password}
+  # Inputs:
+  postBuild:
+    substitute:
+      secret_name: fleet-repo
+      secret_namespace: ${BOOTSTRAP_SECRET_NAMESPACE}
+    substituteFrom:
+      - kind: Secret
+        name: fleet-repo
+
 ---
 # Creates remote `sw-catalogs.flux-system` secret
 apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
 kind: Kustomization
 metadata:
   name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-catalogs
-  namespace: managed-resources
+  namespace: ${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}
   labels:
     cluster: ${CLUSTER_KUSTOMIZATION_NAME}
 spec:
@@ -217,8 +312,8 @@ spec:
   path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
   kubeConfig:
     secretRef:
-      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
-      key: kubeconfig
+      name: ${CLUSTER_KUBECONFIG_SECRET_NAME}
+      key: ${CLUSTER_KUBECONFIG_SECRET_KEY}
   patches:
     - patch: |-
         apiVersion: v1
@@ -238,13 +333,60 @@ spec:
       - kind: Secret
         name: sw-catalogs
 
+---
+# Creates remote `sw-catalogs.managed-resources` secret
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-managedresources-catalogs
+  namespace: ${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  # interval: 1h
+  interval: 5m
+  retryInterval: 1m
+  timeout: 5m
+  dependsOn:
+    - name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-ns
+  prune: true
+  # wait: true
+  force: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
+  kubeConfig:
+    secretRef:
+      name: ${CLUSTER_KUBECONFIG_SECRET_NAME}
+      key: ${CLUSTER_KUBECONFIG_SECRET_KEY}
+  patches:
+    - patch: |-
+        apiVersion: v1
+        kind: Secret
+        metadata:
+          name: ${secret_name}
+          namespace: ${secret_namespace}
+        stringData:
+          username: ${username}
+          password: ${password}
+  # Inputs:
+  postBuild:
+    substitute:
+      secret_name: sw-catalogs
+      secret_namespace: ${BOOTSTRAP_SECRET_NAMESPACE}
+    substituteFrom:
+      - kind: Secret
+        name: sw-catalogs
+
 ---
 # Remote installation of Flux controller (to let the cluster be autonomous)
 apiVersion: kustomize.toolkit.fluxcd.io/v1
 kind: Kustomization
 metadata:
   name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-fluxctrl
-  namespace: managed-resources
+  namespace: ${BOOTSTRAP_KUSTOMIZATION_NAMESPACE}
   labels:
     cluster: ${CLUSTER_KUSTOMIZATION_NAME}
 spec:
@@ -261,5 +403,5 @@ spec:
     namespace: flux-system
   kubeConfig:
     secretRef:
-      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
-      key: kubeconfig
+      name: ${CLUSTER_KUBECONFIG_SECRET_NAME}
+      key: ${CLUSTER_KUBECONFIG_SECRET_KEY}
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/apps.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/apps.yaml
new file mode 100644 (file)
index 0000000..607b8c9
--- /dev/null
@@ -0,0 +1,41 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: apps
+  namespace: flux-system
+  labels:
+    osm_profile_type: apps
+spec:
+  interval: 10m0s
+  dependsOn:
+    - name: infra-configs
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${APPS_PATH}
+  prune: true
+  wait: true
+  timeout: 5m0s
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/fleet-repo.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/fleet-repo.yaml
new file mode 100644 (file)
index 0000000..4f70cd7
--- /dev/null
@@ -0,0 +1,30 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: GitRepository
+metadata:
+  name: fleet-repo
+  namespace: flux-system
+spec:
+  interval: 1m0s
+  ref:
+    branch: main
+  secretRef:
+    name: fleet-repo
+  url: ${FLEET_REPO_URL}
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/flux-system/gotk-sync.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/flux-system/gotk-sync.yaml
new file mode 100644 (file)
index 0000000..4346fee
--- /dev/null
@@ -0,0 +1,44 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# This manifest was generated by flux. DO NOT EDIT.
+---
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: GitRepository
+metadata:
+  name: flux-system
+  namespace: flux-system
+spec:
+  interval: 1m0s
+  ref:
+    branch: main
+  secretRef:
+    name: flux-system
+  url: ${FLEET_REPO_URL}
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: flux-system
+  namespace: flux-system
+spec:
+  interval: 10m0s
+  path: ./clusters/${CLUSTER_KUSTOMIZATION_NAME}
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: flux-system
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/flux-system/kustomization.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/flux-system/kustomization.yaml
new file mode 100644 (file)
index 0000000..c923e88
--- /dev/null
@@ -0,0 +1,51 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+resources:
+  - gotk-components.yaml
+  - gotk-sync.yaml
+  - scc.yaml
+patches:
+  - patch: |
+      apiVersion: apps/v1
+      kind: Deployment
+      metadata:
+        name: all
+      spec:
+        template:
+          spec:
+            securityContext:
+              $patch: delete
+            containers:
+              - name: manager
+                securityContext:
+                  runAsUser: 65534
+                  seccompProfile:
+                    $patch: delete
+    target:
+      kind: Deployment
+      labelSelector: app.kubernetes.io/part-of=flux
+  - patch: |-
+      - op: remove
+        path: /metadata/labels/pod-security.kubernetes.io~1warn
+      - op: remove
+        path: /metadata/labels/pod-security.kubernetes.io~1warn-version
+    target:
+      kind: Namespace
+      labelSelector: app.kubernetes.io/part-of=flux
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/flux-system/scc.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/flux-system/scc.yaml
new file mode 100644 (file)
index 0000000..6522067
--- /dev/null
@@ -0,0 +1,60 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Allow Flux controllers to run as non-root on OpenShift
+# Docs: https://fluxcd.io/flux/installation/configuration/openshift/
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: flux-scc
+rules:
+  - apiGroups:
+      - security.openshift.io
+    resources:
+      - securitycontextconstraints
+    resourceNames:
+      - nonroot
+    verbs:
+      - use
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: flux-scc
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: flux-scc
+subjects:
+  - kind: ServiceAccount
+    name: source-controller
+    namespace: flux-system
+  - kind: ServiceAccount
+    name: kustomize-controller
+    namespace: flux-system
+  - kind: ServiceAccount
+    name: helm-controller
+    namespace: flux-system
+  - kind: ServiceAccount
+    name: notification-controller
+    namespace: flux-system
+  - kind: ServiceAccount
+    name: image-reflector-controller
+    namespace: flux-system
+  - kind: ServiceAccount
+    name: image-automation-controller
+    namespace: flux-system
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/infra-configs.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/infra-configs.yaml
new file mode 100644 (file)
index 0000000..d2879eb
--- /dev/null
@@ -0,0 +1,49 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: infra-configs
+  namespace: flux-system
+  labels:
+    osm_profile_type: infra-configs
+spec:
+  dependsOn:
+    - name: infra-controllers
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${INFRA_CONFIGS_PATH}
+  prune: true
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
+  # patches:
+  #   - patch: |
+  #       - op: replace
+  #         path: /spec/acme/server
+  #         value: https://acme-v02.api.letsencrypt.org/directory
+  #     target:
+  #       kind: ClusterIssuer
+  #       name: letsencrypt
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/infra-controllers.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/infra-controllers.yaml
new file mode 100644 (file)
index 0000000..671afc8
--- /dev/null
@@ -0,0 +1,40 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: infra-controllers
+  namespace: flux-system
+  labels:
+    osm_profile_type: infra-controllers
+spec:
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${INFRA_CONTROLLERS_PATH}
+  prune: true
+  wait: true
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/kustomization.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/kustomization.yaml
new file mode 100644 (file)
index 0000000..6e3c9af
--- /dev/null
@@ -0,0 +1,36 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+resources:
+  # Repos
+  - fleet-repo.yaml
+  - sw-catalogs-repo.yaml
+
+  # Base cluster structure (CRDs, operators and their configs)
+  - infra-controllers.yaml
+  - infra-configs.yaml
+
+  # Managed resources
+  - managed-resources.yaml
+
+  # Managed apps
+  - apps.yaml
+
+  # Adds also the `flux-system` folder to preserve bootstrap structure
+  - flux-system
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/managed-resources.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/managed-resources.yaml
new file mode 100644 (file)
index 0000000..2d59cc9
--- /dev/null
@@ -0,0 +1,52 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Namespace
+# apiVersion: v1
+# kind: Namespace
+# metadata:
+#   name: managed-resources
+
+---
+# Managed resources
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: managed-resources
+  namespace: flux-system
+  labels:
+    osm_profile_type: managed-resources
+spec:
+  # interval: 10m0s
+  interval: 7m0s
+  dependsOn:
+    - name: infra-configs
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${MANAGED_RESOURCES_PATH}
+  prune: true
+  wait: true
+  # timeout: 5m0s
+  timeout: 7m0s
+  retryInterval: 2m0s
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/sw-catalogs-repo.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base-openshift/templates/sw-catalogs-repo.yaml
new file mode 100644 (file)
index 0000000..75bc138
--- /dev/null
@@ -0,0 +1,30 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: GitRepository
+metadata:
+  name: sw-catalogs
+  namespace: flux-system
+spec:
+  interval: 1m0s
+  ref:
+    branch: main
+  secretRef:
+    name: sw-catalogs
+  url: ${SW_CATALOGS_REPO_URL}
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/hostedcluster.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/hostedcluster.yaml
new file mode 100644 (file)
index 0000000..59f206e
--- /dev/null
@@ -0,0 +1,69 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: hypershift.openshift.io/v1beta1
+kind: HostedCluster
+metadata:
+  name: ${cluster_name}
+  namespace: ${hosted_cluster_project}
+  labels:
+    cluster: ${cluster_name}
+    "cluster.open-cluster-management.io/clusterset": "default"
+spec:
+  etcd:
+    managed:
+      storage:
+        persistentVolume:
+          size: "${etcd_volume_size}"
+          storageClassName: ${storage_class}
+        type: PersistentVolume
+    managementType: Managed
+  release:
+    image: "quay.io/openshift-release-dev/ocp-release:${openshift_release}"
+  pullSecret:
+    name: "pullsecret-cluster-${cluster_name}"
+  sshKey:
+    name: "sshkey-cluster-${cluster_name}"
+  networking:
+    clusterNetwork:
+      - cidr: 10.132.0.0/14
+    serviceNetwork:
+      - cidr: 172.31.0.0/16
+    networkType: OVNKubernetes
+  controllerAvailabilityPolicy: ${control_plane_availability}
+  infrastructureAvailabilityPolicy: ${control_plane_availability}
+  platform:
+    type: KubeVirt
+    kubevirt:
+      baseDomainPassthrough: true
+  infraID: ${cluster_name}
+  services:
+    - service: OAuthServer
+      servicePublishingStrategy:
+        type: Route
+    - service: OIDC
+      servicePublishingStrategy:
+        type: Route
+    - service: Konnectivity
+      servicePublishingStrategy:
+        type: Route
+    - service: Ignition
+      servicePublishingStrategy:
+        type: Route
+    - service: APIServer
+      servicePublishingStrategy:
+        type: LoadBalancer
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/klusterlet.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/klusterlet.yaml
new file mode 100644 (file)
index 0000000..c436d31
--- /dev/null
@@ -0,0 +1,38 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: agent.open-cluster-management.io/v1
+kind: KlusterletAddonConfig
+metadata:
+  name: ${cluster_name}
+  namespace: ${cluster_project}
+  labels:
+    cluster: ${cluster_name}
+spec:
+  clusterName: ${cluster_name}
+  clusterNamespace: ${cluster_project}
+  clusterLabels:
+    cloud: BareMetal
+    vendor: OpenShift
+  applicationManager:
+    enabled: true
+  policyController:
+    enabled: true
+  searchCollector:
+    enabled: true
+  certPolicyController:
+    enabled: true
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/managedcluster.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/managedcluster.yaml
new file mode 100644 (file)
index 0000000..e1fc0aa
--- /dev/null
@@ -0,0 +1,33 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: cluster.open-cluster-management.io/v1
+kind: ManagedCluster
+metadata:
+  annotations:
+    import.open-cluster-management.io/hosting-cluster-name: local-cluster 
+    import.open-cluster-management.io/klusterlet-deploy-mode: Hosted
+    open-cluster-management/created-via: hypershift
+  labels:
+    cloud: BareMetal
+    cluster: ${cluster_name}
+    vendor: OpenShift
+    name: ${cluster_name}
+    cluster.open-cluster-management.io/clusterset: "default"
+  name: ${cluster_name}
+spec:
+  hubAcceptsClient: true
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/nodepool.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/cluster/nodepool.yaml
new file mode 100644 (file)
index 0000000..d7f442d
--- /dev/null
@@ -0,0 +1,48 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: hypershift.openshift.io/v1beta1
+kind: NodePool
+metadata:
+  name: "${cluster_name}-np1"
+  namespace: ${hosted_cluster_project}
+  labels:
+    cluster: ${cluster_name}
+spec:
+  arch: amd64
+  clusterName: ${cluster_name}
+  replicas: ${worker_count}
+  management:
+    autoRepair: false
+    upgradeType: Replace
+  platform:
+    type: KubeVirt
+    kubevirt:
+      compute:
+        cores: ${worker_cores}
+        memory: "${worker_memory}"
+      rootVolume:
+        type: Persistent
+        persistent:
+          size: "${worker_volume_size}"
+          accessModes:
+            - ReadWriteMany
+          storageClass: ${storage_class}
+          volumeMode: Block
+      # defaultPodNetwork: true
+  release:
+    image: "quay.io/openshift-release-dev/ocp-release:${openshift_release}"
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/namespaces/namespaces.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/openshift/manifests/namespaces/namespaces.yaml
new file mode 100644 (file)
index 0000000..d3745f8
--- /dev/null
@@ -0,0 +1,31 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: "${cluster_project}"
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: "clusters-${cluster_project}"
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: "klusterlet-${cluster_project}"
diff --git a/installers/flux/templates/sw-catalogs/cloud-resources/openshift/templates/openshift01.yaml b/installers/flux/templates/sw-catalogs/cloud-resources/openshift/templates/openshift01.yaml
new file mode 100644 (file)
index 0000000..2684255
--- /dev/null
@@ -0,0 +1,122 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+---
+# TEMPLATE_PARAMETERS:
+# ===================
+#
+# CLUSTER_KUSTOMIZATION_NAME: Name of the cluster in the ACM management cluster (e.g., for `Kustomization`s).
+# CLUSTER_PROJECT: Name of one of the three projects for the cluster that will be created in the ACM management cluster.
+#
+# PARAMETERS TO PATCH:
+# ===================
+#
+# .spec.postBuild.substitute.cluster_project: Project name to be created
+
+# Cluster projects
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}-ns
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  commonMetadata:
+    labels:
+      cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/openshift/manifests/namespaces
+  prune: true
+  # force: true
+  wait: true
+  # Input parameters
+  postBuild:
+    substitute:
+      cluster_project: ${CLUSTER_PROJECT}
+---
+# TEMPLATE_PARAMETERS:
+# ===================
+#
+# CLUSTER_KUSTOMIZATION_NAME: Name of the cluster in the management cluster (e.g., for `Kustomization`s).
+# - Alternatively, it can be patched at:
+#   .metadata.name
+#   .metadata.labels.cluster
+#   .spec.commonMetadata.labels.cluster
+#   .spec.postBuild.substitute.cluster_resource_name
+#
+# PARAMETERS TO PATCH:
+# ===================
+#
+# .spec.postBuild.substitute.base_domain: Domain name to use as base.
+# .spec.postBuild.substitute.cluster_name: Name of the cluster in the target cloud. It may differ from `CLUSTER_KUSTOMIZATION_NAME` since naming restrictions are often different from K8s resource naming restrictions (e.g., hyphens vs. underscores).
+# .spec.postBuild.substitute.cluster_project: Project name to use
+# .spec.postBuild.substitute.hosted_cluster_project: Common project name to use for use with all workload clusters.
+# .spec.postBuild.substitute.etcd_volume_size: Volume size of ETCD in Gi
+# .spec.postBuild.substitute.openshift_release: Flavor of worker node VMs.
+# .spec.postBuild.substitute.storage_class: OpenShift StorageClass to use to create volumes.
+# .spec.postBuild.substitute.control_plane_availability: Availability of the contro plane. Valid only SingleReplica or HighAvailability
+# .spec.postBuild.substitute.worker_count: Number of Workers.
+# .spec.postBuild.substitute.worker_cores: CPU count of Workers.
+# .spec.postBuild.substitute.worker_memory: Memory size of Workers in Gi.
+# .spec.postBuild.substitute.worker_volume_size: Volume size of Workers in Gi.
+
+# Cluster resource
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  dependsOn:
+    - name: ${CLUSTER_KUSTOMIZATION_NAME}-ns
+  commonMetadata:
+    labels:
+      cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/openshift/manifests/cluster
+  prune: true
+  # force: true
+  wait: true
+  # Input parameters
+  postBuild:
+    substitute:
+      base_domain: ${BASE_DOMAIN}
+      cluster_name: ${CLUSTER_NAME}
+      cluster_project: ${CLUSTER_PROJECT}
+      hosted_cluster_project: ${HOSTED_CLUSTER_PROJECT}
+      etcd_volume_size: ${ETCD_VOLUME_SIZE}
+      openshift_release: ${OPENSHIFT_RELEASE}
+      storage_class: ${STORAGE_CLASS}
+      control_plane_availability: ${CONTROL_PLANE_AVAILABILITY}
+      worker_count: ${WORKER_COUNT}
+      worker_cores: ${WORKER_CORES}
+      worker_memory: ${WORKER_MEMORY}
+      worker_volume_size: ${WORKER_VOLUME_SIZE}