chore: add rook_ceph_cluster role
diff --git a/playbooks/openstack.yml b/playbooks/openstack.yml
index 8bec7c2..db8eda5 100644
--- a/playbooks/openstack.yml
+++ b/playbooks/openstack.yml
@@ -80,6 +80,11 @@
tags:
- rook-ceph
+ - role: rook_ceph_cluster
+ when: atmosphere_ceph_enabled | default(true)
+ tags:
+ - rook-ceph-cluster
+
- role: ceph_provisioners
when: atmosphere_ceph_enabled | default(true)
tags:
diff --git a/roles/defaults/defaults/main.yml b/roles/defaults/defaults/main.yml
index 936bb16..f89c8bd 100644
--- a/roles/defaults/defaults/main.yml
+++ b/roles/defaults/defaults/main.yml
@@ -13,6 +13,7 @@
cert_manager_cli: quay.io/jetstack/cert-manager-ctl:v1.7.1
cert_manager_controller: quay.io/jetstack/cert-manager-controller:v1.7.1
cert_manager_webhook: quay.io/jetstack/cert-manager-webhook:v1.7.1
+ ceph: quay.io/ceph/ceph:v16.2.11
cilium_node: quay.io/cilium/cilium:v1.10.7@sha256:e23f55e80e1988db083397987a89967aa204ad6fc32da243b9160fbcea29b0ca
cilium_operator: quay.io/cilium/operator-generic:v1.10.7@sha256:d0b491d8d8cb45862ed7f0410f65e7c141832f0f95262643fa5ff1edfcddcafe
cinder_api: quay.io/vexxhost/cinder:zed
diff --git a/roles/rook_ceph_cluster/defaults/main.yml b/roles/rook_ceph_cluster/defaults/main.yml
new file mode 100644
index 0000000..7fee383
--- /dev/null
+++ b/roles/rook_ceph_cluster/defaults/main.yml
@@ -0,0 +1,30 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# 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.
+
+rook_ceph_cluster_name: ceph
+
+rook_ceph_cluster_helm_release_name: "{{ rook_ceph_cluster_name }}"
+rook_ceph_cluster_helm_chart_path: "{{ role_path }}/../../charts/rook-ceph-cluster/"
+rook_ceph_cluster_helm_chart_ref: /usr/local/src/rook-ceph-cluster
+
+rook_ceph_cluster_helm_release_namespace: openstack
+rook_ceph_cluster_helm_values: {}
+
+# List of annotations to apply to the Ingress
+rook_ceph_cluster_radosgw_annotations: {}
+
+rook_ceph_cluster_mon_group: controllers
+
+rook_ceph_cluster_spec: {}
+rook_ceph_cluster_radosgw_spec: {}
diff --git a/roles/rook_ceph_cluster/meta/main.yml b/roles/rook_ceph_cluster/meta/main.yml
new file mode 100644
index 0000000..c5bb5e8
--- /dev/null
+++ b/roles/rook_ceph_cluster/meta/main.yml
@@ -0,0 +1,34 @@
+# Copyright (c) 2022 VEXXHOST, Inc.
+#
+# 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.
+
+galaxy_info:
+ author: VEXXHOST, Inc.
+ description: Ansible role for Rook Ceph Cluster
+ license: Apache-2.0
+ min_ansible_version: 5.5.0
+ standalone: false
+ platforms:
+ - name: Ubuntu
+ versions:
+ - focal
+
+dependencies:
+ - role: defaults
+ - role: openstacksdk
+ - role: openstack_helm_endpoints
+ openstack_helm_endpoints_list: ["rook_ceph_cluster"]
+ - role: upload_helm_chart
+ vars:
+ upload_helm_chart_src: "{{ rook_ceph_cluster_helm_chart_path }}"
+ upload_helm_chart_dest: "{{ rook_ceph_cluster_helm_chart_ref }}"
diff --git a/roles/rook_ceph_cluster/tasks/main.yml b/roles/rook_ceph_cluster/tasks/main.yml
new file mode 100644
index 0000000..ee3c06b
--- /dev/null
+++ b/roles/rook_ceph_cluster/tasks/main.yml
@@ -0,0 +1,125 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# 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.
+
+- name: Collect "ceph quorum_status" output from a monitor
+ run_once: true
+ delegate_to: "{{ groups[rook_ceph_cluster_mon_group][0] }}"
+ ansible.builtin.command: ceph quorum_status -f json
+ changed_when: false
+ register: _rook_ceph_cluster_quorum_status_data
+
+- name: Retrieve keyring for client.admin
+ run_once: true
+ delegate_to: "{{ groups[rook_ceph_cluster_mon_group][0] }}"
+ vexxhost.atmosphere.ceph_key:
+ name: client.admin
+ state: info
+ output_format: json
+ register: _rook_ceph_cluster_admin_auth_data
+
+- name: Retrieve keyring for monitors
+ run_once: true
+ delegate_to: "{{ groups[rook_ceph_cluster_mon_group][0] }}"
+ vexxhost.atmosphere.ceph_key:
+ name: mon.
+ state: info
+ output_format: json
+ register: _rook_ceph_cluster_mon_auth_data
+
+- name: Create Ceph cluster resource
+ run_once: true
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ - apiVersion: v1
+ kind: Secret
+ metadata:
+ name: rook-ceph-mon
+ namespace: "{{ rook_ceph_cluster_helm_release_namespace }}"
+ stringData:
+ cluster-name: "{{ rook_ceph_cluster_name }}"
+ fsid: "{{ _rook_ceph_cluster_quorum_status.monmap.fsid }}"
+ admin-secret: "{{ _rook_ceph_cluster_admin_auth.key }}"
+ mon-secret: "{{ _rook_ceph_cluster_mon_auth.key }}"
+
+ - apiVersion: v1
+ kind: ConfigMap
+ metadata:
+ name: rook-ceph-mon-endpoints
+ namespace: "{{ rook_ceph_cluster_helm_release_namespace }}"
+ data:
+ data: "{{ _rook_ceph_cluster_leader_name }}={{ _rook_ceph_cluster_leader_addr }}"
+ maxMonId: "0"
+ mapping: "{}"
+ vars:
+ _rook_ceph_cluster_quorum_status: "{{ _rook_ceph_cluster_quorum_status_data.stdout | from_json }}"
+ _rook_ceph_cluster_admin_auth: "{{ _rook_ceph_cluster_admin_auth_data.stdout | from_json | first }}"
+ _rook_ceph_cluster_mon_auth: "{{ _rook_ceph_cluster_mon_auth_data.stdout | from_json | first }}"
+ _rook_ceph_cluster_leader_name: "{{ _rook_ceph_cluster_quorum_status.quorum_leader_name }}"
+ _rook_ceph_cluster_leader_mon: "{{ (_rook_ceph_cluster_quorum_status.monmap.mons | selectattr('name', 'equalto', _rook_ceph_cluster_leader_name) | list | first) }}"
+ _rook_ceph_cluster_leader_addr: "{{ _rook_ceph_cluster_leader_mon.public_addr.split('/')[0] }}"
+
+- name: Deploy Helm chart
+ run_once: true
+ kubernetes.core.helm:
+ name: "{{ rook_ceph_cluster_helm_release_name }}"
+ chart_ref: "{{ rook_ceph_cluster_helm_chart_ref }}"
+ release_namespace: "{{ rook_ceph_cluster_helm_release_namespace }}"
+ create_namespace: true
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _rook_ceph_cluster_helm_values | combine(rook_ceph_cluster_helm_values, recursive=True) }}"
+
+- name: Create OpenStack user
+ openstack.cloud.identity_user:
+ cloud: atmosphere
+ name: "{{ openstack_helm_endpoints.identity.auth.rgw.username }}"
+ password: "{{ openstack_helm_endpoints.identity.auth.rgw.password }}"
+ domain: service
+
+- name: Grant access to "service" project
+ openstack.cloud.role_assignment:
+ cloud: atmosphere
+ domain: service
+ user: "{{ openstack_helm_endpoints.identity.auth.rgw.username }}"
+ project: service
+ role: admin
+
+- name: Create OpenStack service
+ openstack.cloud.catalog_service:
+ cloud: atmosphere
+ name: swift
+ service_type: object-store
+ description: OpenStack Object Storage
+
+- name: Create OpenStack endpoints
+ openstack.cloud.endpoint:
+ cloud: atmosphere
+ service: swift
+ endpoint_interface: "{{ item.interface }}"
+ url: "{{ item.url }}"
+ region: "{{ openstack_helm_endpoints.identity.auth.rgw.region_name }}"
+ loop:
+ - interface: public
+ url: "https://{{ openstack_helm_endpoints.rook_ceph_cluster.host_fqdn_override.public.host }}/swift/v1/%(tenant_id)s"
+ - interface: internal
+ url: "http://rook-ceph-rgw-ceph.openstack.svc.cluster.local/swift/v1/%(tenant_id)s"
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: rook_ceph_cluster
+ openstack_helm_ingress_service_name: rook-ceph-rgw-ceph
+ openstack_helm_ingress_service_port: 80
+ openstack_helm_ingress_annotations: "{{ _rook_ceph_cluster_radosgw_annotations | combine(rook_ceph_cluster_radosgw_annotations, recursive=True) }}"
diff --git a/roles/rook_ceph_cluster/vars/main.yml b/roles/rook_ceph_cluster/vars/main.yml
new file mode 100644
index 0000000..1ed5894
--- /dev/null
+++ b/roles/rook_ceph_cluster/vars/main.yml
@@ -0,0 +1,71 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# 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.
+
+_rook_ceph_cluster_spec:
+ cephVersion:
+ image: "{{ atmosphere_images['ceph'] | vexxhost.atmosphere.docker_image('ref') }}"
+ external:
+ enable: true
+
+_rook_ceph_cluster_radosgw_spec:
+ preservePoolsOnDelete: true
+ metadataPool:
+ failureDomain: host
+ replicated:
+ size: 3
+ dataPool:
+ failureDomain: host
+ replicated:
+ size: 3
+ gateway:
+ port: 80
+ instances: 3
+ placement:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: openstack-control-plane
+ operator: In
+ values: ["enabled"]
+
+_rook_ceph_cluster_helm_values:
+ clusterName: "{{ rook_ceph_cluster_name }}"
+ configOverride: |
+ [client]
+ rgw keystone api version = 3
+ rgw keystone url = http://keystone-api.openstack.svc.cluster.local:5000
+ rgw keystone admin user = "{{ openstack_helm_endpoints.identity.auth.rgw.username }}"
+ rgw keystone admin password = "{{ openstack_helm_endpoints.identity.auth.rgw.password }}"
+ rgw_keystone admin domain = service
+ rgw_keystone admin project = service
+ rgw keystone implicit tenants = true
+ rgw keystone accepted roles = member,admin
+ rgw_keystone accepted admin roles = admin
+ rgw keystone token cache size = 0
+ rgw s3 auth use keystone = true
+ rgw swift account in url = true
+ rgw swift versioning enabled = true
+ cephClusterSpec: "{{ _rook_ceph_cluster_spec | combine(rook_ceph_cluster_spec, recursive=True) }}"
+ cephBlockPools: []
+ cephFileSystems: []
+ cephObjectStores:
+ - name: "{{ rook_ceph_cluster_name }}"
+ spec: "{{ _rook_ceph_cluster_radosgw_spec | combine(rook_ceph_cluster_radosgw_spec, recursive=True) }}"
+ storageClass:
+ enabled: false
+
+_rook_ceph_cluster_radosgw_annotations:
+ nginx.ingress.kubernetes.io/proxy-body-size: "0"
+ nginx.ingress.kubernetes.io/proxy-request-buffering: "off"