Skip to content

Commit

Permalink
Add crc-cloud Ansible role
Browse files Browse the repository at this point in the history
The Ansible tool might handle in better way how to deploy the
CRC cloud.
  • Loading branch information
danpawlik committed Dec 16, 2024
1 parent 4be45c7 commit e1021fc
Show file tree
Hide file tree
Showing 22 changed files with 629 additions and 0 deletions.
59 changes: 59 additions & 0 deletions ansible/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Deploy CRC cloud directly on CRC host

## Introduction

The CRC cloud tool deploys the CRC host using its own binary, but it
requires access to the cloud provider credentials. That functionality
is useless when the CRC cloud needs to be used in externa CI, where
the crc-cloud tool can not be used - especially when the CI is responsible
to check how many VMs are spawned or checking job results.

## CRC QCOW2 image

There is a simply way to bootstrap the CRC without using the crc-cloud
tool and upload it to your cloud provider:

- download libvirt bundle (you can see url when crc is in debug mode)
- extract libvirt bundle using tar command with zst:

```shell
tar xaf crc_libvirt_$VERSION_amd64.crcbundle
```

- upload crc.qcow2 image to your cloud provider
- take the id_ecdsa_crc file

## Bootstrap crc-cloud directly on host

Now after spawning VM using the `crc.qcow2` image:

- prepare `inventory.yaml` file:

```shell
CRC_VM_IP=<ip address>

cat << EOF > inventory.yaml
---
all:
hosts:
crc-cloud.dev:
ansible_port: 22
ansible_host: $CRC_VM_IP
ansible_user: core
vars:
openshift_pull_secret: |
< PULL SECRET >
EOF
```

- clone crc-cloud project (FIXME: change repository)

```shell
git clone https://github.com/danpawlik/crc-cloud -b add-ansible-role
```

- run playbook to boostrap the container that later would start deploy-crc-cloud role

```shell
ansible-playbook -i inventory.yaml crc-cloud/ansible/playbooks/bootstrap.yaml
```
112 changes: 112 additions & 0 deletions ansible/playbooks/bootstrap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
- name: Prepare and create container to start crc-cloud playbook
hosts: crc-cloud.dev
tasks:
# FIXME: change to main repository
- name: Clone crc-cloud repository
ansible.builtin.git:
repo: https://github.com/danpawlik/crc-cloud
dest: crc-cloud
version: add-ansible-role

- name: Check if boostrap ssh key exists
ansible.builtin.stat:
path: .ssh/crc-cloud-bootstrap.pub
register: _boostrap_ssh_key

- name: Generate ssh keypair
when: not _boostrap_ssh_key.stat.exists
community.crypto.openssh_keypair:
path: .ssh/crc-cloud-bootstrap
type: ed25519
state: present
owner: core
group: core

- name: Add generated key to authorized keys
ansible.builtin.shell: |
cat .ssh/crc-cloud-bootstrap.pub >> .ssh/authorized_keys.d/ignition
# FIXME: move it to dedicated files
- name: Create entrypoint file
ansible.builtin.copy:
content: |
#!/bin/bash
echo "Check if ${HOME}/inventory.yaml exists..."
if ! [ -f "${HOME}/inventory.yaml" ]; then
echo "Starting Ansible..."
export ANSIBLE_HOST_KEY_CHECKING=False
export ANSIBLE_LOG_PATH=/home/user/ansible-logs/ansible.log
ansible-playbook -i "${HOME}/inventory.yaml" "${HOME}/crc-cloud/ansible/playbooks/start.yaml"
else
echo "Could not find inventory file. Exit"
exit 1
fi
dest: entrypoint.sh

- name: Prepare Dockerfile
ansible.builtin.copy:
content: |
FROM quay.io/centos/centos:stream9
RUN dnf install -y ansible-core sudo && \
ansible-galaxy collection install community.general \
community.crypto ansible.posix \
kubernetes.core
RUN groupadd --gid 1000 user && \
useradd --uid 1000 --gid 1000 -d /home/user user
COPY entrypoint.sh /home/user/entrypoint.sh
RUN chown -R user:user /home/user && chmod +x /home/user/entrypoint.sh
USER user
WORKDIR /home/user
ENTRYPOINT ["/home/user/entrypoint.sh"]
dest: Dockerfile

- name: Build bootstrap container
ansible.builtin.shell: |
podman build -t crc-cloud-bootstrap -f Dockerfile
- name: Create inventory file
ansible.builtin.copy:
content: |
---
all:
hosts:
{{ ansible_fqdn }}:
ansible_port: 22
ansible_host: {{ ansible_default_ipv4.address }}
ansible_user: core
vars:
openshift_pull_secret: |
{{ openshift_pull_secret }}
dest: inventory.yaml

- name: Create Ansible log directory
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: core
group: core
loop:
- ansible-logs
- .kube

- name: Create container to boostrap
ansible.builtin.shell: >
podman create --name crc-cloud-boostrap
--network host
-v "/var/home/core/.ssh:/home/user/.ssh:z"
-v "/var/home/core/inventory.yaml:/home/user/inventory.yaml:z"
-v "/var/home/core/crc-cloud:/home/user/crc-cloud:z"
-v "/var/home/core/ansible-logs:/home/user/ansible-logs:z"
-v "/var/home/core/.kube:/home/user/.kube:z"
crc-cloud-bootstrap
- name: Start the container
ansible.builtin.shell: |
podman start crc-cloud-boostrap
1 change: 1 addition & 0 deletions ansible/playbooks/roles
7 changes: 7 additions & 0 deletions ansible/playbooks/start.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
# NOTE: The playbook by default will create nested and extracted image.
- name: Start crc-cloud
gather_facts: true
hosts: crc
roles:
- deploy-crc-cloud
33 changes: 33 additions & 0 deletions ansible/roles/deploy-crc-cloud/defaults/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
dnsmasq_conf_path: /etc/dnsmasq.d/crc-dnsmasq.conf
openshift_pull_secret: ""
eip: crc.dev
alternative_domain: nip.io

# wait for resource
max_retry: 20
wait_interval: 5

# wait cluster become healthy
max_retries: 20
retry_delay: 5

pass_developer: _PASS_DEVELOPER_
pass_kubeadmin: _PASS_KUBEADMIN_
pass_redhat: _PASS_REDHAT_

users:
- name: developer
password: "{{ pass_developer }}"
- name: kubeadmin
password: "{{ pass_kubeadmin }}"
- name: redhat
password: "{{ pass_redhat }}"

# replace default ca
ca_user: "system:admin"
ca_group: "system:masters"
ca_user_subj: "/O=${GROUP}/CN=${USER}"
ca_name: "custom"
ca_subj: "/OU=openshift/CN=admin-kubeconfig-signer-custom"
ca_validity: 3650
16 changes: 16 additions & 0 deletions ansible/roles/deploy-crc-cloud/tasks/console_route.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
# https://github.com/crc-org/crc-cloud/blob/main/pkg/bundle/setup/clustersetup.sh#L282
- name: Get route to console custom
ansible.builtin.shell: |
oc get route console-custom -n openshift-console
register: _route_console_custom
until: _route_console_custom.rc != 1
retries: 60
delay: 10
changed_when: false

- name: Get console route
ansible.builtin.shell: >
oc get route console-custom
-n openshift-console
-o json | jq -r '.spec.host'
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
# https://github.com/crc-org/crc-cloud/blob/main/pkg/bundle/setup/clustersetup.sh#L185
- name: Create alternative cert
ansible.builtin.shell: >
openssl req
-newkey rsa:2048
-new -nodes
-x509
-days 3650
-keyout nip.key
-out nip.crt
-subj "/CN={{ eip }}.{{ alternative_domain }}"
-addext "subjectAltName=DNS:apps.{{ eip }}.{{ alternative_domain }},DNS:*.apps.{{ eip }}.{{ alternative_domain }},DNS:api.{{ eip }}.{{ alternative_domain }}"
- name: "Create secret for {{ alternative_domain }}"
ansible.builtin.command: >
oc create secret tls nip-secret
--cert=nip.crt
--key=nip.key
-n openshift-config
51 changes: 51 additions & 0 deletions ansible/roles/deploy-crc-cloud/tasks/dnsmasq.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
# From https://github.com/crc-org/crc-cloud/blob/main/pkg/bundle/setup/clustersetup.sh#L101
- name: Create crc-dnsmasq.conf
become: true
ansible.builtin.copy:
content: |
listen-address={{ ansible_default_ipv4.address }}
expand-hosts
log-queries
local=/crc.testing/
domain=crc.testing
address=/apps-crc.testing/{{ ansible_default_ipv4.address }}
address=/api.crc.testing/{{ ansible_default_ipv4.address }}
address=/api-int.crc.testing/{{ ansible_default_ipv4.address }}
address=/{{ ansible_fqdn }}.crc.testing/192.168.126.11
dest: "{{ dnsmasq_conf_path }}"
register: _dnsmasq_conf

- name: Set this host as first nameserver in /etc/resolv.conf
become: true
ansible.builtin.lineinfile:
path: /etc/resolv.conf
regexp: '^# Generated by NetworkManager'
line: "nameserver {{ item }}"
create: true
loop: "{{ [ansible_default_ipv4.address] + ansible_facts['dns']['nameservers'] | flatten }}"
register: _etc_resolv

- name: Disable overwriting /etc/resolv.conf by the NetworkManager
become: true
ansible.builtin.copy:
content: |
[main]
dns=none
dest: /etc/NetworkManager/conf.d/00-custom-crc.conf
register: _disable_dns_overwrite

- name: Restart NetworkManager when its needed
when: _disable_dns_overwrite.changed
become: true
ansible.builtin.systemd:
name: NetworkManager
state: restarted

- name: Restart dnsmasq
when: _etc_resolv.changed
become: true
ansible.builtin.systemd:
name: dnsmasq
state: restarted
enabled: true
11 changes: 11 additions & 0 deletions ansible/roles/deploy-crc-cloud/tasks/get_htpasswd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
- name: "Get htpasswd for {{ user.name }}"
ansible.builtin.shell: |
podman run --rm -ti xmartlabs/htpasswd {{ user.name }} {{ user.password }}
register: _user_hash

- name: Create htpasswd.txt
ansible.builtin.lineinfile:
path: htpasswd.txt
line: "{{ _user_hash.stdout }}"
create: true
15 changes: 15 additions & 0 deletions ansible/roles/deploy-crc-cloud/tasks/kubeconfig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
- name: Create kube directory
ansible.builtin.file:
path: .kube
state: directory
owner: core
group: core

- name: Copy kubeconfig to user dir
ansible.builtin.copy:
src: /opt/kubeconfig
dest: .kube/config
remote_src: true
owner: core
group: core
30 changes: 30 additions & 0 deletions ansible/roles/deploy-crc-cloud/tasks/kubelet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
# https://github.com/crc-org/crc-cloud/blob/main/pkg/bundle/setup/clustersetup.sh#L132
- name: Start and enable kubelet
become: true
ansible.builtin.systemd:
name: kubelet
state: started
enabled: true

- name: Wait for port 6443 to be up
ansible.builtin.wait_for:
timeout: 300
port: 6443
delay: 60

- name: Wait for API to start before continue
ansible.builtin.command: >
oc get pods --all-namespaces
register: _openshift_containers
until: |
('No resources found' not in _openshift_containers.stdout) or
('connect: connection refused' not in _openshift_containers.stderr) or
('get current server API group list' not in _openshift_containers.stderr)
retries: 60
delay: 20
changed_when: false
failed_when:
- "'connect: connection refused' in _openshift_containers.stderr"
- "'get current server API group list' in _openshift_containers.stderr"
- _openshift_containers.rc != 0
14 changes: 14 additions & 0 deletions ansible/roles/deploy-crc-cloud/tasks/login.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
# https://github.com/crc-org/crc-cloud/blob/main/pkg/bundle/setup/clustersetup.sh#L67
- name: Try to login after all changes
ansible.builtin.command: >
oc login
--insecure-skip-tls-verify=true
-u kubeadmin
-p "{{ pass_kubeadmin }}"
https://api.crc.testing:6443
register: _openshift_login
until: _openshift_login.rc != 1
retries: 60
delay: 10
changed_when: false
Loading

0 comments on commit e1021fc

Please sign in to comment.