From 7f4a14f5fcca3c6cd7e3fa4d2060455aa553f145 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 8 Oct 2025 15:50:19 +1100 Subject: [PATCH 1/2] [host-ocp4-assisted-installer] README.md --- .../host-ocp4-assisted-installer/README.md | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 ansible/roles/host-ocp4-assisted-installer/README.md diff --git a/ansible/roles/host-ocp4-assisted-installer/README.md b/ansible/roles/host-ocp4-assisted-installer/README.md new file mode 100644 index 00000000000..7b13b55ead3 --- /dev/null +++ b/ansible/roles/host-ocp4-assisted-installer/README.md @@ -0,0 +1,108 @@ +# host-ocp4-assisted-installer + +- Provisions an OpenShift cluster using Assisted Installer and KubeVirt VMs running on an existing OpenShift/Kubernetes cluster. +- Handles SNO (Single Node, workers=0) and Full (control plane + workers) topologies. +- Creates KubeVirt VMs, Assisted Installer cluster + infra-env, injects manifests, configures DNS/Services, waits for readiness, starts install, and downloads credentials/artifacts. + +## Flow +```mermaid +flowchart TD + subgraph Local + A1[Determine oc client URL
stable vs specific] --> A2[Download and install oc] + A2 --> A3[Login via openshift_auth
optional] + end + + subgraph "KubeVirt/k8s" + K1{workers > 0?} + K2S[SNO: Create Svc LoadBalancer] + K2M[Create masters LB Service] + K2W[Create workers LB Service] + K3[Create OVN secondary network
if ai_install_use_network not set] + K4[Create PVC for installation ISO] + K5[Create Control Plane VMs
+ etcd disk, extra disks] + K6[Create Worker VMs
if workers > 0] + K7[Delete failed installer Pods
label app=installer] + end + + subgraph DNS + DNSSEL{DNS provider?} + DNS_NS[Create A records via nsupdate] + DNS_R53[Create A records via Route53] + end + + subgraph "Assisted Installer API" + AI1[create_cluster] + AI1a[Set HA mode - Full or None] + AI2[Upload manifests:
etcd disk, router replicas, network config] + AI2b{OCP >= 4.14?} + AI2c[Upload sysctl manifests
control-plane and workers] + AI3[Upload custom MachineConfigs
optional] + AI4[create_infra_env] + AI5[wait_for_hosts] + AI6[install_cluster - async] + AI7[get_credentials +
download_credentials/files] + end + + subgraph "Local render" + L1[Generate MACs for NICs and attached networks] + L2[Render static_network_config from template] + L3[Setup ~/.kube for ansible_user and root] + L4[Setup student kubeconfig
optional] + L5[Install oc bash completion] + L6[Print cluster info and user messages] + end + + A3 --> K1 + K1 -- no --> K2S --> DNSSEL + K1 -- yes --> K2M --> K2W --> DNSSEL + DNSSEL -- nsupdate --> DNS_NS --> K3 + DNSSEL -- Route53 --> DNS_R53 --> K3 + K3 --> AI1 --> AI1a --> AI2 --> AI2b + AI2b -- yes --> AI2c --> AI3 + AI2b -- no --> AI3 + AI3 --> L1 --> L2 --> AI4 --> K4 --> K5 --> K6 --> AI5 --> AI6 --> AI7 --> L3 --> L4 --> L5 --> K7 --> L6 +``` + +## Requirements +- Access to an OpenShift cluster API (`sandbox_openshift_api_url`) with KubeVirt and LoadBalancer services available. +- Assisted Installer credentials and pull secret. +- DNS either via `nsupdate` or AWS Route53 when configured. +- Collections used: `kubernetes.core`, `kubevirt.core`, `community.general`, `amazon.aws`, `rhpds.assisted_installer`. + +## Variables +Required (must be provided by inventory/group vars): +- `ocp4_installer_version`: OpenShift version (e.g. `4.13` or `4.13.21`). +- `ocp4_ai_pull_secret` or `ai_pull_secret`: Pull secret JSON string/object. +- `ocp4_ai_offline_token` or `ai_offline_token`: Assisted Installer offline token. +- `sandbox_openshift_api_url`: API endpoint of the management cluster running KubeVirt. +- `sandbox_openshift_username`/`sandbox_openshift_password` or `sandbox_openshift_api_key`: For API auth. +- `cluster_name` and `cluster_dns_zone`: Base cluster FQDN components. + +Common defaults you may override (see `defaults/main.yml`): +- `ai_cluster_version` (defaults to `ocp4_installer_version` or `4.13`) +- `ai_cluster_iso_type` (e.g. `minimal-iso`) +- `ai_ocp_namespace` (defaults to `env_type-guid`) +- `ai_ocp_vmname_master_prefix`, `ai_ocp_vmname_worker_prefix` +- `ai_storage_class`, `ai_local_storageclass` +- `ai_network_prefix`, `ai_service_network_cidr`, `ai_cluster_network_cidr`, `ai_network_mtu` +- `ai_control_plane_cores`, `ai_control_plane_memory`, `ai_workers_cores`, `ai_workers_memory` +- MAC/attached networks lists: `ai_masters_macs*`, `ai_workers_macs*`, `ai_attach_*_networks`, `ai_attach_*_macs` +- Extra disks: `ai_masters_extra_disks`, `ai_workers_extra_disks` +- Output and SSH: `ai_ocp_output_dir`, `ai_ssh_authorized_key` +- Optional: `ai_machineconfigs` (array of MachineConfig objects to upload) + +Other inputs used by tasks (set by your inventory/parent role): +- `master_instance_count`, `worker_instance_count` +- `env_type`, `guid`, `ansible_user`, `student_name`, `install_student_user` +- DNS (optional): `cluster_dns_server`, `cluster_dns_port`, `cluster_dns_zone`, `ddns_key_name`, `ddns_key_secret` +- Route53 (optional): `route53_aws_zone_id`, `route53_aws_access_key_id`, `route53_aws_secret_access_key` +- Optional network override: `ai_install_use_network` + +## Outputs +- Downloads to `{{ ai_ocp_output_dir }}/{{ cluster_name }}/`: kubeconfig(s), kubeadmin-password, ignition files, install-config and custom manifests. +- Writes user info messages with console/API URLs and client download link. +- Configures `/home/{{ ansible_user }}/.kube/config` and `/root/.kube/config`. + +### Notes +- When `worker_instance_count == 0`, the role configures SNO and only creates the SNO Service and DNS. +- If `ai_machineconfigs` is provided, each item is uploaded as an Assisted Installer custom manifest. From d6d5e29791c420f5052be24a648a51200b76f561 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 9 Oct 2025 16:57:30 +1100 Subject: [PATCH 2/2] [host-ocp4-hcp-cnv-install] README.md --- .../roles/host-ocp4-hcp-cnv-install/README.md | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 ansible/roles/host-ocp4-hcp-cnv-install/README.md diff --git a/ansible/roles/host-ocp4-hcp-cnv-install/README.md b/ansible/roles/host-ocp4-hcp-cnv-install/README.md new file mode 100644 index 00000000000..7f8d7fb2ec5 --- /dev/null +++ b/ansible/roles/host-ocp4-hcp-cnv-install/README.md @@ -0,0 +1,210 @@ +host-ocp4-hcp-cnv-install +========================= + +Purpose +------- +Provision an OpenShift 4 Hosted Control Plane (HCP) cluster on OpenShift Virtualization (CNV/KubeVirt) using HyperShift APIs in a management cluster. The role: + +- Creates TLS for OAuth via cert-manager `ClusterIssuer` +- Creates pull secret and infra kubeconfig secret for HyperShift +- Optionally configures `htpasswd` identity provider and generates users +- Creates `HostedCluster` and `NodePool` (KubeVirt platform) +- Waits for admin kubeconfig and makes it available locally +- Exposes apps via a LoadBalancer Service and creates a Route53 wildcard DNS record +- Copies kubeconfig to `/home//.kube/config` and `/root/.kube/config` +- Optionally sets up a student user kubeconfig +- Prints/saves access information via `agnosticd_user_info` + +Requirements +------------ +- Management OpenShift cluster with HyperShift installed (CRDs: `HostedCluster`, `NodePool`) +- OpenShift Virtualization (CNV/KubeVirt) enabled in the management cluster +- cert-manager installed with a `ClusterIssuer` matching `hcp_cluster_issuer` +- A DNS zone managed in Route53 if DNS automation is desired +- Access to the management cluster via username/password or API token +- Ansible collections in execution context: `kubernetes.core`, `community.okd`, `community.general`, `amazon.aws` +- Python virtualenv at `/opt/virtualenvs/k8s` with Kubernetes client libs (the role sets `ansible_python_interpreter` to this path) + +Behavior Overview +----------------- +1. Downloads `oc` client matching the requested OCP version +2. Authenticates to the management cluster (username/password or API token) +3. Resolves `ocp_release_image` from ClusterImageSets for `hcp_cluster_version` (supports `x.y` or `x.y.z`) +4. Applies templates to create: + - cert-manager `Certificate` for OAuth endpoint + - pull secret for the release image + - infra kubeconfig `Secret` used by HyperShift + - optional `htpasswd` Secret and identity provider + - `HostedCluster` and `NodePool` (KubeVirt) +5. Waits for hosted admin kubeconfig, writes `/tmp/kubeconfig`, copies to users +6. Creates a LoadBalancer Service targeting worker nodeports and adds a Route53 wildcard `A` record +7. Grants cluster-admin to the configured admin user and prints/saves access data + +Diagram +------- +```mermaid +flowchart TD + A[Start role] --> B[Set ansible_python_interpreter /opt/virtualenvs/k8s] + B --> C{ocp4_installer_version format} + C -->|x.y.z| D[Set GA client URL - exact] + C -->|x.y| E[Set GA client URL - stable] + D --> F[Download oc client] + E --> F + F --> G[Authenticate to mgmt cluster] + G --> H{Resolve ocp_release_image + from ClusterImageSets} + H --> I[Create OAuth Certificate] + I --> J[Wait Certificate Ready] + J --> K[Create pull secret] + K --> L[Create infra kubeconfig Secret] + L --> M{hcp_authentication == htpasswd?} + M -->|yes| N[Generate users + htpasswd Secret] + M -->|no| O[Read kubeadmin password Secret] + N --> P[Create HostedCluster - KubeVirt] + O --> P + P --> Q[Create NodePool] + Q --> R[Wait hosted admin kubeconfig] + R --> S[Write /tmp/kubeconfig and copy to users] + S --> T[Expose apps via LB Service] + T --> U[Create Route53 wildcard A record] + U --> V[Grant cluster-admin to admin user] + V --> W[Print and save access info] +``` + +Sequence Diagram +---------------- +```mermaid +sequenceDiagram + participant R as Role + participant M as Mgmt OCP API + participant CM as cert-manager + participant HS as HyperShift Operator + participant KV as KubeVirt CNV + participant DNS as Route53 + + R->>M: Apply Certificate for OAuth + M->>CM: Reconcile Certificate + CM-->>M: Secret oauth- ready + + R->>M: Create pull secret and infra kubeconfig secret + + R->>M: Create HostedCluster + M->>HS: Reconcile HostedCluster + HS->>KV: Provision control-plane VMs + HS-->>M: Admin kubeconfig secret available + R->>M: Read admin kubeconfig secret + R-->>R: Write /tmp/kubeconfig and copy to users + + R->>M: Create NodePool + M->>HS: Reconcile NodePool + HS->>KV: Provision worker VMs + + R->>M: Create LoadBalancer Service for apps + M-->>R: Service ingress IP available + R->>DNS: Create wildcard A record + R-->>R: Save and print access info +``` + +Role Variables (defaults) +------------------------ +Defined in `defaults/main.yaml`: + +- `num_users` (int, default `1`): Number of non-admin users to create when `htpasswd` auth is enabled +- `hcp_ssh_authorized_key` (string): SSH public key for node access +- `hcp_cluster_name` (string, default `guid`): Cluster name +- `hcp_cluster_version` (string, default `4.16`): OCP version (`x.y` or `x.y.z`) +- `hcp_storage_class` (string, default `ocs-external-storagecluster-ceph-rbd`): Default storage class name +- `hcp_etcd_storage_class` (string, default `hcp_storage_class`): etcd storage class +- `hcp_ocp_namespace` (string): Namespace for hosted cluster resources (defaults to `-`) +- `hcp_cluster_issuer` (string, default `letsencrypt-production-ec2`): cert-manager ClusterIssuer name +- `hcp_admin_password_length` (int, default `16`) +- `hcp_user_password_length` (int, default `16`) +- `hcp_user_base` (string, default `user`) +- `hcp_admin_user` (string, default `admin`) +- `hcp_user_passwords` (list, default `[]`): Populated when generating random passwords +- `hcp_admin_password` (string, default empty): If provided, used as admin password +- `hcp_user_password` (string, default empty): If provided, used for all non-admin users +- `hcp_enable_user_info_messages` (bool, default `true`): Print user info messages +- `hcp_enable_user_info_data` (bool, default `true`): Save user info data +- `hcp_controller_availability_policy` (string, default `SingleReplica`) +- `hcp_authentication` (string, default `htpasswd`): `htpasswd` or any other value to use kubeadmin secret +- `hcp_etcd_pvc_size` (string, default `8Gi`) +- `hcp_worker_cores` (int, default `16`) +- `hcp_worker_memory` (string, default `32Gi`) +- `hcp_worker_root_volume_size` (string, default `100Gi`) +- `hcp_worker_instance_count` (int): Number of worker replicas when autoscaling is disabled +- `hcp_worker_autoscale` (bool, default `false`) +- `hcp_worker_instance_min_count` (int, default `3`) +- `hcp_worker_instance_max_count` (int, default `5`) +- `hcp_quay_api_url` (string): Used to query release tags for tooling (informational) +- `hcp_disable_storage_class` (bool, default `false`): When true, sets storage driver to `None` in HostedCluster + +Additional required/expected variables +-------------------------------------- +- `guid` (string): Unique environment identifier +- `cluster_dns_zone` (string): Base DNS zone (e.g., `example.com`) +- `ocp4_pull_secret` (object or string): Pull secret JSON (object or already-serialized string) +- `worker_instance_count` (int) when not using autoscaling +- `sandbox_openshift_api_url` (string): Management cluster API URL +- One of: + - `sandbox_openshift_username` and `sandbox_openshift_password` (strings) + - or `sandbox_hcp.sandbox_openshift_api_key` (string) +- `sandbox_hcp.sandbox_openshift_api_url` (string): Management API URL used by HyperShift module defaults +- `sandbox_hcp.sandbox_openshift_namespace` (string): Namespace where hosted resources are created +- `sandbox_hcp.sandbox_openshift_apps_domain` (string): Apps domain of the management cluster (used for OAuth certificate and named certs) +- Route53 (optional, for DNS automation): + - `route53_aws_access_key_id`, `route53_aws_secret_access_key`, `route53_aws_zone_id` + +Optional variables +------------------ +- `install_student_user` (bool): If true, copies kubeconfig to `/home//.kube/config` +- `student_name` (string): Target username for student kubeconfig copy +- `ansible_user` (string): Used to place kubeconfig in `/home//.kube/config` +- `ocp4_installer_version` (string): `x.y` or `x.y.z`; determines client URL and release image selection +- `ocp4_installer_root_url` (string): Override clients mirror root if needed + +Outputs and Side Effects +------------------------ +- Resources created in the management cluster namespace `{{ sandbox_hcp.sandbox_openshift_namespace }}`: + - `Certificate` `oauth-{{ guid }}` + - `Secret` `hcp-{{ guid }}-pull-secret` + - `Secret` `hcp-{{ guid }}-infra-credentials` + - `Secret` `htpasswd-{{ guid }}` (when `hcp_authentication == 'htpasswd'`) + - `HostedCluster` `hcp-{{ guid }}` + - `NodePool` `hcp-{{ guid }}` +- LoadBalancer `Service` `svc-{{ guid }}-apps` and Route53 wildcard `A` record `*.apps.hcp-{{ guid }}.{{ cluster_dns_zone }}` +- Local files: kubeconfig copied to `/home/{{ ansible_user }}/.kube/config` and `/root/.kube/config` +- User info printed and stored via `agnosticd_user_info` + +Example +------- +Playbook snippet: + +```yaml +- hosts: bastion + gather_facts: false + roles: + - role: host-ocp4-hcp-cnv-install + vars: + guid: abc123 + cluster_dns_zone: example.com + hcp_cluster_version: "4.16" + sandbox_openshift_api_url: https://api.mgmt.example.com:6443 + sandbox_hcp: + sandbox_openshift_api_url: https://api.mgmt.example.com:6443 + sandbox_openshift_api_key: "" + sandbox_openshift_namespace: hcp-abc123 + ocp4_pull_secret: "{{ lookup('file', 'pull-secret.json') | from_json }}" + hcp_authentication: htpasswd + num_users: 5 + route53_aws_access_key_id: "AKIA..." + route53_aws_secret_access_key: "..." + route53_aws_zone_id: "Z123456789" +``` + +Notes +----- +- `hcp_cluster_version` may be specified as `x.y.z` (exact) or `x.y` (latest matching `ClusterImageSet` will be selected). The role fails early if a suitable image set is not found. +- If `hcp_authentication != 'htpasswd'`, the role reads the kubeadmin password from `hcp-{{ guid }}-kubeadmin-password` Secret. +- DNS automation via Route53 is optional; skip Route53 variables to disable it. +- To remove a hosted cluster, delete the `HostedCluster` and `NodePool` objects (or use a corresponding destroy role if available).