Deployment automation for Stolostron on OKD

Stolostron (https://github.com/stolostron) is the open source implementation of Red Hat Advanced Cluster Management and provides the API interfaces required by the OKD-compatible oran-o2ims operator (https://github.com/openshift-kni/oran-o2ims). It includes the open-cluster-management and multicluster-engine operators, which enable policy-driven, centralized management of Kubernetes clusters.

Issue-ID: INF-480
Signed-off-by: Chris Wheeler <chwheele@redhat.com>
Change-Id: I135d5cb47eae6ce5845b248f39508b8a2ddea77a
diff --git a/okd/requirements.txt b/okd/requirements.txt
index 4aa2ac0..385bb9b 100644
--- a/okd/requirements.txt
+++ b/okd/requirements.txt
@@ -1,2 +1,3 @@
+kubernetes
 netaddr
 libvirt-python
diff --git a/okd/roles/ocloud/tasks/main.yml b/okd/roles/ocloud/tasks/main.yml
index 9f9a930..6820b37 100644
--- a/okd/roles/ocloud/tasks/main.yml
+++ b/okd/roles/ocloud/tasks/main.yml
@@ -10,3 +10,11 @@
     name: "ocloud_infra_vm"
   delegate_to: "{{ groups['kvm'][0] }}"
   when: ocloud_infra == "vm"
+
+- meta: flush_handlers
+
+- name: Include platform role - Stolostron
+  ansible.builtin.import_role:
+    name: "ocloud_platform_stolostron"
+  delegate_to: "{{ groups['deployer'][0] }}"
+  when: ocloud_platform == "okd"
diff --git a/okd/roles/ocloud_platform_okd/defaults/main.yml b/okd/roles/ocloud_platform_okd/defaults/main.yml
index 16e0318..587e419 100644
--- a/okd/roles/ocloud_platform_okd/defaults/main.yml
+++ b/okd/roles/ocloud_platform_okd/defaults/main.yml
@@ -1,5 +1,8 @@
 ---
 ocloud_platform_okd_pull_secret: '{"auths":{"fake":{"auth":"aWQ6cGFzcwo="}}}'
 ocloud_platform_okd_ssh_pubkey: ~
-ocloud_platform_okd_release: "4.14.0-0.okd-2024-01-26-175629"
-ocloud_platform_okd_base_url: "https://github.com/okd-project/okd/releases/download"
+ocloud_platform_okd_kubeconfig: ~
+ocloud_platform_okd_release: "4.16.0-0.okd-scos-2024-08-01-132038"
+ocloud_platform_okd_base_url: "quay.io/okd/scos-release"
+ocloud_platform_okd_cli_url: "https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp"
+ocloud_platform_okd_image_url: "https://mirror.openshift.com/pub/openshift-v4/x86_64/dependencies/rhcos/4.16/4.16.3/rhcos-4.16.3-x86_64-live.x86_64.iso"
diff --git a/okd/roles/ocloud_platform_okd/handlers/main.yml b/okd/roles/ocloud_platform_okd/handlers/main.yml
index a89e727..2044f42 100644
--- a/okd/roles/ocloud_platform_okd/handlers/main.yml
+++ b/okd/roles/ocloud_platform_okd/handlers/main.yml
@@ -1,7 +1,10 @@
 ---
-- name: Monitor OKD platform bootstrap
+- name: Monitor OKD platform deployment
   ansible.builtin.command:
-    cmd: "openshift-install agent wait-for bootstrap-complete --log-level=info --dir {{ ocloud_platform_okd_staging_dir['path'] }}/cfg"
+    cmd: "openshift-install agent wait-for {{ item }} --log-level=info --dir {{ ocloud_platform_okd_staging_dir['path'] }}/cfg"
   environment:
     PATH: "{{ ocloud_platform_okd_staging_dir['path'] }}/bin:{{ ansible_env.PATH }}"
+  loop:
+    - bootstrap-complete
+    - install-complete
   listen: monitor_platform_deployment
diff --git a/okd/roles/ocloud_platform_okd/tasks/install.yml b/okd/roles/ocloud_platform_okd/tasks/install.yml
new file mode 100644
index 0000000..6896b88
--- /dev/null
+++ b/okd/roles/ocloud_platform_okd/tasks/install.yml
@@ -0,0 +1,56 @@
+---
+- name: Create staging dir for OKD installation
+  ansible.builtin.tempfile:
+    state: directory
+  register: ocloud_platform_okd_staging_dir
+
+- name: Create staging subdirs
+  ansible.builtin.file:
+    path: "{{ ocloud_platform_okd_staging_dir['path'] }}/{{ item }}"
+    state: directory
+  loop:
+    - bin
+    - cfg
+
+- name: Download OKD CLI
+  ansible.builtin.get_url:
+    url: "{{ ocloud_platform_okd_cli_url }}/stable-{{ ocloud_platform_okd_release | regex_search('^[0-9]*\\.[0-9]*') }}/openshift-client-linux.tar.gz"
+    dest: "{{ ocloud_platform_okd_staging_dir['path'] }}"
+
+- name: Extract OKD CLI
+  ansible.builtin.unarchive:
+    src: "{{ ocloud_platform_okd_staging_dir['path'] }}/openshift-client-linux.tar.gz"
+    dest: "{{ ocloud_platform_okd_staging_dir['path'] }}/bin"
+    remote_src: true
+
+- name: Extract OKD installer
+  ansible.builtin.shell:
+    cmd: "oc adm release extract --command=openshift-install {{ ocloud_platform_okd_base_url }}:{{ ocloud_platform_okd_release }} --to {{ ocloud_platform_okd_staging_dir['path'] }}/bin"
+  environment:
+    PATH: "{{ ocloud_platform_okd_staging_dir['path'] }}/bin:{{ ansible_env.PATH }}"
+
+- name: Template OKD configs
+  ansible.builtin.template:
+    src: "{{ item }}.j2"
+    dest: "{{ ocloud_platform_okd_staging_dir['path'] }}/cfg/{{ item }}"
+  loop:
+    - agent-config.yaml
+    - install-config.yaml
+
+- name: Generate OKD agent-based installer image
+  ansible.builtin.shell:
+    cmd: "openshift-install agent create image --dir {{ ocloud_platform_okd_staging_dir['path'] }}/cfg"
+  environment:
+    PATH: "{{ ocloud_platform_okd_staging_dir['path'] }}/bin:{{ ansible_env.PATH }}"
+    OPENSHIFT_INSTALL_OS_IMAGE_OVERRIDE: "{{ ocloud_platform_okd_image_url }}"
+
+- debug:
+    msg: |
+       OKD agent-based installer image has been created as {{ ocloud_platform_okd_staging_dir['path'] }}/cfg/agent.x86_64.iso
+       kubeconfig and kubeadmin-password can be found under {{ ocloud_platform_okd_staging_dir['path'] }}/cfg/auth/
+
+- ansible.builtin.set_fact:
+    ocloud_platform_okd_kubeconfig: "{{ ocloud_platform_okd_staging_dir['path'] }}/cfg/auth/kubeconfig"
+
+- ansible.builtin.set_fact:
+    ocloud_platform_image: "{{ ocloud_platform_okd_staging_dir['path'] }}/cfg/agent.x86_64.iso"
diff --git a/okd/roles/ocloud_platform_okd/tasks/main.yml b/okd/roles/ocloud_platform_okd/tasks/main.yml
index 472a81a..3b00e37 100644
--- a/okd/roles/ocloud_platform_okd/tasks/main.yml
+++ b/okd/roles/ocloud_platform_okd/tasks/main.yml
@@ -3,54 +3,8 @@
   ansible.builtin.setup:
     gather_subset: all
 
-- name: Create staging dir for OKD installation
-  ansible.builtin.tempfile:
-    state: directory
-  register: ocloud_platform_okd_staging_dir
+- include_tasks: version.yml
+  when: ocloud_platform_okd_kubeconfig
 
-- name: Create staging subdirs
-  ansible.builtin.file:
-    path: "{{ ocloud_platform_okd_staging_dir['path'] }}/{{ item }}"
-    state: directory
-  loop:
-    - bin
-    - cfg
-
-- name: Download OKD binaries
-  ansible.builtin.get_url:
-    url: "{{ ocloud_platform_okd_base_url }}/{{ ocloud_platform_okd_release }}/{{ item }}-{{ ocloud_platform_okd_release }}.tar.gz"
-    dest: "{{ ocloud_platform_okd_staging_dir['path'] }}"
-  loop:
-    - openshift-client-linux
-    - openshift-install-linux
-
-- name: Extract OKD binaries
-  ansible.builtin.unarchive:
-    src: "{{ ocloud_platform_okd_staging_dir['path'] }}/{{ item }}-{{ ocloud_platform_okd_release }}.tar.gz"
-    dest: "{{ ocloud_platform_okd_staging_dir['path'] }}/bin"
-    remote_src: true
-  loop:
-    - openshift-client-linux
-    - openshift-install-linux
-
-- name: Template OKD configs
-  ansible.builtin.template:
-    src: "{{ item }}.j2"
-    dest: "{{ ocloud_platform_okd_staging_dir['path'] }}/cfg/{{ item }}"
-  loop:
-    - agent-config.yaml
-    - install-config.yaml
-
-- name: Generate OKD agent-based installer image
-  ansible.builtin.shell:
-    cmd: "openshift-install agent create image --dir {{ ocloud_platform_okd_staging_dir['path'] }}/cfg"
-  environment:
-    PATH: "{{ ocloud_platform_okd_staging_dir['path'] }}/bin:{{ ansible_env.PATH }}"
-
-- debug:
-    msg: |
-       OKD agent-based installer image has been created as {{ ocloud_platform_okd_staging_dir['path'] }}/cfg/agent.x86_64.iso
-       kubeconfig and kubeadmin-password can be found under {{ ocloud_platform_okd_staging_dir['path'] }}/cfg/auth/
-
-- ansible.builtin.set_fact:
-    ocloud_platform_image: "{{ ocloud_platform_okd_staging_dir['path'] }}/cfg/agent.x86_64.iso"
+- include_tasks: install.yml
+  when: ocloud_platform_okd_installed_release != ocloud_platform_okd_release
diff --git a/okd/roles/ocloud_platform_okd/tasks/version.yml b/okd/roles/ocloud_platform_okd/tasks/version.yml
new file mode 100644
index 0000000..5aa0c3d
--- /dev/null
+++ b/okd/roles/ocloud_platform_okd/tasks/version.yml
@@ -0,0 +1,11 @@
+---
+- name: Get OKD cluster info
+  kubernetes.core.k8s_info:
+    api_version: config.openshift.io/v1
+    kind: ClusterVersion
+    kubeconfig: "{{ ocloud_platform_okd_kubeconfig }}"
+  register: ocloud_platform_okd_cluster_info
+
+- name: Set OKD installed release
+  set_fact:
+    ocloud_platform_okd_installed_release: "{{ ocloud_platform_okd_cluster_info['resources'][0]['status']['desired']['version'] }}"
diff --git a/okd/roles/ocloud_platform_okd/vars/main.yml b/okd/roles/ocloud_platform_okd/vars/main.yml
new file mode 100644
index 0000000..bb6a4b5
--- /dev/null
+++ b/okd/roles/ocloud_platform_okd/vars/main.yml
@@ -0,0 +1,2 @@
+---
+ocloud_platform_okd_installed_release: ~
diff --git a/okd/roles/ocloud_platform_stolostron/defaults/main.yml b/okd/roles/ocloud_platform_stolostron/defaults/main.yml
new file mode 100644
index 0000000..ec96784
--- /dev/null
+++ b/okd/roles/ocloud_platform_stolostron/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+ocloud_platform_stolostron_pull_secret: "{{ ocloud_platform_okd_pull_secret }}"
+ocloud_platform_stolostron_kubeconfig: "{{ ocloud_platform_okd_kubeconfig }}"
+ocloud_platform_stolostron_snapshot: "2.11.2-SNAPSHOT-2024-08-27-14-52-55"
+ocloud_platform_stolostron_repo_url: "https://github.com/stolostron/deploy.git"
diff --git a/okd/roles/ocloud_platform_stolostron/tasks/main.yml b/okd/roles/ocloud_platform_stolostron/tasks/main.yml
new file mode 100644
index 0000000..cc446c1
--- /dev/null
+++ b/okd/roles/ocloud_platform_stolostron/tasks/main.yml
@@ -0,0 +1,79 @@
+---
+- name: Gather facts
+  ansible.builtin.setup:
+    gather_subset: all
+
+- name: Disable default catalog sources
+  kubernetes.core.k8s:
+    api_version: config.openshift.io/v1
+    kind: OperatorHub
+    name: cluster
+    namespace: default
+    state: patched
+    definition:
+      spec:
+        disableAllDefaultSources: true
+    kubeconfig: "{{ ocloud_platform_stolostron_kubeconfig }}"
+
+- name: Create staging dir for Stolostron installation
+  ansible.builtin.tempfile:
+    state: directory
+  register: ocloud_platform_stolostron_staging_dir
+
+- name: Create staging subdirs
+  ansible.builtin.file:
+    path: "{{ ocloud_platform_stolostron_staging_dir['path'] }}/{{ item }}"
+    state: directory
+  loop:
+    - bin
+    - git
+
+- name: Download OKD CLI
+  ansible.builtin.get_url:
+    url: "{{ ocloud_platform_okd_cli_url }}/stable-{{ ocloud_platform_okd_release | regex_search('^[0-9]*\\.[0-9]*') }}/openshift-client-linux.tar.gz"
+    dest: "{{ ocloud_platform_stolostron_staging_dir['path'] }}"
+
+- name: Extract OKD CLI
+  ansible.builtin.unarchive:
+    src: "{{ ocloud_platform_stolostron_staging_dir['path'] }}/openshift-client-linux.tar.gz"
+    dest: "{{ ocloud_platform_stolostron_staging_dir['path'] }}/bin"
+    remote_src: true
+
+- name: Clone stolostron/deploy repo
+  ansible.builtin.git:
+    repo: "{{ ocloud_platform_stolostron_repo_url }}"
+    dest: "{{ ocloud_platform_stolostron_staging_dir['path'] }}/git"
+
+- name: Template pull secret
+  ansible.builtin.template:
+    src: "pull-secret.yaml.j2"
+    dest: "{{ ocloud_platform_stolostron_staging_dir['path'] }}/git/prereqs/pull-secret.yaml"
+
+- name: Template snapshot version
+  ansible.builtin.template:
+    src: "snapshot.ver.j2"
+    dest: "{{ ocloud_platform_stolostron_staging_dir['path'] }}/git/snapshot.ver"
+
+- name: Install stolostron
+  ansible.builtin.shell:
+    chdir: "{{ ocloud_platform_stolostron_staging_dir['path'] }}/git"
+    cmd: "./start.sh --silent --watch --search"
+  environment:
+    PATH: "{{ ocloud_platform_stolostron_staging_dir['path'] }}/bin:{{ ansible_env.PATH }}"
+    KUBECONFIG: "{{ ocloud_platform_stolostron_kubeconfig }}"
+
+- name: Create search-api route
+  kubernetes.core.k8s:
+    api_version: route.openshift.io/v1
+    kind: Route
+    name: search-api
+    namespace: open-cluster-management
+    state: present
+    definition:
+      spec:
+        tls:
+          termination: reencrypt
+        to:
+          kind: Service
+          name: search-search-api
+    kubeconfig: "{{ ocloud_platform_stolostron_kubeconfig }}"
diff --git a/okd/roles/ocloud_platform_stolostron/templates/pull-secret.yaml.j2 b/okd/roles/ocloud_platform_stolostron/templates/pull-secret.yaml.j2
new file mode 100644
index 0000000..4d445db
--- /dev/null
+++ b/okd/roles/ocloud_platform_stolostron/templates/pull-secret.yaml.j2
@@ -0,0 +1,7 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name: multiclusterhub-operator-pull-secret
+data:
+  .dockerconfigjson: {{ ocloud_platform_stolostron_pull_secret | to_json | b64encode }}
+type: kubernetes.io/dockerconfigjson
diff --git a/okd/roles/ocloud_platform_stolostron/templates/snapshot.ver.j2 b/okd/roles/ocloud_platform_stolostron/templates/snapshot.ver.j2
new file mode 100644
index 0000000..a8a31a9
--- /dev/null
+++ b/okd/roles/ocloud_platform_stolostron/templates/snapshot.ver.j2
@@ -0,0 +1 @@
+{{ ocloud_platform_stolostron_snapshot }}