Add tempest role

Sem-Ver: feature
Change-Id: I2bc7f206cda99b76aa8bc23b864f53120de27185
diff --git a/roles/openstack_helm_endpoints/defaults/main.yml b/roles/openstack_helm_endpoints/defaults/main.yml
index 1fef800..70aa15c 100644
--- a/roles/openstack_helm_endpoints/defaults/main.yml
+++ b/roles/openstack_helm_endpoints/defaults/main.yml
@@ -407,3 +407,15 @@
 openstack_helm_endpoints_horizon_mariadb_password: "{{ undef(hint='You must specify a Horizon MariaDB password') }}"
 
                                                                    # ]]]
+# .. envvar:: openstack_helm_endpoints_tempest_region_name [[[
+#
+# Region name for service
+openstack_helm_endpoints_tempest_region_name: "{{ openstack_helm_endpoints_region_name }}"
+
+                                                                   # ]]]
+# .. envvar:: openstack_helm_endpoints_tempest_keystone_password [[[
+#
+# Keystone password for service
+openstack_helm_endpoints_tempest_keystone_password: "{{ undef(hint='You must specify a Tempest Keystone password') }}"
+
+                                                                   # ]]]
diff --git a/roles/openstack_helm_endpoints/vars/main.yml b/roles/openstack_helm_endpoints/vars/main.yml
index f575e92..cc77ab1 100644
--- a/roles/openstack_helm_endpoints/vars/main.yml
+++ b/roles/openstack_helm_endpoints/vars/main.yml
@@ -401,3 +401,11 @@
     auth:
       horizon:
         password: "{{ openstack_helm_endpoints_horizon_mariadb_password }}"
+
+_openstack_helm_endpoints_tempest:
+  identity:
+    auth:
+      tempest:
+        region_name: "{{ openstack_helm_endpoints_tempest_region_name }}"
+        username: "tempest-{{ openstack_helm_endpoints_tempest_region_name }}"
+        password: "{{ openstack_helm_endpoints_tempest_keystone_password }}"
diff --git a/roles/openstack_helm_tempest/defaults/main.yml b/roles/openstack_helm_tempest/defaults/main.yml
new file mode 100644
index 0000000..6ccf3b3
--- /dev/null
+++ b/roles/openstack_helm_tempest/defaults/main.yml
@@ -0,0 +1,55 @@
+---
+# .. vim: foldmarker=[[[,]]]:foldmethod=marker
+
+# .. Copyright (C) 2022 VEXXHOST, Inc.
+# .. SPDX-License-Identifier: Apache-2.0
+
+# Default variables
+# =================
+
+# .. contents:: Sections
+#    :local:
+
+
+# .. envvar:: openstack_helm_tempest_chart_repo_name [[[
+#
+# Helm repository name for the chart.
+openstack_helm_tempest_chart_repo_name: openstack-helm
+
+                                                                   # ]]]
+# .. envvar:: openstack_helm_tempest_chart_repo_url [[[
+#
+# Helm repository URL for the chart.
+openstack_helm_tempest_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm/
+
+                                                                   # ]]]
+# .. envvar:: openstack_helm_tempest_chart_name [[[
+#
+# Helm chart name (will also be used for release name)
+openstack_helm_tempest_chart_name: tempest
+
+                                                                   # ]]]
+# .. envvar:: openstack_helm_tempest_image_repository [[[
+#
+# Image repository location to be prefixed for all images
+openstack_helm_tempest_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+
+                                                                   # ]]]
+# .. envvar:: openstack_helm_tempest_image_tag [[[
+#
+# Image tag for container
+openstack_helm_tempest_image_tag: 30.1.0-4
+
+                                                                   # ]]]
+# .. envvar:: openstack_helm_tempest_heat_image_tag [[[
+#
+# Image tag for Heat to be used for jobs running via Helm hooks
+openstack_helm_tempest_heat_image_tag: wallaby
+
+                                                                   # ]]]
+# .. envvar:: openstack_helm_tempest_values [[[
+#
+# Overrides for Helm chart values
+openstack_helm_tempest_values: {}
+
+                                                                   # ]]]
diff --git a/roles/openstack_helm_tempest/meta/main.yml b/roles/openstack_helm_tempest/meta/main.yml
new file mode 100644
index 0000000..d9b9461
--- /dev/null
+++ b/roles/openstack_helm_tempest/meta/main.yml
@@ -0,0 +1,29 @@
+# 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 OpenStack Tempest
+  license: Apache-2.0
+  min_ansible_version: 5.5.0
+  platforms:
+    - name: Ubuntu
+      versions:
+        - focal
+
+dependencies:
+  - role: helm_repository
+    vars:
+      helm_repository_name: "{{ openstack_helm_tempest_chart_repo_name }}"
+      helm_repository_repo_url: "{{ openstack_helm_tempest_chart_repo_url }}"
diff --git a/roles/openstack_helm_tempest/tasks/main.yml b/roles/openstack_helm_tempest/tasks/main.yml
new file mode 100644
index 0000000..4094809
--- /dev/null
+++ b/roles/openstack_helm_tempest/tasks/main.yml
@@ -0,0 +1,141 @@
+# 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: Generate OpenStack-Helm endpoints
+  ansible.builtin.include_role:
+    name: openstack_helm_endpoints
+  vars:
+    openstack_helm_endpoints_repo_name: "{{ openstack_helm_tempest_chart_repo_name }}"
+    openstack_helm_endpoints_repo_url: "{{ openstack_helm_tempest_chart_repo_url }}"
+    openstack_helm_endpoints_chart: "{{ openstack_helm_tempest_chart_name }}"
+
+- name: Configure tempest
+  block:
+    - name: Get test image object
+      openstack.cloud.image_info:
+        auth:
+          auth_url: "https://{{ openstack_helm_endpoints['identity']['host_fqdn_override']['public']['host'] }}"
+          username: "{{ openstack_helm_endpoints['identity']['auth']['admin']['username'] }}"
+          password: "{{ openstack_helm_endpoints['identity']['auth']['admin']['password'] }}"
+          project_name: admin
+          user_domain_name: Default
+          project_domain_name: Default
+        image: cirros
+      register: _openstack_helm_tempest_test_image
+      when: openstack_helm_tempest_values.conf.tempest.compute.image_ref is not defined
+
+    - name: Configure test image ref
+      ansible.builtin.set_fact:
+        openstack_helm_tempest_values: "{{ openstack_helm_tempest_values | default({}) | combine({item.key: item.value}, recursive=True) }}"
+      with_dict:
+        conf:
+          tempest:
+            compute:
+              image_ref: "{{ _openstack_helm_tempest_test_image.openstack_image.id }}"
+      when:
+        - openstack_helm_tempest_values.conf.tempest.compute.image_ref is not defined
+        - _openstack_helm_tempest_test_image.openstack_image.id is defined
+
+    - name: Get test flavor object
+      openstack.cloud.compute_flavor_info:
+        auth:
+          auth_url: "https://{{ openstack_helm_endpoints['identity']['host_fqdn_override']['public']['host'] }}"
+          username: "{{ openstack_helm_endpoints['identity']['auth']['admin']['username'] }}"
+          password: "{{ openstack_helm_endpoints['identity']['auth']['admin']['password'] }}"
+          project_name: admin
+          user_domain_name: Default
+          project_domain_name: Default
+        name: m1.tiny
+      register: _openstack_helm_tempest_test_flavor
+      when: openstack_helm_tempest_values.conf.tempest.compute.flavor_ref is not defined
+
+    - name: Set test flavor ref
+      ansible.builtin.set_fact:
+        openstack_helm_tempest_values: "{{ openstack_helm_tempest_values | default({}) | combine({item.key: item.value}, recursive=True) }}"
+      with_dict:
+        conf:
+          tempest:
+            compute:
+              flavor_ref: "{{ _openstack_helm_tempest_test_flavor.openstack_flavors[0].id }}"
+      when:
+        - openstack_helm_tempest_values.conf.tempest.compute.flavor_ref is not defined
+        - _openstack_helm_tempest_test_flavor.openstack_flavors[0].id is defined
+
+    - name: Get test network object
+      openstack.cloud.networks_info:
+        auth:
+          auth_url: "https://{{ openstack_helm_endpoints['identity']['host_fqdn_override']['public']['host'] }}"
+          username: "{{ openstack_helm_endpoints['identity']['auth']['admin']['username'] }}"
+          password: "{{ openstack_helm_endpoints['identity']['auth']['admin']['password'] }}"
+          project_name: admin
+          user_domain_name: Default
+          project_domain_name: Default
+        name: public
+      register: _openstack_helm_tempest_test_network
+      when: openstack_helm_tempest_values.conf.tempest.network.public_network_id is not defined
+
+    - name: Set test network ref
+      ansible.builtin.set_fact:
+        openstack_helm_tempest_values: "{{ openstack_helm_tempest_values | default({}) | combine({item.key: item.value}, recursive=True) }}"
+      with_dict:
+        conf:
+          tempest:
+            network:
+              public_network_id: "{{ _openstack_helm_tempest_test_network.openstack_networks[0].id }}"
+      when:
+        - openstack_helm_tempest_values.conf.tempest.network.public_network_id is not defined
+        - _openstack_helm_tempest_test_network.openstack_networks[0].id is defined
+
+- name: Deploy Helm chart
+  kubernetes.core.helm:
+    name: "{{ openstack_helm_tempest_chart_name }}"
+    chart_ref: "{{ openstack_helm_tempest_chart_repo_name }}/{{ openstack_helm_tempest_chart_name }}"
+    chart_version: 0.2.3
+    release_namespace: openstack
+    kubeconfig: /etc/kubernetes/admin.conf
+    wait: true
+    wait_timeout: 20m
+    values: "{{ _openstack_helm_tempest_values | combine(openstack_helm_tempest_values, recursive=True) }}"
+
+- name: Get tempest job object
+  kubernetes.core.k8s_info:
+    api_version: batch/v1
+    kind: Job
+    name: tempest-run-tests
+    namespace: openstack
+  register: _tempest_job_obj
+
+- name: Get tempest log
+  kubernetes.core.k8s_log:
+    namespace: openstack
+    label_selectors:
+      - job-name=tempest-run-tests
+  register: _tempest_log
+
+- name: Print success tempest result
+  ansible.builtin.debug:
+    msg: "Tempest success!"
+  when:
+    - _tempest_job_obj.resources[0]['status']['succeeded'] is defined
+    - _tempest_job_obj.resources[0]['status']['succeeded'] == 1
+
+- name: Print failed tempest result
+  ansible.builtin.debug:
+    msg: "Tempest failed!"
+  when: _tempest_job_obj.resources[0]['status']['succeeded'] is not defined or
+        _tempest_job_obj.resources[0]['status']['succeeded'] != 1
+
+- name: Print tempest log details
+  ansible.builtin.debug:
+    msg: "{{ _tempest_log.log_lines }}"
diff --git a/roles/openstack_helm_tempest/vars/main.yml b/roles/openstack_helm_tempest/vars/main.yml
new file mode 100644
index 0000000..8a97656
--- /dev/null
+++ b/roles/openstack_helm_tempest/vars/main.yml
@@ -0,0 +1,55 @@
+# 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.
+
+_openstack_helm_tempest_values:
+  endpoints: "{{ openstack_helm_endpoints }}"
+  images:
+    tags:
+      dep_check: "{{ openstack_helm_tempest_image_repository }}/kubernetes-entrypoint:latest"
+      tempest_run_tests: "{{ openstack_helm_tempest_image_repository }}/tempest:{{ openstack_helm_tempest_image_tag }}"
+      ks_user: "{{ openstack_helm_tempest_image_repository }}/heat:{{ openstack_helm_tempest_heat_image_tag }}"
+  jobs:
+    run_tests:
+      restartPolicy: Never
+      backoffLimit: 0
+  conf:
+    tempest:
+      service_available:
+        cinder: true
+        glance: true
+        horizon: true
+        neutron: true
+        nova: true
+        swift: false
+      compute:
+        endpoint_type: internal
+        fixed_network_name: public
+      dashboard:
+        dashboard_url: "http://horizon-int.openstack.svc.cluster.local"
+      image:
+        endpoint_type: internal
+      network:
+        endpoint_type: internal
+        floating_network_name: public
+        shared_physical_network: false
+      placement:
+        endpoint_type: internal
+      validation:
+        image_ssh_user: cirros
+      volume:
+        endpoint_type: internal
+      object-storage:
+        endpoint_type: internal
+  pvc:
+    enabled: false