Add keepalived role
Sem-Ver: feature
Change-Id: Ibb54fa4cefe2393eb86a9f1646d108448a589a7e
diff --git a/doc/source/roles/keepalived/index.rst b/doc/source/roles/keepalived/index.rst
new file mode 100644
index 0000000..de5844e
--- /dev/null
+++ b/doc/source/roles/keepalived/index.rst
@@ -0,0 +1,10 @@
+.. Copyright (C) 2022 VEXXHOST, Inc.
+.. SPDX-License-Identifier: Apache-2.0
+
+``keepalived``
+================
+
+.. toctree::
+ :maxdepth: 2
+
+ defaults/main
\ No newline at end of file
diff --git a/playbooks/generate_workspace.yml b/playbooks/generate_workspace.yml
index 9dec792..02f4fd4 100644
--- a/playbooks/generate_workspace.yml
+++ b/playbooks/generate_workspace.yml
@@ -134,6 +134,39 @@
content: "{{ kubernetes | to_nice_yaml(indent=2, width=180) }}"
dest: "{{ _kubernetes_path }}"
+- name: Generate Keepalived configuration for workspace
+ hosts: localhost
+ gather_facts: false
+ vars:
+ _keepalived_path: "{{ workspace_path }}/group_vars/all/keepalived.yml"
+ tasks:
+ - name: Ensure the Keeaplived configuration file exists
+ ansible.builtin.file:
+ path: "{{ _keepalived_path }}"
+ state: touch
+
+ - name: Load the current Keepalived configuration into a variable
+ ansible.builtin.include_vars:
+ file: "{{ _keepalived_path }}"
+ name: keepalived
+
+ - name: Generate Keepalived values for missing variables
+ ansible.builtin.set_fact:
+ keepalived: "{{ keepalived | default({}) | combine({item.key: item.value}) }}"
+ # NOTE(mnaser): We don't want to override existing Keepalived configurations,
+ # so we generate a stub one if and only if it doesn't exist
+ when: item.key not in keepalived
+ # NOTE(mnaser): This is absolutely hideous but there's no clean way of
+ # doing this using `with_fileglob` or `with_filetree`
+ with_dict:
+ keepalived_interface: ens4
+ keepalived_vip: 10.96.250.10
+
+ - name: Write new Keepalived configuration file to disk
+ ansible.builtin.copy:
+ content: "{{ keepalived | to_nice_yaml(indent=2, width=180) }}"
+ dest: "{{ _keepalived_path }}"
+
- name: Generate endpoints for workspace
hosts: localhost
gather_facts: false
diff --git a/playbooks/openstack.yml b/playbooks/openstack.yml
index e005549..019d33d 100644
--- a/playbooks/openstack.yml
+++ b/playbooks/openstack.yml
@@ -48,6 +48,10 @@
tags:
- cert-manager
+ - role: keepalived
+ tags:
+ - keepalived
+
- role: percona_xtradb_cluster
tags:
- percona-xtradb-cluster
diff --git a/releasenotes/notes/keepalived-add-role-1b2ad22c86e253ba.yaml b/releasenotes/notes/keepalived-add-role-1b2ad22c86e253ba.yaml
new file mode 100644
index 0000000..9634c55
--- /dev/null
+++ b/releasenotes/notes/keepalived-add-role-1b2ad22c86e253ba.yaml
@@ -0,0 +1,3 @@
+---
+features:
+ - Add role for keepalived in openstack namespace
diff --git a/roles/keepalived/defaults/main.yml b/roles/keepalived/defaults/main.yml
new file mode 100644
index 0000000..5b0e8d9
--- /dev/null
+++ b/roles/keepalived/defaults/main.yml
@@ -0,0 +1,49 @@
+---
+# .. vim: foldmarker=[[[,]]]:foldmethod=marker
+
+# .. Copyright (C) 2022 VEXXHOST, Inc.
+# .. SPDX-License-Identifier: Apache-2.0
+
+# Default variables
+# =================
+
+# .. contents:: Sections
+# :local:
+
+
+# .. envvar:: keepalived_password [[[
+#
+# Keepalived password
+keepalived_password: "{{ undef(hint='You must specify a Keepalived password') }}"
+
+ # ]]]
+# .. envvar:: keepalived_vip [[[
+#
+# Keepalived virtual IP address
+keepalived_vip: "{{ undef(hint='You must specify a Keepalived virtual IP address') }}"
+
+ # ]]]
+# .. envvar:: keepalived_interface [[[
+#
+# Keepalived virtual IP interface
+keepalived_interface: "{{ undef(hint='You must specify a Keepalived virtual IP interface') }}"
+
+ # ]]]
+# .. envvar:: keepalived_image_repository [[[
+#
+# Keepalived container image repository location
+keepalived_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+
+ # ]]]
+# .. envvar:: keepalived_image_tag [[[
+#
+# Keepalived container image tag
+keepalived_image_tag: 2.0.19
+
+ # ]]]
+# .. envvar:: keepalived_vrid [[[
+#
+# Keepalived virtual router id
+keepalived_vrid: 51
+
+ # ]]]
diff --git a/roles/keepalived/meta/main.yml b/roles/keepalived/meta/main.yml
new file mode 100644
index 0000000..39b6ca5
--- /dev/null
+++ b/roles/keepalived/meta/main.yml
@@ -0,0 +1,23 @@
+# 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 keepalived
+ license: Apache-2.0
+ min_ansible_version: 5.5.0
+ platforms:
+ - name: Ubuntu
+ versions:
+ - focal
diff --git a/roles/keepalived/tasks/main.yml b/roles/keepalived/tasks/main.yml
new file mode 100644
index 0000000..c97d66b
--- /dev/null
+++ b/roles/keepalived/tasks/main.yml
@@ -0,0 +1,200 @@
+# 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.
+
+- name: Create Secret
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Secret
+ metadata:
+ name: keepalived-etc
+ namespace: openstack
+ stringData:
+ keepalived.conf: |
+ global_defs {
+ default_interface {{ keepalived_interface }}
+ }
+
+ vrrp_instance VI_1 {
+ interface {{ keepalived_interface }}
+
+ state BACKUP
+ virtual_router_id {{ keepalived_vrid }}
+ priority 150
+ nopreempt
+
+ virtual_ipaddress {
+ {{ keepalived_vip }}
+ }
+
+ authentication {
+ auth_type PASS
+ auth_pass {{ keepalived_password }}
+ }
+ }
+
+- name: Create ConfigMap
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: ConfigMap
+ metadata:
+ name: keepalived-bin
+ namespace: openstack
+ data:
+ wait-for-ip.sh: |
+ #!/bin/sh -x
+
+ while true; do
+ ip -4 addr list dev {{ keepalived_interface }} | grep {{ keepalived_interface }}
+
+ # We detected an IP address
+ if [ $? -eq 0 ]; then
+ break
+ fi
+
+ sleep 1
+ done
+
+- name: Create Role
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: rbac.authorization.k8s.io/v1
+ kind: Role
+ metadata:
+ name: keepalived
+ namespace: openstack
+ rules:
+ - apiGroups:
+ - ""
+ resources:
+ - pods
+ verbs:
+ - list
+ - get
+
+- name: Create ServiceAccount
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ automountServiceAccountToken: true
+ kind: ServiceAccount
+ metadata:
+ name: keepalived
+ namespace: openstack
+
+- name: Create ServiceAccount
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: rbac.authorization.k8s.io/v1
+ kind: RoleBinding
+ metadata:
+ name: keepalived
+ namespace: openstack
+ roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: keepalived
+ subjects:
+ - kind: ServiceAccount
+ name: keepalived
+ namespace: openstack
+
+- name: Create DaemonSet
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: apps/v1
+ kind: DaemonSet
+ metadata:
+ name: keepalived
+ namespace: openstack
+ spec:
+ selector:
+ matchLabels:
+ application: keepalived
+ template:
+ metadata:
+ labels:
+ application: keepalived
+ spec:
+ automountServiceAccountToken: true
+ initContainers:
+ - name: init
+ image: "{{ keepalived_image_repository }}/kubernetes-entrypoint:latest"
+ env:
+ - name: NAMESPACE
+ valueFrom:
+ fieldRef:
+ apiVersion: v1
+ fieldPath: metadata.namespace
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ apiVersion: v1
+ fieldPath: metadata.name
+ - name: DEPENDENCY_POD_JSON
+ value: '[{"labels":{"application":"neutron","component":"neutron-ovs-agent"},"requireSameNode":true}]'
+ - name: wait-for-ip
+ image: "{{ keepalived_image_repository }}/keepalived:{{ keepalived_image_tag }}"
+ command:
+ - /bin/wait-for-ip.sh
+ volumeMounts:
+ - mountPath: /bin/wait-for-ip.sh
+ mountPropagation: None
+ name: keepalived-bin
+ readOnly: true
+ subPath: wait-for-ip.sh
+ containers:
+ - name: keepalived
+ image: "{{ keepalived_image_repository }}/keepalived:{{ keepalived_image_tag }}"
+ command:
+ - keepalived
+ - -f
+ - /etc/keepalived/keepalived.conf
+ - --dont-fork
+ - --log-console
+ - --log-detail
+ - --dump-conf
+ securityContext:
+ allowPrivilegeEscalation: true
+ capabilities:
+ add:
+ - NET_ADMIN
+ - NET_BROADCAST
+ - NET_RAW
+ volumeMounts:
+ - mountPath: /etc/keepalived
+ mountPropagation: None
+ name: keepalived-etc
+ readOnly: true
+ hostNetwork: true
+ nodeSelector:
+ openstack-control-plane: enabled
+ serviceAccountName: keepalived
+ volumes:
+ - name: keepalived-etc
+ secret:
+ optional: false
+ secretName: keepalived-etc
+ - configMap:
+ defaultMode: 0755
+ name: keepalived-bin
+ optional: false
+ name: keepalived-bin