aboutsummaryrefslogtreecommitdiffstats
path: root/deployment/noheat
diff options
context:
space:
mode:
Diffstat (limited to 'deployment/noheat')
-rw-r--r--deployment/noheat/README.rst48
-rw-r--r--deployment/noheat/cluster-rke/ansible/create.yml63
-rw-r--r--deployment/noheat/cluster-rke/ansible/group_vars/all.yml.sm-onap11
l---------deployment/noheat/cluster-rke/ansible/group_vars/all/all.yml1
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/create_bastion/tasks/main.yml35
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/deps/defaults/main.yml11
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/deps/files/envoyfilter-case.yml41
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/deps/tasks/cert-manager.yml17
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/deps/tasks/istio.yml55
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/deps/tasks/main.yml19
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/deps/tasks/metallb.yml51
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/deps/tasks/prometheus.yml13
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/deps/tasks/strimzi.yml15
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/oom/tasks/main.yml66
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_docker/defaults/main.yml3
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_docker/handlers/main.yml5
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_docker/tasks/main.yml26
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_docker/tasks/packages.yml41
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_docker/vars/main.yml8
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_helm/defaults/main.yml7
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_helm/handlers/main.yml5
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/cm.yml45
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/helm.yml35
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/main.yml12
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_helm/templates/chartmuseum.service.j213
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_k8s/defaults/main.yml3
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/kubectl.yml13
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/main.yml16
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/rke.yml25
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_k8s/templates/cluster.yml.j252
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_nfs/defaults/main.yml2
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_nfs/tasks/main.yml59
-rw-r--r--deployment/noheat/cluster-rke/ansible/roles/setup_nfs/templates/exports.j21
-rw-r--r--deployment/noheat/common-vars.yml2
-rw-r--r--deployment/noheat/deploy-all.yml9
-rw-r--r--deployment/noheat/devstack/ansible/create.yml43
-rw-r--r--deployment/noheat/devstack/ansible/group_vars/all/all.yml3
-rw-r--r--deployment/noheat/devstack/ansible/templates/local.conf.j25
-rw-r--r--deployment/noheat/infra-openstack/HACKING.rst30
-rw-r--r--deployment/noheat/infra-openstack/README.rst34
-rw-r--r--deployment/noheat/infra-openstack/ansible/create.yml136
-rw-r--r--deployment/noheat/infra-openstack/ansible/destroy.yml15
-rw-r--r--deployment/noheat/infra-openstack/ansible/group_vars/all.yml.sample63
-rw-r--r--deployment/noheat/infra-openstack/ansible/group_vars/all.yml.sm-onap86
l---------deployment/noheat/infra-openstack/ansible/group_vars/all/all.yml1
-rw-r--r--deployment/noheat/infra-openstack/ansible/group_vars/all/openstack.yml6
-rw-r--r--deployment/noheat/infra-openstack/ansible/operator-requirements.yml8
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/create_hosts/tasks/create_host.yml33
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/create_hosts/tasks/main.yml5
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/create_keypair/tasks/main.yml25
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/create_network/tasks/create_network.yml28
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/create_network/tasks/main.yml6
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/create_securitygroup/tasks/create_securitygroup.yml23
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/create_securitygroup/tasks/main.yml6
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/destroy_hosts/tasks/destroy_host.yml5
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/destroy_hosts/tasks/main.yml5
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/destroy_keypair/tasks/main.yml12
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/destroy_network/tasks/destroy_network.yml10
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/destroy_network/tasks/main.yml6
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/destroy_securitygroup/tasks/destroy_securitygroup.yml5
-rw-r--r--deployment/noheat/infra-openstack/ansible/roles/destroy_securitygroup/tasks/main.yml6
-rw-r--r--deployment/noheat/infra-openstack/ansible/templates/clouds.yaml.j211
-rw-r--r--deployment/noheat/infra-openstack/ansible/templates/inventory.ini.j253
-rw-r--r--deployment/noheat/infra-openstack/ansible/templates/openstack.yml.j25
-rw-r--r--deployment/noheat/infra-openstack/vagrant/Vagrantfile167
-rw-r--r--deployment/noheat/infra-openstack/vagrant/config/clouds.yaml12
-rw-r--r--deployment/noheat/infra-openstack/vagrant/config/local.conf6
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/Makefile12
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/README.rst31
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/create_host.stderr0
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/create_host.stdout1
-rwxr-xr-xdeployment/noheat/infra-openstack/vagrant/test/create_host.test27
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/create_keypair.stderr0
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/create_keypair.stdout1
-rwxr-xr-xdeployment/noheat/infra-openstack/vagrant/test/create_keypair.test27
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/create_network.stderr0
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/create_network.stdout1
-rwxr-xr-xdeployment/noheat/infra-openstack/vagrant/test/create_network.test27
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.stderr0
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.stdout1
-rwxr-xr-xdeployment/noheat/infra-openstack/vagrant/test/create_securitygroup.test27
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/destroy_host.stderr0
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/destroy_host.stdout1
-rwxr-xr-xdeployment/noheat/infra-openstack/vagrant/test/destroy_host.test22
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.stderr0
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.stdout1
-rwxr-xr-xdeployment/noheat/infra-openstack/vagrant/test/destroy_keypair.test22
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/destroy_network.stderr0
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/destroy_network.stdout1
-rwxr-xr-xdeployment/noheat/infra-openstack/vagrant/test/destroy_network.test22
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.stderr0
-rw-r--r--deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.stdout1
-rwxr-xr-xdeployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.test22
-rw-r--r--deployment/noheat/requirements.txt3
-rw-r--r--deployment/noheat/requirements.yml10
95 files changed, 1947 insertions, 0 deletions
diff --git a/deployment/noheat/README.rst b/deployment/noheat/README.rst
new file mode 100644
index 000000000..a75ad2bb2
--- /dev/null
+++ b/deployment/noheat/README.rst
@@ -0,0 +1,48 @@
+================================
+ ONAP on Openstack without Heat
+================================
+
+Ansible roles and sample playbooks for automatic deployments for system testing and continuous
+integration test flows. These will orchestrate Openstack virtual machines setup for a Kubernetes
+cluster, a Rancher Kubernetes Engine (RKE) deployment, a DevStack deployment and an ONAP deployment.
+
+They will be used in Service Mesh lab.
+
+Prerequisites
+-------------
+
+Infrastructure
+~~~~~~~~~~~~~~
+
+- OpenStack cloud (no Heat support required)
+
+Configuration
+~~~~~~~~~~~~~
+
+- OpenStack ``clouds.yaml`` file
+
+Dependencies
+~~~~~~~~~~~~
+
+- Required python packages (including Ansible) can be found in ``requirements.txt`` pip file.
+ Tested on Python 3.8.10.
+- Ansible required collections & roles can be found in ``requirements.yml`` file for installation
+ with ansible-galaxy tool.
+
+Expected output
+---------------
+
+Ephemeral (disposable) ONAP instance.
+
+Running
+-------
+
+There are 4 playbooks available:
+
+- infa-openstack/ansible/create.yml: creates and prepares OpenStack VMs, generates inventory.
+ Must be run as a first playbook. Run on your machine.
+- devstack/ansible/create.yml: deploys Devstack on appropriate VM. Run on jumphost VM (operator0).
+- cluster-rke/ansible/create.yml: deploys NFS, k8s, helm charts and ONAP. Run on jumphost VM.
+- deploy-all.yml: runs above playbooks. Run on your machine.
+
+User may run deploy-all.yml or manually run infra-openstack, devstack and cluster-rke playbooks.
diff --git a/deployment/noheat/cluster-rke/ansible/create.yml b/deployment/noheat/cluster-rke/ansible/create.yml
new file mode 100644
index 000000000..920db966d
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/create.yml
@@ -0,0 +1,63 @@
+---
+- name: Update packages
+ hosts: operator
+ become: true
+ tasks:
+ - name: Update ca-certificates
+ package:
+ name: ca-certificates
+ state: latest
+- name: Install NFS
+ hosts: all
+ become: yes
+ roles:
+ - role: setup_nfs
+- name: Set up bastion node for ONAP Docker registry
+ hosts: "nfs0"
+ become: yes
+ roles:
+ - role: create_bastion
+ destination: "{{ nexus }}"
+- name: Add bastion information to the cluster nodes
+ hosts: control,workers
+ become: yes
+ tasks:
+ - name: Add cluster hostnames to /etc/hosts file
+ lineinfile:
+ path: /etc/hosts
+ line: "{{ hostvars['nfs0']['ansible_default_ipv4']['address'] }} {{ item }}"
+ loop:
+ - "nexus3.onap.org"
+- name: Install Docker
+ become: yes
+ hosts: operator,control,workers
+ roles:
+ - role: setup_docker
+- name: Deploy k8s
+ hosts: operator0
+ vars_files:
+ - ~/common-vars.yml
+ roles:
+ - role: setup_k8s
+- name: Download OOM
+ hosts: operator0
+ tasks:
+ - name: Clone OOM
+ git:
+ repo: "https://git.onap.org/oom"
+ dest: "{{ oom_dir }}"
+ version: "{{ onap_branch }}"
+- name: Install Helm
+ hosts: operator0
+ roles:
+ - role: setup_helm
+- name: Install metallb, cert-manager and prometheus
+ hosts: operator0
+ gather_facts: false
+ roles:
+ - role: deps
+- name: Deploy sm-onap
+ hosts: operator0
+ gather_facts: false
+ roles:
+ - role: oom
diff --git a/deployment/noheat/cluster-rke/ansible/group_vars/all.yml.sm-onap b/deployment/noheat/cluster-rke/ansible/group_vars/all.yml.sm-onap
new file mode 100644
index 000000000..9fb3313ee
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/group_vars/all.yml.sm-onap
@@ -0,0 +1,11 @@
+---
+nexus:
+ address: 199.204.45.137
+ port: 10001
+oom_dir: "{{ ansible_user_dir }}/oom"
+onap_branch: "master"
+override_file: "{{ oom_dir }}/kubernetes/onap/resources/overrides/sm-onap.yaml"
+integration_dir: "{{ ansible_user_dir }}/integration"
+prometheus_enabled: true
+metallb_enabled: true
+istio_enabled: true
diff --git a/deployment/noheat/cluster-rke/ansible/group_vars/all/all.yml b/deployment/noheat/cluster-rke/ansible/group_vars/all/all.yml
new file mode 120000
index 000000000..206526103
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/group_vars/all/all.yml
@@ -0,0 +1 @@
+../all.yml.sm-onap \ No newline at end of file
diff --git a/deployment/noheat/cluster-rke/ansible/roles/create_bastion/tasks/main.yml b/deployment/noheat/cluster-rke/ansible/roles/create_bastion/tasks/main.yml
new file mode 100644
index 000000000..8189968c4
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/create_bastion/tasks/main.yml
@@ -0,0 +1,35 @@
+- name: Add cluster hostnames to /etc/hosts file
+ lineinfile:
+ path: /etc/hosts
+ line: "{{ ansible_default_ipv4.address + ' ' + ansible_hostname }}"
+
+- name: Enable IP forwarding
+ ansible.posix.sysctl:
+ name: net.ipv4.ip_forward
+ value: '1'
+ sysctl_set: yes
+
+- name: Create PREROUTING rule
+ ansible.builtin.iptables:
+ table: nat
+ chain: PREROUTING
+ protocol: tcp
+ destination_port: "{{ destination.port }}"
+ jump: DNAT
+ to_destination: "{{ destination.address }}:{{ destination.port }}"
+
+- name: Create OUTPUT rule
+ ansible.builtin.iptables:
+ table: nat
+ chain: OUTPUT
+ protocol: tcp
+ destination: "{{ ansible_default_ipv4.address }}"
+ destination_port: "{{ destination.port }}"
+ jump: DNAT
+ to_destination: "{{ destination.address }}"
+
+- name: Enable masquerading
+ ansible.builtin.iptables:
+ table: nat
+ chain: POSTROUTING
+ jump: MASQUERADE
diff --git a/deployment/noheat/cluster-rke/ansible/roles/deps/defaults/main.yml b/deployment/noheat/cluster-rke/ansible/roles/deps/defaults/main.yml
new file mode 100644
index 000000000..6a3594628
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/deps/defaults/main.yml
@@ -0,0 +1,11 @@
+---
+cert_manager_version: "1.5.5"
+prometheus_enabled: true
+prometheus_version: "19.3.0"
+metallb_enabled: true
+metallb_version: "0.13.7"
+metallb_addresses: "192.168.1.129-192.168.1.255"
+istio_enabled: true
+istio_version: "1.14.5"
+strimzi_enabled: true
+strimzi_version: "0.31.1"
diff --git a/deployment/noheat/cluster-rke/ansible/roles/deps/files/envoyfilter-case.yml b/deployment/noheat/cluster-rke/ansible/roles/deps/files/envoyfilter-case.yml
new file mode 100644
index 000000000..8edcf09c5
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/deps/files/envoyfilter-case.yml
@@ -0,0 +1,41 @@
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: EnvoyFilter
+metadata:
+ name: header-casing
+ namespace: istio-config
+spec:
+ configPatches:
+ - applyTo: CLUSTER
+ match:
+ context: ANY
+ patch:
+ operation: MERGE
+ value:
+ typed_extension_protocol_options:
+ envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
+ '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
+ use_downstream_protocol_config:
+ http_protocol_options:
+ header_key_format:
+ stateful_formatter:
+ name: preserve_case
+ typed_config:
+ '@type': type.googleapis.com/envoy.extensions.http.header_formatters.preserve_case.v3.PreserveCaseFormatterConfig
+ - applyTo: NETWORK_FILTER
+ match:
+ listener:
+ filterChain:
+ filter:
+ name: envoy.filters.network.http_connection_manager
+ patch:
+ operation: MERGE
+ value:
+ typed_config:
+ '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
+ http_protocol_options:
+ header_key_format:
+ stateful_formatter:
+ name: preserve_case
+ typed_config:
+ '@type': type.googleapis.com/envoy.extensions.http.header_formatters.preserve_case.v3.PreserveCaseFormatterConfig
diff --git a/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/cert-manager.yml b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/cert-manager.yml
new file mode 100644
index 000000000..5a14d93ce
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/cert-manager.yml
@@ -0,0 +1,17 @@
+---
+- name: Check if cert-manager manifest file is present
+ stat:
+ path: /tmp/cert-manager.yaml
+ register: cm_manifest
+
+- name: Download cert-manager
+ get_url:
+ url: "https://github.com/jetstack/cert-manager/releases/download/v{{ cert_manager_version }}/cert-manager.yaml"
+ dest: "/tmp"
+ mode: '0400'
+ when: not cm_manifest.stat.exists
+
+- name: Deploy cert-manager
+ kubernetes.core.k8s:
+ src: /tmp/cert-manager.yaml
+ state: present
diff --git a/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/istio.yml b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/istio.yml
new file mode 100644
index 000000000..89b848636
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/istio.yml
@@ -0,0 +1,55 @@
+---
+- name: Add Istio Helm repository
+ kubernetes.core.helm_repository:
+ name: istio
+ repo_url: https://istio-release.storage.googleapis.com/charts
+
+- name: Create Istio config namespace
+ kubernetes.core.k8s:
+ name: istio-config
+ api_version: v1
+ kind: Namespace
+ state: present
+
+- name: Deploy Istio base chart
+ kubernetes.core.helm:
+ name: istio-base
+ chart_version: "{{ istio_version }}"
+ chart_ref: istio/base
+ release_namespace: istio-system
+ create_namespace: true
+
+- name: Deploy Istio discovery chart
+ kubernetes.core.helm:
+ name: istiod
+ chart_version: "{{ istio_version }}"
+ chart_ref: istio/istiod
+ release_namespace: istio-system
+ wait: true
+ release_values:
+ meshConfig:
+ rootNamespace: istio-config
+
+- name: Apply workaround for SDC case sensivity issue
+ kubernetes.core.k8s:
+ state: present
+ definition: "{{ lookup('file', 'envoyfilter-case.yml') | from_yaml }}"
+
+- name: Create Istio ingress gateway namespace
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Namespace
+ metadata:
+ name: istio-ingress
+ labels:
+ istio-injection: enabled
+
+- name: Deploy Istio ingress gateway chart
+ kubernetes.core.helm:
+ name: istio-ingress
+ chart_version: "{{ istio_version }}"
+ chart_ref: istio/gateway
+ release_namespace: istio-ingress
+ wait: true
diff --git a/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/main.yml b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/main.yml
new file mode 100644
index 000000000..32adc3310
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/main.yml
@@ -0,0 +1,19 @@
+---
+- name: Setup cert-manager
+ include_tasks: cert-manager.yml
+
+- name: Setup strimzi
+ include_tasks: strimzi.yml
+ when: strimzi_enabled
+
+- name: Setup MetalLB
+ include_tasks: metallb.yml
+ when: metallb_enabled
+
+- name: Setup Prometheus
+ include_tasks: prometheus.yml
+ when: prometheus_enabled
+
+- name: Setup Istio
+ include_tasks: istio.yml
+ when: istio_enabled
diff --git a/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/metallb.yml b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/metallb.yml
new file mode 100644
index 000000000..95547ec32
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/metallb.yml
@@ -0,0 +1,51 @@
+---
+- name: Add MetalLB Helm repository
+ kubernetes.core.helm_repository:
+ name: metallb
+ repo_url: https://metallb.github.io/metallb
+
+- name: Create MetalLB namespace
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Namespace
+ metadata:
+ name: metallb-system
+ labels:
+ pod-security.kubernetes.io/enforce: privileged
+ pod-security.kubernetes.io/audit: privileged
+ pod-security.kubernetes.io/warn: privileged
+- name: Deploy MetalLB charts
+ kubernetes.core.helm:
+ name: metallb
+ chart_version: "{{ metallb_version }}"
+ chart_ref: metallb/metallb
+ release_namespace: metallb-system
+ wait: true
+
+- name: Create MetalLB IP Address Pool Resource
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: metallb.io/v1beta1
+ kind: IPAddressPool
+ metadata:
+ name: onap-pool
+ namespace: metallb-system
+ spec:
+ addresses:
+ - "{{ metallb_addresses }}"
+ register: result
+ retries: 1
+ until: result['failed'] == false
+
+- name: Create MetalLB L2 Advertisement Resource
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: metallb.io/v1beta1
+ kind: L2Advertisement
+ metadata:
+ name: onap
+ namespace: metallb-system
diff --git a/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/prometheus.yml b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/prometheus.yml
new file mode 100644
index 000000000..e046cddb8
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/prometheus.yml
@@ -0,0 +1,13 @@
+---
+- name: Add prometheus Helm repository
+ kubernetes.core.helm_repository:
+ name: prometheus
+ repo_url: https://prometheus-community.github.io/helm-charts
+
+- name: Deploy Prometheus charts
+ kubernetes.core.helm:
+ name: prometheus
+ chart_version: "{{ prometheus_version }}"
+ chart_ref: prometheus/kube-prometheus-stack
+ release_namespace: prometheus
+ create_namespace: true
diff --git a/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/strimzi.yml b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/strimzi.yml
new file mode 100644
index 000000000..fd5828b19
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/deps/tasks/strimzi.yml
@@ -0,0 +1,15 @@
+---
+- name: Add Strimzi Helm repository
+ kubernetes.core.helm_repository:
+ name: strimzi
+ repo_url: https://strimzi.io/charts
+
+- name: Deploy Strimzi chart
+ kubernetes.core.helm:
+ name: strimzi-kafka-operator
+ chart_version: "{{ strimzi_version }}"
+ chart_ref: strimzi/strimzi-kafka-operator
+ release_namespace: strimzi-system
+ create_namespace: true
+ values:
+ watchAnyNamespace: true
diff --git a/deployment/noheat/cluster-rke/ansible/roles/oom/tasks/main.yml b/deployment/noheat/cluster-rke/ansible/roles/oom/tasks/main.yml
new file mode 100644
index 000000000..035fb01f5
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/oom/tasks/main.yml
@@ -0,0 +1,66 @@
+---
+- name: Build OOM charts
+ make:
+ chdir: "{{ oom_dir }}/kubernetes"
+ target: all
+ params:
+ SKIP_LINT: "TRUE"
+
+- name: Build ONAP charts
+ make:
+ chdir: "{{ oom_dir }}/kubernetes"
+ target: onap
+ params:
+ SKIP_LINT: "TRUE"
+
+- name: Create ONAP namespace
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Namespace
+ metadata:
+ name: onap
+ labels:
+ istio-injection: enabled
+ when: istio_enabled
+
+- name: Create ONAP namespace
+ kubernetes.core.k8s:
+ name: onap
+ api_version: v1
+ kind: Namespace
+ state: present
+ when: not istio_enabled
+
+- name: Get encryption key
+ command: cat "{{ oom_dir }}/kubernetes/so/resources/config/mso/encryption.key"
+ register: encryption_key
+ when: encryption_key is undefined
+- name: Clone integration project
+ git:
+ repo: "https://git.onap.org/integration"
+ dest: "{{ integration_dir }}"
+ version: "{{ onap_branch }}"
+- name: Compile encryption tool
+ command:
+ cmd: javac Crypto.java
+ chdir: "{{ integration_dir }}/deployment/heat/onap-rke/scripts"
+ creates: "{{ integration_dir }}/deployment/heat/onap-rke/scripts/Crypto.class"
+- name: Encrypt password
+ command:
+ cmd: java Crypto "{{ openstack_passwd }}" "{{ encryption_key.stdout }}"
+ chdir: "{{ integration_dir }}/deployment/heat/onap-rke/scripts"
+ register: encrypted_password
+ when: encrypted_password is undefined
+
+- name: Deploy sm-onap
+ command:
+ cmd: "helm deploy onap local/onap --namespace onap --set global.masterPassword=scrtPasswd -f {{ override_file }}"
+ environment:
+ OPENSTACK_USER_NAME: "{{ openstack_username }}"
+ OPENSTACK_REGION: "{{ openstack_region }}"
+ OPENSTACK_KEYSTONE_URL: "http://{{ hostvars['openstack0']['ansible_default_ipv4']['address'] }}:5000/3.0"
+ OPENSTACK_TENANT_NAME: "{{ openstack_tenant }}"
+ OPENSTACK_ENCTYPTED_PASSWORD: "{{ encrypted_password.stdout }}"
+ changed_when: false
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_docker/defaults/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_docker/defaults/main.yml
new file mode 100644
index 000000000..cafa274a1
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_docker/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+docker_version: "20.10.21"
+local_user: "ubuntu"
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_docker/handlers/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_docker/handlers/main.yml
new file mode 100644
index 000000000..3627303e6
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_docker/handlers/main.yml
@@ -0,0 +1,5 @@
+---
+- name: restart docker
+ service:
+ name: docker
+ state: restarted
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_docker/tasks/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_docker/tasks/main.yml
new file mode 100644
index 000000000..12e13f47b
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_docker/tasks/main.yml
@@ -0,0 +1,26 @@
+---
+- name: Setup Docker repo and packages
+ include_tasks: packages.yml
+
+- name: Add user to docker group
+ user:
+ name: "{{ local_user }}"
+ groups: docker
+ append: yes
+ when: local_user is defined
+
+- name: Make sure Docker is started and enabled
+ service:
+ name: docker
+ state: started
+ enabled: yes
+
+- name: Configure Docker
+ copy:
+ dest: /etc/docker/daemon.json
+ content: "{{ docker_config | to_nice_json }}"
+ mode: 0600
+ backup: true
+ when: docker_config is defined
+ notify:
+ - restart docker
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_docker/tasks/packages.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_docker/tasks/packages.yml
new file mode 100644
index 000000000..814dd285a
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_docker/tasks/packages.yml
@@ -0,0 +1,41 @@
+---
+- name: Install deps
+ apt:
+ name: "{{ item }}"
+ state: present
+ with_items:
+ - apt-transport-https
+ - ca-certificates
+ - curl
+ - software-properties-common
+
+- name: Add Docker repo key
+ apt_key:
+ url: "https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg"
+ state: present
+
+- name: Add Docker repo
+ apt_repository:
+ repo: "deb https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release | lower }} stable"
+ state: present
+ update_cache: yes
+
+- name: Find exact Docker version
+ shell: "set -o pipefail && apt-cache madison docker-ce | grep {{ docker_version }} | head -n 1 | cut -d ' ' -f 4"
+ args:
+ executable: "/bin/bash"
+ register: docker_pkg_version
+ changed_when: false
+
+- name: install Docker
+ apt:
+ name: "{{ item }}"
+ state: present
+ allow_downgrade: true
+ with_items:
+ - "docker-ce={{ docker_pkg_version.stdout }}"
+ - "docker-ce-cli={{ docker_pkg_version.stdout }}"
+
+- name: Lock docker version
+ command: apt-mark hold docker-ce docker-ce-cli
+ changed_when: false
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_docker/vars/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_docker/vars/main.yml
new file mode 100644
index 000000000..6879cca7e
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_docker/vars/main.yml
@@ -0,0 +1,8 @@
+---
+# docker_config will be converted to json and placed as a /etc/docker/daemon.json
+#docker_config:
+# insecure-registries:
+# - "192.168.1.1:5000"
+# - "192.168.1.2:5000"
+# registry-mirrors:
+# - "http://192.168.1.1:5000"
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_helm/defaults/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/defaults/main.yml
new file mode 100644
index 000000000..f0416f9df
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/defaults/main.yml
@@ -0,0 +1,7 @@
+---
+helm_version: "3.8.2"
+helm_cm_push_version: "0.10.3"
+chartmuseum_version: "0.15.0"
+chartmuseum_port: "8879"
+chartmuseum_dir: "{{ ansible_user_dir }}/helm3-storage"
+local_user: "{{ ansible_user_id }}"
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_helm/handlers/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/handlers/main.yml
new file mode 100644
index 000000000..0847b8182
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/handlers/main.yml
@@ -0,0 +1,5 @@
+---
+- name: Reload systemd
+ become: yes
+ systemd:
+ daemon-reload: yes
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/cm.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/cm.yml
new file mode 100644
index 000000000..71f43ad0a
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/cm.yml
@@ -0,0 +1,45 @@
+---
+- name: Check if chartmuseum is installed
+ stat:
+ path: /usr/local/bin/chartmuseum
+ register: cm_bin
+
+- name: Check if chartmuseum is installed
+ stat:
+ path: /tmp/get-chartmuseum
+ register: cm_install
+
+- name: Download chartmuseum install script
+ get_url:
+ url: "https://raw.githubusercontent.com/helm/chartmuseum/v{{ chartmuseum_version }}/scripts/get-chartmuseum"
+ dest: "/tmp/"
+ mode: '700'
+ when: not cm_install.stat.exists
+
+- name: Install chartmuseum
+ become: yes
+ command:
+ cmd: "./get-chartmuseum -v v{{ chartmuseum_version }}"
+ chdir: "/tmp/"
+ when: not cm_bin.stat.exists
+
+- name: Create chartmuseum local storage
+ file:
+ name: "{{ chartmuseum_dir }}"
+ state: directory
+ mode: '0755'
+
+- name: Install chartmuseum service file
+ become: yes
+ template:
+ src: "chartmuseum.service.j2"
+ dest: "/etc/systemd/system/chartmuseum.service"
+ mode: '0444'
+ notify: Reload systemd
+
+- name: Start and enable chartmuseum
+ become: yes
+ service:
+ name: "chartmuseum"
+ state: started
+ enabled: yes
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/helm.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/helm.yml
new file mode 100644
index 000000000..88ba29f64
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/helm.yml
@@ -0,0 +1,35 @@
+---
+- name: Download helm
+ get_url:
+ url: "https://get.helm.sh/helm-v{{ helm_version }}-linux-amd64.tar.gz"
+ dest: "/tmp"
+
+- name: Unarchive helm
+ unarchive:
+ src: "/tmp/helm-v{{ helm_version }}-linux-amd64.tar.gz"
+ dest: "/tmp/"
+ remote_src: yes
+
+- name: Copy helm binary to $PATH
+ become: yes
+ copy:
+ src: "/tmp/linux-amd64/helm"
+ dest: "/usr/local/bin/"
+ remote_src: yes
+ mode: '0555'
+
+- name: Install Helm Push plugin
+ kubernetes.core.helm_plugin:
+ plugin_path: "https://github.com/chartmuseum/helm-push.git"
+ plugin_version: "{{ helm_cm_push_version }}"
+ state: present
+
+- name: Install Helm OOM Deploy plugin
+ kubernetes.core.helm_plugin:
+ plugin_path: "{{ oom_dir }}/kubernetes/helm/plugins/deploy"
+ state: present
+
+- name: Install Helm OOM Undeploy plugin
+ kubernetes.core.helm_plugin:
+ plugin_path: "{{ oom_dir }}/kubernetes/helm/plugins/undeploy"
+ state: present
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/main.yml
new file mode 100644
index 000000000..94abf6ea8
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/tasks/main.yml
@@ -0,0 +1,12 @@
+---
+- name: Setup helm
+ include_tasks: helm.yml
+
+- name: Setup chartmuseum
+ include_tasks: cm.yml
+
+- name: Add local Helm repository
+ kubernetes.core.helm_repository:
+ name: "local"
+ repo_url: "http://127.0.0.1:{{ chartmuseum_port }}"
+ state: present
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_helm/templates/chartmuseum.service.j2 b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/templates/chartmuseum.service.j2
new file mode 100644
index 000000000..78d7967f9
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_helm/templates/chartmuseum.service.j2
@@ -0,0 +1,13 @@
+[Unit]
+Description=chartmuseum
+Requires=network-online.target
+After=network-online.target
+
+[Service]
+ExecStart=/usr/local/bin/chartmuseum --port "{{ chartmuseum_port }}" --storage local --storage-local-rootdir "{{ chartmuseum_dir }}"
+ExecStop=/usr/local/bin/chartmuseum step-down
+User={{ local_user }}
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/defaults/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/defaults/main.yml
new file mode 100644
index 000000000..021aae0ee
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+rke_version: "1.3.15"
+rke_k8s_version: "v{{ k8s_version }}-rancher1-1"
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/kubectl.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/kubectl.yml
new file mode 100644
index 000000000..f9912ebdf
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/kubectl.yml
@@ -0,0 +1,13 @@
+---
+- name: Check if kubectl is available
+ stat:
+ path: "/usr/local/bin/kubectl"
+ register: kubectl_bin
+
+- name: Get kubectl
+ become: yes
+ get_url:
+ url: "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubectl"
+ dest: "/usr/local/bin/"
+ mode: '0555'
+ when: not kubectl_bin.stat.exists
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/main.yml
new file mode 100644
index 000000000..7d3ba0096
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/main.yml
@@ -0,0 +1,16 @@
+---
+- name: Deploy kubernetes with RKE
+ include_tasks: rke.yml
+
+- name: Create k8s directory
+ file:
+ name: "{{ ansible_user_dir }}/.kube"
+ state: directory
+ mode: '0700'
+
+- name: Set k8s config
+ command: "mv {{ ansible_user_dir }}/kube_config_cluster.yml {{ ansible_user_dir }}/.kube/config"
+ when: rke_run and rke_run.rc == 0
+
+- name: Install kubectl
+ include_tasks: kubectl.yml
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/rke.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/rke.yml
new file mode 100644
index 000000000..b253e711d
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/tasks/rke.yml
@@ -0,0 +1,25 @@
+---
+- name: Check if RKE is available
+ stat:
+ path: "{{ ansible_user_dir }}/rke"
+ register: rke_bin
+
+- name: Download RKE
+ get_url:
+ url: "https://github.com/rancher/rke/releases/download/v{{ rke_version }}/rke_linux-amd64"
+ dest: "{{ ansible_user_dir }}/rke"
+ mode: '0700'
+ when: not rke_bin.stat.exists
+
+- name: Prepare RKE configuration
+ template:
+ src: "cluster.yml.j2"
+ dest: "{{ ansible_user_dir }}/cluster.yml"
+ mode: '0400'
+
+- name: Run RKE
+ command:
+ cmd: "./rke up"
+ chdir: "{{ ansible_user_dir }}"
+ creates: "{{ ansible_user_dir }}/kube_config_cluster.yml"
+ register: rke_run
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/templates/cluster.yml.j2 b/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/templates/cluster.yml.j2
new file mode 100644
index 000000000..3b83fd466
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_k8s/templates/cluster.yml.j2
@@ -0,0 +1,52 @@
+# An example of an HA Kubernetes cluster for ONAP
+nodes:
+{% for host in (groups['control'] | list() ) %}
+- address: "{{ hostvars[host]['ansible_host'] }}"
+ port: "22"
+ role:
+ - controlplane
+ - etcd
+ hostname_override: "onap-control-{{ loop.index }}"
+ user: {{ ansible_user_id }}
+ ssh_key_path: "{{ ansible_ssh_private_key_file }}"
+{% endfor %}
+{% for host in (groups['workers'] | list()) %}
+- address: "{{ hostvars[host]['ansible_host'] }}"
+ port: "22"
+ role:
+ - worker
+ hostname_override: "onap-k8s-{{ loop.index }}"
+ user: {{ ansible_user_id }}
+ ssh_key_path: "{{ ansible_ssh_private_key_file }}"
+{% endfor %}
+services:
+ kube-api:
+ service_cluster_ip_range: 10.43.0.0/16
+ pod_security_policy: false
+ always_pull_images: false
+ kube-controller:
+ cluster_cidr: 10.42.0.0/16
+ service_cluster_ip_range: 10.43.0.0/16
+ kubelet:
+ cluster_domain: cluster.local
+ cluster_dns_server: 10.43.0.10
+ fail_swap_on: false
+network:
+ plugin: canal
+authentication:
+ strategy: x509
+ssh_key_path: "{{ ansible_ssh_private_key_file }}"
+ssh_agent_auth: false
+authorization:
+ mode: rbac
+ignore_docker_version: false
+kubernetes_version: "{{ rke_k8s_version }}"
+private_registries:
+- url: nexus3.onap.org:10001
+ user: docker
+ password: docker
+ is_default: true
+cluster_name: "onap"
+restore:
+ restore: false
+ snapshot_name: ""
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_nfs/defaults/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_nfs/defaults/main.yml
new file mode 100644
index 000000000..da66bfb38
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_nfs/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+nfs_mountpoint: "/dockerdata-nfs"
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_nfs/tasks/main.yml b/deployment/noheat/cluster-rke/ansible/roles/setup_nfs/tasks/main.yml
new file mode 100644
index 000000000..2d8d0b006
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_nfs/tasks/main.yml
@@ -0,0 +1,59 @@
+- name: Install NFS common
+ apt:
+ name: nfs-common
+ state: present
+ when: nfs_role is defined
+
+- name: Install NFS server
+ apt:
+ name: nfs-kernel-server
+ state: present
+ when: nfs_role is defined and nfs_role == "server"
+
+- name: Umount
+ ansible.posix.mount:
+ path: "{{ nfs_mountpoint }}"
+ state: unmounted
+ ignore_errors: yes
+
+- name: Remove leftovers
+ file:
+ path: "{{ nfs_mountpoint }}"
+ state: absent
+ when: nfs_role is defined
+
+- name: Create dockerdata directory
+ file:
+ path: "{{ nfs_mountpoint }}"
+ state: directory
+ mode: '0777'
+ owner: nobody
+ group: nogroup
+ when: nfs_role is defined
+
+- name: Configure NFS server
+ template:
+ src: "exports.j2"
+ dest: "/etc/exports"
+ owner: root
+ group: root
+ mode: '0644'
+ when: nfs_role is defined and nfs_role == "server"
+
+- name: Restart NFS server
+ service:
+ name: nfs-kernel-server
+ state: restarted
+ enabled: yes
+ when: nfs_role is defined and nfs_role == "server"
+
+- name: Configure NFS clients
+ mount:
+ path: "{{ nfs_mountpoint }}"
+ src: "{{ hostvars[groups['nfs'][0]]['ansible_default_ipv4']['address'] }}:{{ nfs_mountpoint }}"
+ fstype: nfs
+ opts: auto,nofail,noatime,nolock,intr,tcp,actimeo=1800
+ dump: 0
+ passno: 0
+ state: mounted
+ when: nfs_role is defined and nfs_role == "client"
diff --git a/deployment/noheat/cluster-rke/ansible/roles/setup_nfs/templates/exports.j2 b/deployment/noheat/cluster-rke/ansible/roles/setup_nfs/templates/exports.j2
new file mode 100644
index 000000000..6a5a825c6
--- /dev/null
+++ b/deployment/noheat/cluster-rke/ansible/roles/setup_nfs/templates/exports.j2
@@ -0,0 +1 @@
+{{ nfs_mountpoint }} {% for host in (groups['control'] | union(groups['workers'])) %} {{ hostvars[host]['ansible_default_ipv4']['address'] }}(rw,sync,no_root_squash,no_subtree_check){% endfor %}
diff --git a/deployment/noheat/common-vars.yml b/deployment/noheat/common-vars.yml
new file mode 100644
index 000000000..f7265f4a6
--- /dev/null
+++ b/deployment/noheat/common-vars.yml
@@ -0,0 +1,2 @@
+---
+k8s_version: "1.23.10"
diff --git a/deployment/noheat/deploy-all.yml b/deployment/noheat/deploy-all.yml
new file mode 100644
index 000000000..2ea069525
--- /dev/null
+++ b/deployment/noheat/deploy-all.yml
@@ -0,0 +1,9 @@
+---
+- name: Create infastructure
+ import_playbook: infra-openstack/ansible/create.yml
+- hosts: operator0
+ tasks:
+ - name: Deploy Devstack
+ ansible.builtin.command: ansible-playbook -i {{ ansible_user_dir }}/inventory.ini {{ ansible_user_dir }}/devstack/ansible/create.yml
+ - name: Deploy k8s & ONAP
+ ansible.builtin.command: ansible-playbook -i {{ ansible_user_dir }}/inventory.ini {{ ansible_user_dir }}/deploy/cluster-rke/ansible/create.yml
diff --git a/deployment/noheat/devstack/ansible/create.yml b/deployment/noheat/devstack/ansible/create.yml
new file mode 100644
index 000000000..f11fe1194
--- /dev/null
+++ b/deployment/noheat/devstack/ansible/create.yml
@@ -0,0 +1,43 @@
+---
+- name: Deploy Devstack
+ hosts: "openstack*"
+ tasks:
+ - name: Update Devstack hosts
+ become: true
+ ansible.builtin.apt:
+ upgrade: full
+ update_cache: true
+ autoremove: true
+ autoclean: true
+
+ - name: Reboot OS
+ become: true
+ ansible.builtin.reboot:
+
+ - name: Clone Devstack
+ ansible.builtin.git:
+ repo: "https://opendev.org/openstack/devstack"
+ dest: "{{ devstack_dir }}"
+ version: "{{ devstack_version }}"
+
+ - name: Copy local.conf
+ ansible.builtin.template:
+ src: "local.conf.j2"
+ dest: "{{ devstack_dir }}/local.conf"
+ mode: '0600'
+
+ - name: Run devstack setup script
+ ansible.builtin.command:
+ chdir: "{{ devstack_dir }}"
+ cmd: "./stack.sh"
+ creates: /opt/stack
+
+ - name: Run devstack setup script
+ ansible.builtin.file:
+ path: "{{ devstack_dir }}"
+ state: absent
+
+ handlers:
+ - name: Reboot OS
+ become: true
+ ansible.builtin.reboot:
diff --git a/deployment/noheat/devstack/ansible/group_vars/all/all.yml b/deployment/noheat/devstack/ansible/group_vars/all/all.yml
new file mode 100644
index 000000000..b2d63c672
--- /dev/null
+++ b/deployment/noheat/devstack/ansible/group_vars/all/all.yml
@@ -0,0 +1,3 @@
+---
+devstack_dir: "{{ ansible_user_dir }}/devstack"
+devstack_version: "stable/yoga"
diff --git a/deployment/noheat/devstack/ansible/templates/local.conf.j2 b/deployment/noheat/devstack/ansible/templates/local.conf.j2
new file mode 100644
index 000000000..0bfa3bba9
--- /dev/null
+++ b/deployment/noheat/devstack/ansible/templates/local.conf.j2
@@ -0,0 +1,5 @@
+[[local|localrc]]
+ADMIN_PASSWORD="{{ openstack_passwd }}"
+DATABASE_PASSWORD=$ADMIN_PASSWORD
+RABBIT_PASSWORD=$ADMIN_PASSWORD
+SERVICE_PASSWORD=$ADMIN_PASSWORD
diff --git a/deployment/noheat/infra-openstack/HACKING.rst b/deployment/noheat/infra-openstack/HACKING.rst
new file mode 100644
index 000000000..dcdc2062e
--- /dev/null
+++ b/deployment/noheat/infra-openstack/HACKING.rst
@@ -0,0 +1,30 @@
+=========================
+ Development environment
+=========================
+
+This environment focuses on interactions with OpenStack (here: DevStack) instance. Changes can be
+made from host machine but additional guest ("operator") is provided for developers' convenience.
+
+Environment on "operator" machine is already set up and can be accessed by:
+
+.. code-block:: shell
+
+ $ vagrant ssh operator
+
+Provided ``clouds.yaml`` file differs slightly from the one that can be obtained with following
+steps:
+
+#. Open OpenStack dashboard (http://localhost:8080 forwarded from "devstack" machine)
+#. Navigate to ``Project``, then ``API Access`` on the left panel
+#. Select ``Download OpenStack RC File``, then ``OpenStack clouds.yaml File`` on the right side
+
+Summary of changes:
+
+- Added password from ``local.conf`` file (used in DevStack instance setup)
+- Removed ``project_id`` which might change on a new DevStack instance
+- Replaced ``auth_url`` based on machine's dynamic IP with the static private address
+- Added ``project_domain_name`` needed to run Ansible playbooks
+
+Installed Python package ``python-openstackclient`` includes key package ``openstacksdk`` as
+a dependency and provides additional CLI tools. Tool ``pip`` for Python 3 was used for installing
+these packages.
diff --git a/deployment/noheat/infra-openstack/README.rst b/deployment/noheat/infra-openstack/README.rst
new file mode 100644
index 000000000..c48dfa7f2
--- /dev/null
+++ b/deployment/noheat/infra-openstack/README.rst
@@ -0,0 +1,34 @@
+==================================================
+ Cloud infrastructure: OpenStack virtual machines
+==================================================
+
+Ansible roles and sample playbooks for creating virtual machines on OpenStack without Heat support.
+
+They will be used to create virtual machines hosting Service Mesh lab cluster.
+
+Prerequisites
+-------------
+
+Infrastructure
+~~~~~~~~~~~~~~
+
+- OpenStack cloud (no Heat support required)
+
+Configuration
+~~~~~~~~~~~~~
+
+- OpenStack ``clouds.yaml`` file
+
+Dependencies
+~~~~~~~~~~~~
+
+Tested on Python 3.8.10. Required Python dependencies can be found in ``../requirements.txt``.
+Required Ansible roles and collections can be found in ``../requirements.yml``
+
+.. _openstacksdk: https://pypi.org/project/openstacksdk
+
+
+Expected output
+---------------
+
+Ephemeral (disposable) OpenStack virtual machines for a Kubernetes cluster.
diff --git a/deployment/noheat/infra-openstack/ansible/create.yml b/deployment/noheat/infra-openstack/ansible/create.yml
new file mode 100644
index 000000000..73830663c
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/create.yml
@@ -0,0 +1,136 @@
+---
+- name: Prepare infrastructure and create operation instances
+ hosts: localhost
+ connection: local
+ gather_facts: False
+ roles:
+ - create_network
+ - create_securitygroup
+ - create_keypair
+ - role: create_hosts
+ hosts: "{{ operation.hosts }}"
+ operator_key: "dummy"
+ tasks:
+ - name: Get operator Openstack info
+ openstack.cloud.server_info:
+ server: "operator0"
+ register: operator_info
+ - name: Create directory for artifacts
+ ansible.builtin.file:
+ name: "artifacts"
+ state: directory
+ mode: '0755'
+ - name: Save operator access information
+ ansible.builtin.copy:
+ content: "{{ operator_info['openstack_servers'][0]['public_v4'] }},{{ image['user'] }},~/.ssh/{{ keypair['key']['name'] }}"
+ dest: "artifacts/operator.csv"
+ mode: "0644"
+- name: Create cluster operator access keypair
+ hosts: "operator0"
+ gather_facts: False
+ tasks:
+ - name: Wait for system to become reachable
+ wait_for_connection:
+ - name: Generate an OpenSSH keypair with the default values (4096 bits, rsa)
+ community.crypto.openssh_keypair:
+ path: "~/.ssh/{{ keypair.name }}"
+ register: key
+ - name: Add operator0 public key to it's authorized keys
+ ansible.posix.authorized_key:
+ key: "{{ key['public_key'] }}"
+ state: present
+ user: "{{ ansible_user }}"
+- name: Create OpenStack instances
+ hosts: localhost
+ connection: local
+ gather_facts: False
+ roles:
+ - role: create_hosts
+ hosts: "{{ openstack.hosts }}"
+ operator_key: "{{ hostvars['operator0']['key']['public_key'] }}"
+- name: Create cluster instances
+ hosts: localhost
+ connection: local
+ gather_facts: False
+ roles:
+ - role: create_hosts
+ hosts: "{{ cluster.hosts }}"
+ operator_key: "{{ hostvars['operator0']['key']['public_key'] }}"
+- name: Create cluster operator access information
+ hosts: "operator0"
+ vars_files:
+ - ../../common-vars.yml
+ tasks:
+ - name: Add cluster hostnames to /etc/hosts file
+ lineinfile:
+ path: /etc/hosts
+ line: "{{ item.value + ' ' + item.key }}"
+ become: yes
+ loop: "{{ lookup('dict', hostvars['localhost']['hosts_dict']) }}"
+ - name: Create inventory for in-cluster deployment stage
+ template:
+ src: templates/inventory.ini.j2
+ dest: "{{ operation.inventory }}"
+ vars:
+ hosts: "{{ lookup('dict', hostvars['localhost']['hosts_dict']) }}"
+ - name: Push in-cluster deployment stage description to the next Ansible control host
+ copy:
+ src: ../../cluster-rke
+ dest: ~/deploy
+ - name: Push Devstack deployment stage description to the next Ansible control host
+ copy:
+ src: ../../devstack
+ dest: ~/
+ - name: Push common variables to the next Ansible control host
+ copy:
+ src: ../../common-vars.yml
+ dest: ~/
+ - name: Push Devstack vars to the next Ansible control host (for Devstack stage)
+ template:
+ src: "templates/openstack.yml.j2"
+ dest: ~/devstack/ansible/group_vars/all/openstack.yml
+ mode: '0644'
+ - name: Push Devstack vars to the next Ansible control host (for cluster-rke stage)
+ template:
+ src: "templates/openstack.yml.j2"
+ dest: ~/deploy/cluster-rke/ansible/group_vars/all/openstack.yml
+ mode: '0644'
+ - name: Create Devstack config directory
+ file:
+ path: ~/.config/openstack/
+ state: directory
+ mode: '0755'
+ - name: Generate Devstack clouds.yml file
+ template:
+ src: "templates/clouds.yaml.j2"
+ dest: ~/.config/openstack/clouds.yml
+ mode: '0644'
+ - block:
+ - name: Install python dependencies
+ become: yes
+ apt:
+ name:
+ - python3-pip
+ - python3-setuptools
+ - default-jdk-headless
+ state: present
+ update_cache: true
+ - name: Install community.kubernetes.k8s Ansible collection dependencies
+ pip:
+ name:
+ - ansible-core==2.13.5
+ - openshift==0.13.1
+ - pyyaml==6.0
+ # Major version of Python k8s libraty matches minor version of k8s.
+ - kubernetes~={{ k8s_version | regex_search("[^^.][0-9]+[^$]") ~ "0" }}
+ executable: pip3
+ become: yes
+ - name: Copy ansible-galaxy requirements file
+ copy:
+ src: operator-requirements.yml
+ dest: ~/requirements.yml
+ mode: '0444'
+ - name: Install ansible-galaxy collections
+ community.general.ansible_galaxy_install:
+ requirements_file: ~/requirements.yml
+ type: both
diff --git a/deployment/noheat/infra-openstack/ansible/destroy.yml b/deployment/noheat/infra-openstack/ansible/destroy.yml
new file mode 100644
index 000000000..1564e3088
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/destroy.yml
@@ -0,0 +1,15 @@
+---
+- name: Destroy infrastructure
+ hosts: localhost
+ connection: local
+ gather_facts: False
+ roles:
+ - role: destroy_hosts
+ hosts: "{{ cluster.hosts }}"
+ - role: destroy_hosts
+ hosts: "{{ operation.hosts }}"
+ - role: destroy_hosts
+ hosts: "{{ openstack.hosts }}"
+ - destroy_keypair
+ - destroy_network
+ - destroy_securitygroup
diff --git a/deployment/noheat/infra-openstack/ansible/group_vars/all.yml.sample b/deployment/noheat/infra-openstack/ansible/group_vars/all.yml.sample
new file mode 100644
index 000000000..541e15279
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/group_vars/all.yml.sample
@@ -0,0 +1,63 @@
+---
+network:
+ name: &network_name "onap_ci_lab"
+ cidr: "192.168.1.0/24"
+ dns_servers:
+ # - x.x.x.x
+ # - y.y.y.y
+
+keypair:
+ name: &keypair_name "onap_ci_lab"
+
+securitygroup:
+ name: &securitygroup_name "onap_ci_lab"
+ remote_ip_prefix:
+ - "172.24.4.0/24"
+ - "192.168.1.0/24"
+ local_ip_prefix:
+ - "192.168.1.0/24"
+
+image:
+ name: &image_name "Ubuntu_20.04"
+ user: "ubuntu"
+
+openstack:
+ name: "vnf0"
+ inventory: "~/inventory.ini"
+ hosts:
+ - name: "openstack0"
+ image: *image_name
+ flavor: "m1.large"
+ keypair: *keypair_name
+ network: *network_name
+ securitygroup: *securitygroup_name
+ boot_from_volume: true
+ terminate_volume: true
+ volume_size: 100
+
+operation:
+ name: "operation0"
+ inventory: "~/inventory.ini"
+ hosts:
+ - name: "operator0"
+ image: *image_name
+ flavor: "m1.tiny"
+ keypair: *keypair_name
+ network: *network_name
+ securitygroup: *securitygroup_name
+ boot_from_volume: true
+ terminate_volume: true
+ volume_size: 5
+
+cluster:
+ name: "cluster0"
+ hosts:
+ - name: "worker0"
+ image: *image_name
+ flavor: "m1.tiny"
+ keypair: *keypair_name
+ network: *network_name
+ securitygroup: *securitygroup_name
+ boot_from_volume: true
+ terminate_volume: true
+ volume_size: 5
diff --git a/deployment/noheat/infra-openstack/ansible/group_vars/all.yml.sm-onap b/deployment/noheat/infra-openstack/ansible/group_vars/all.yml.sm-onap
new file mode 100644
index 000000000..9223ea591
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/group_vars/all.yml.sm-onap
@@ -0,0 +1,86 @@
+---
+network:
+ name: &network_name "onap_ci_lab"
+ cidr: "192.168.1.0/24"
+
+keypair:
+ name: &keypair_name "onap_ci_lab"
+
+securitygroup:
+ name: &securitygroup_name "onap_ci_lab"
+ remote_ip_prefix:
+ - "0.0.0.0/0"
+ local_ip_prefix:
+ - "192.168.1.0/24"
+
+image:
+ name: &image_name "Ubuntu_20.04"
+ user: "ubuntu"
+
+openstack:
+ name: "vnf0"
+ inventory: "~/inventory.ini"
+ hosts:
+ - name: "openstack0"
+ image: *image_name
+ flavor: "m1.xlarge"
+ keypair: *keypair_name
+ network: *network_name
+ auto_ip: false
+ securitygroup: *securitygroup_name
+ volume_size: 140
+
+operation:
+ name: "operation0"
+ inventory: "~/inventory.ini"
+ hosts:
+ - name: "operator0"
+ image: *image_name
+ flavor: "m1.xlarge"
+ keypair: *keypair_name
+ network: *network_name
+ securitygroup: *securitygroup_name
+ volume_size: 20
+
+cluster:
+ name: "cluster0"
+ hosts:
+ - name: "control0"
+ image: *image_name
+ flavor: "m1.xlarge"
+ keypair: *keypair_name
+ network: *network_name
+ auto_ip: false
+ securitygroup: *securitygroup_name
+ volume_size: 50
+ - name: "worker0a"
+ image: *image_name
+ flavor: "m1.2xlarge"
+ keypair: *keypair_name
+ network: *network_name
+ auto_ip: false
+ securitygroup: *securitygroup_name
+ volume_size: 80
+ - name: "worker0b"
+ image: *image_name
+ flavor: "m1.2xlarge"
+ keypair: *keypair_name
+ network: *network_name
+ auto_ip: false
+ securitygroup: *securitygroup_name
+ volume_size: 80
+ - name: "worker0c"
+ image: *image_name
+ flavor: "m1.2xlarge"
+ keypair: *keypair_name
+ network: *network_name
+ auto_ip: false
+ securitygroup: *securitygroup_name
+ volume_size: 80
+ - name: "nfs0"
+ image: *image_name
+ flavor: "m1.large"
+ keypair: *keypair_name
+ network: *network_name
+ securitygroup: *securitygroup_name
+ volume_size: 150
diff --git a/deployment/noheat/infra-openstack/ansible/group_vars/all/all.yml b/deployment/noheat/infra-openstack/ansible/group_vars/all/all.yml
new file mode 120000
index 000000000..854839817
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/group_vars/all/all.yml
@@ -0,0 +1 @@
+../all.yml.sample \ No newline at end of file
diff --git a/deployment/noheat/infra-openstack/ansible/group_vars/all/openstack.yml b/deployment/noheat/infra-openstack/ansible/group_vars/all/openstack.yml
new file mode 100644
index 000000000..63ed1b081
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/group_vars/all/openstack.yml
@@ -0,0 +1,6 @@
+---
+openstack_username: "admin"
+openstack_domain: "Default"
+openstack_passwd: "secret"
+openstack_region: "RegionOne"
+openstack_tenant: "admin"
diff --git a/deployment/noheat/infra-openstack/ansible/operator-requirements.yml b/deployment/noheat/infra-openstack/ansible/operator-requirements.yml
new file mode 100644
index 000000000..0532eb473
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/operator-requirements.yml
@@ -0,0 +1,8 @@
+---
+collections:
+ - name: ansible.posix
+ version: 1.4.0
+ - name: kubernetes.core
+ version: 2.3.2
+ - name: community.general
+ version: 5.8.0
diff --git a/deployment/noheat/infra-openstack/ansible/roles/create_hosts/tasks/create_host.yml b/deployment/noheat/infra-openstack/ansible/roles/create_hosts/tasks/create_host.yml
new file mode 100644
index 000000000..8fa4d0709
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/create_hosts/tasks/create_host.yml
@@ -0,0 +1,33 @@
+---
+- name: Create host
+ os_server:
+ state: present
+ name: "{{ host.name }}"
+ image: "{{ host.image }}"
+ flavor: "{{ host.flavor }}"
+ key_name: "{{ host.keypair }}"
+ network: "{{ host.network }}"
+ security_groups:
+ - "{{ host.securitygroup }}"
+ auto_ip: "{{ host.auto_ip | default(true) }}"
+ boot_from_volume: "{{ host.boot_from_volume | default(true) }}"
+ terminate_volume: "{{ host.terminate_volume | default(true) }}"
+ volume_size: "{{ host.volume_size | default(10) }}"
+ userdata: |
+ #cloud-config
+ ssh_authorized_keys:
+ - "{{ operator_key }}"
+ register: new_host
+
+- name: Add host to inventory
+ add_host:
+ hostname: "{{ new_host.server.name }}"
+ groups: "{{ cluster.name }}"
+ ansible_ssh_host: "{{ new_host.server.public_v4 }}"
+ ansible_ssh_user: "{{ image.user }}"
+ ansible_ssh_extra_args: "-o StrictHostKeyChecking=no"
+ ansible_ssh_private_key_file: "~/.ssh/{{ keypair.key.name }}"
+
+- name: Add host to hosts dict
+ set_fact:
+ hosts_dict: "{{ hosts_dict|default({}) | combine( {new_host.server.name: new_host.server.private_v4} ) }}"
diff --git a/deployment/noheat/infra-openstack/ansible/roles/create_hosts/tasks/main.yml b/deployment/noheat/infra-openstack/ansible/roles/create_hosts/tasks/main.yml
new file mode 100644
index 000000000..933b2f526
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/create_hosts/tasks/main.yml
@@ -0,0 +1,5 @@
+---
+- include_tasks: create_host.yml
+ loop: "{{ hosts }}"
+ loop_control:
+ loop_var: host
diff --git a/deployment/noheat/infra-openstack/ansible/roles/create_keypair/tasks/main.yml b/deployment/noheat/infra-openstack/ansible/roles/create_keypair/tasks/main.yml
new file mode 100644
index 000000000..8a7c72092
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/create_keypair/tasks/main.yml
@@ -0,0 +1,25 @@
+- name: Create keypair
+ os_keypair:
+ state: present
+ name: "{{ keypair.name }}"
+ register: keypair
+
+- name: Create local public key
+ copy:
+ content: "{{ keypair.key.public_key }}"
+ dest: "~/.ssh/{{ keypair.key.name }}.pub"
+ mode: 0600
+ delegate_to: localhost
+
+- name: Check if local private key exists
+ stat:
+ path: "~/.ssh/{{ keypair.key.name }}"
+ register: local_private_key
+
+- name: Create local private key
+ copy:
+ content: "{{ keypair.key.private_key }}"
+ dest: "~/.ssh/{{ keypair.key.name }}"
+ mode: 0600
+ delegate_to: localhost
+ when: not local_private_key.stat.exists
diff --git a/deployment/noheat/infra-openstack/ansible/roles/create_network/tasks/create_network.yml b/deployment/noheat/infra-openstack/ansible/roles/create_network/tasks/create_network.yml
new file mode 100644
index 000000000..3e22ee6ce
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/create_network/tasks/create_network.yml
@@ -0,0 +1,28 @@
+---
+- name: "Create {{ net.name }} network"
+ os_network:
+ name: "{{ net.name }}"
+ state: present
+
+- name: Set nameservers list fact
+ set_fact:
+ dns_ips: "{{ network.dns_servers | list }}"
+ when: network.dns_servers[0] is defined
+
+- name: "Create {{ net.name }} subnet"
+ os_subnet:
+ name: "{{ net.name }}_subnet"
+ network_name: "{{ net.name }}"
+ cidr: "{{ net.cidr }}"
+ dns_nameservers: "{{ dns_ips if dns_ips is defined else omit }}"
+ allocation_pool_start: '{{ net.allocation_pool_start | default("") }}'
+ allocation_pool_end: '{{ net.allocation_pool_end | default ("") }}'
+ state: present
+
+- name: "Create {{ net.name }} router"
+ os_router:
+ name: "{{ net.name }}_router"
+ network: public
+ interfaces:
+ - "{{ net.name }}_subnet"
+ state: present
diff --git a/deployment/noheat/infra-openstack/ansible/roles/create_network/tasks/main.yml b/deployment/noheat/infra-openstack/ansible/roles/create_network/tasks/main.yml
new file mode 100644
index 000000000..cce6f790b
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/create_network/tasks/main.yml
@@ -0,0 +1,6 @@
+---
+- include_tasks: create_network.yml
+ loop:
+ - "{{ network }}"
+ loop_control:
+ loop_var: net
diff --git a/deployment/noheat/infra-openstack/ansible/roles/create_securitygroup/tasks/create_securitygroup.yml b/deployment/noheat/infra-openstack/ansible/roles/create_securitygroup/tasks/create_securitygroup.yml
new file mode 100644
index 000000000..b9a3e2973
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/create_securitygroup/tasks/create_securitygroup.yml
@@ -0,0 +1,23 @@
+---
+- name: "Create {{ secgrp.name }} security group"
+ os_security_group:
+ state: present
+ name: "{{ secgrp.name }}"
+
+- name: "Create {{ secgrp.name }} security group rule for ping"
+ os_security_group_rule:
+ security_group: "{{ secgrp.name }}"
+ protocol: icmp
+ remote_ip_prefix: "{{ item }}"
+ loop: "{{ secgrp.remote_ip_prefix }}"
+
+- name: "Create {{ secgrp.name }} security group rule for all TCP"
+ os_security_group_rule:
+ security_group: "{{ secgrp.name }}"
+ protocol: tcp
+ remote_ip_prefix: "0.0.0.0/0"
+
+- name: "Create {{ secgrp.name }} security group rule for all UDP"
+ os_security_group_rule:
+ security_group: "{{ secgrp.name }}"
+ protocol: udp
diff --git a/deployment/noheat/infra-openstack/ansible/roles/create_securitygroup/tasks/main.yml b/deployment/noheat/infra-openstack/ansible/roles/create_securitygroup/tasks/main.yml
new file mode 100644
index 000000000..872988032
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/create_securitygroup/tasks/main.yml
@@ -0,0 +1,6 @@
+---
+- include_tasks: create_securitygroup.yml
+ loop:
+ - "{{ securitygroup }}"
+ loop_control:
+ loop_var: secgrp
diff --git a/deployment/noheat/infra-openstack/ansible/roles/destroy_hosts/tasks/destroy_host.yml b/deployment/noheat/infra-openstack/ansible/roles/destroy_hosts/tasks/destroy_host.yml
new file mode 100644
index 000000000..e9cedce7a
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/destroy_hosts/tasks/destroy_host.yml
@@ -0,0 +1,5 @@
+---
+- name: Destroy host
+ os_server:
+ name: "{{ host.name }}"
+ state: absent
diff --git a/deployment/noheat/infra-openstack/ansible/roles/destroy_hosts/tasks/main.yml b/deployment/noheat/infra-openstack/ansible/roles/destroy_hosts/tasks/main.yml
new file mode 100644
index 000000000..1dd5c7224
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/destroy_hosts/tasks/main.yml
@@ -0,0 +1,5 @@
+---
+- include_tasks: destroy_host.yml
+ loop: "{{ hosts }}"
+ loop_control:
+ loop_var: host
diff --git a/deployment/noheat/infra-openstack/ansible/roles/destroy_keypair/tasks/main.yml b/deployment/noheat/infra-openstack/ansible/roles/destroy_keypair/tasks/main.yml
new file mode 100644
index 000000000..6025b82b3
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/destroy_keypair/tasks/main.yml
@@ -0,0 +1,12 @@
+- name: Destroy keypair
+ os_keypair:
+ state: absent
+ name: "{{ keypair.name }}"
+
+- name: Destroy local keypair
+ file:
+ state: absent
+ path: "{{ item }}"
+ loop:
+ - "~/.ssh/{{ keypair.name }}.pub"
+ - "~/.ssh/{{ keypair.name }}"
diff --git a/deployment/noheat/infra-openstack/ansible/roles/destroy_network/tasks/destroy_network.yml b/deployment/noheat/infra-openstack/ansible/roles/destroy_network/tasks/destroy_network.yml
new file mode 100644
index 000000000..8f97d9507
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/destroy_network/tasks/destroy_network.yml
@@ -0,0 +1,10 @@
+---
+- name: "Destroy {{ net.name }} router"
+ os_router:
+ name: "{{ net.name }}_router"
+ state: absent
+
+- name: "Destroy {{ net.name }} network and its subnets"
+ os_network:
+ name: "{{ net.name }}"
+ state: absent
diff --git a/deployment/noheat/infra-openstack/ansible/roles/destroy_network/tasks/main.yml b/deployment/noheat/infra-openstack/ansible/roles/destroy_network/tasks/main.yml
new file mode 100644
index 000000000..1d84ab62a
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/destroy_network/tasks/main.yml
@@ -0,0 +1,6 @@
+---
+- include_tasks: destroy_network.yml
+ loop:
+ - "{{ network }}"
+ loop_control:
+ loop_var: net
diff --git a/deployment/noheat/infra-openstack/ansible/roles/destroy_securitygroup/tasks/destroy_securitygroup.yml b/deployment/noheat/infra-openstack/ansible/roles/destroy_securitygroup/tasks/destroy_securitygroup.yml
new file mode 100644
index 000000000..eb86f9bc2
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/destroy_securitygroup/tasks/destroy_securitygroup.yml
@@ -0,0 +1,5 @@
+---
+- name: "Destroy {{ secgrp.name }} security group"
+ os_security_group:
+ state: absent
+ name: "{{ secgrp.name }}"
diff --git a/deployment/noheat/infra-openstack/ansible/roles/destroy_securitygroup/tasks/main.yml b/deployment/noheat/infra-openstack/ansible/roles/destroy_securitygroup/tasks/main.yml
new file mode 100644
index 000000000..8142e8070
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/roles/destroy_securitygroup/tasks/main.yml
@@ -0,0 +1,6 @@
+---
+- include_tasks: destroy_securitygroup.yml
+ loop:
+ - "{{ securitygroup }}"
+ loop_control:
+ loop_var: secgrp
diff --git a/deployment/noheat/infra-openstack/ansible/templates/clouds.yaml.j2 b/deployment/noheat/infra-openstack/ansible/templates/clouds.yaml.j2
new file mode 100644
index 000000000..afbbc8738
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/templates/clouds.yaml.j2
@@ -0,0 +1,11 @@
+clouds:
+ openstack:
+ auth:
+ auth_url: "https://{{ hostvars['localhost']['hosts_dict']['openstack0'] }}:5000/v3"
+ project_name: "{{ openstack_tenant }}""
+ username: "{{ openstack_username }}"
+ user_domain_name: "{{ openstack_domain }}"
+ password: "{{ openstack_passwd }}"
+ region_name: "{{ openstack_region }}"
+ interface: "public"
+ identity_api_version: 3
diff --git a/deployment/noheat/infra-openstack/ansible/templates/inventory.ini.j2 b/deployment/noheat/infra-openstack/ansible/templates/inventory.ini.j2
new file mode 100644
index 000000000..79da2c603
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/templates/inventory.ini.j2
@@ -0,0 +1,53 @@
+[all]
+{% for item in hosts %}
+{{ item.key }} ansible_host={{ item.value }}
+{% endfor %}
+
+[openstack]
+{% for item in hosts %}
+{% if "openstack" in item.key %}
+{{ item.key }}
+{% endif %}
+{% endfor %}
+
+[operator]
+{% for item in hosts %}
+{% if "operator" in item.key %}
+{{ item.key }}
+{% endif %}
+{% endfor %}
+
+[control]
+{% for item in hosts %}
+{% if "control" in item.key %}
+{{ item.key }}
+{% endif %}
+{% endfor %}
+
+[workers]
+{% for item in hosts %}
+{% if "worker" in item.key %}
+{{ item.key }}
+{% endif %}
+{% endfor %}
+
+[nfs]
+{% for item in hosts %}
+{% if "nfs" in item.key %}
+{{ item.key }}
+{% endif %}
+{% endfor %}
+
+[nfs:vars]
+nfs_role="server"
+
+[control:vars]
+nfs_role="client"
+
+[workers:vars]
+nfs_role="client"
+
+[all:vars]
+ansible_ssh_private_key_file="~/.ssh/{{ keypair.name }}"
+ansible_ssh_common_args='-o StrictHostKeyChecking=no'
+ansible_python_interpreter="/usr/bin/python3"
diff --git a/deployment/noheat/infra-openstack/ansible/templates/openstack.yml.j2 b/deployment/noheat/infra-openstack/ansible/templates/openstack.yml.j2
new file mode 100644
index 000000000..25233abca
--- /dev/null
+++ b/deployment/noheat/infra-openstack/ansible/templates/openstack.yml.j2
@@ -0,0 +1,5 @@
+---
+openstack_username: "{{ openstack_username }}"
+openstack_passwd: "{{ openstack_passwd }}"
+openstack_region: "{{ openstack_region }}"
+openstack_tenant: "{{ openstack_tenant }}"
diff --git a/deployment/noheat/infra-openstack/vagrant/Vagrantfile b/deployment/noheat/infra-openstack/vagrant/Vagrantfile
new file mode 100644
index 000000000..ed1a3d076
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/Vagrantfile
@@ -0,0 +1,167 @@
+# -*- mode: ruby -*-
+# -*- coding: utf-8 -*-
+
+host_folder_ansible = "../ansible"
+synced_folder_ansible = "/ansible"
+synced_folder_main = "/vagrant"
+synced_folder_config = "#{synced_folder_main}/config"
+os_config = "#{synced_folder_config}/local.conf"
+os_clouds_template = "#{synced_folder_config}/clouds.yaml"
+os_clouds_dir = "${HOME}/.config/openstack"
+os_clouds_config = "#{os_clouds_dir}/clouds.yaml"
+os_admin = "admin"
+os_user = "demo"
+image_url = "https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img"
+image_name = "Ubuntu_20.04"
+
+vm_cpu = 1
+vm_cpus = 4
+vm_memory = 1 * 1024
+vm_memory_os = 8 * 1024
+vm_disk = 32
+vm_box = "generic/ubuntu2004"
+
+operation = {
+ name: 'operator',
+ hostname: 'operator',
+ ip: '172.17.5.254',
+ ip_os: '172.24.4.254',
+ cpus: vm_cpu,
+ memory: vm_memory,
+ disk: vm_disk
+}
+devstack = {
+ name: 'devstack',
+ hostname: 'devstack',
+ ip: '172.17.5.200',
+ ip_os: '172.24.4.2',
+ cpus: vm_cpus,
+ memory: vm_memory_os,
+ disk: vm_disk
+}
+
+all = [] << operation << devstack
+
+operation_post_msg = "Run: \"vagrant provision #{operation[:name]} --provision-with=add_os_image,run_playbook_create\" to complete infrastructure deployment"
+
+$enable_ipv6 = <<-SCRIPT
+ sed -i'' 's/net.ipv6.conf.all.disable_ipv6.*$/net.ipv6.conf.all.disable_ipv6 = 0/' /etc/sysctl.conf
+ sysctl -p
+SCRIPT
+
+$setup_devstack = <<-SCRIPT
+ CONFIG="$1"
+ git clone https://opendev.org/openstack/devstack
+ cd devstack
+ cp "$CONFIG" .
+ ./stack.sh
+SCRIPT
+
+$setup_py = <<-SCRIPT
+ export DEBIAN_FRONTEND=noninteractive
+ apt-get update
+ apt-get install -yq python3-distutils
+
+ curl -fsSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py
+ python3 get-pip.py
+SCRIPT
+
+$setup_openstackclient = <<-SCRIPT
+ pip install --ignore-installed python-openstackclient
+ mkdir -p #{os_clouds_dir}
+SCRIPT
+
+$setup_openstacksdk = <<-SCRIPT
+ pip install ansible openstacksdk
+ mkdir -p #{os_clouds_dir}
+SCRIPT
+
+$create_os_clouds = <<-SCRIPT
+ user="$1"
+ template="$2"
+ config="$3"
+ OS_USERNAME="$user" envsubst < "$template" > "$config"
+SCRIPT
+
+$add_os_image = <<-SCRIPT
+ url="$1"
+ name="$2"
+ image="/root/${name}.img"
+ wget --quiet --continue --output-document="$image" "$url"
+ export OS_CLOUD=openstack
+ openstack image create "$name" --public --disk-format qcow2 --container-format bare --file "$image"
+SCRIPT
+
+$run_playbook = <<-SCRIPT
+ PLAYBOOK="$1"
+ export OS_CLOUD=openstack
+ cd #{synced_folder_ansible}
+ ansible-playbook "$PLAYBOOK"
+SCRIPT
+
+Vagrant.configure("2") do |config|
+ all.each do |machine|
+ config.vm.define machine[:name] do |config|
+ config.vm.box = vm_box
+ config.vm.hostname = machine[:hostname]
+
+ config.vm.provider :virtualbox do |v|
+ v.name = machine[:name]
+ v.memory = machine[:memory]
+ v.cpus = machine[:cpus]
+ end
+
+ config.vm.provider :libvirt do |v|
+ v.memory = machine[:memory]
+ v.cpus = machine[:cpus]
+ v.machine_virtual_size = machine[:disk] # set at VM creation
+ end
+
+ config.vm.network :private_network, ip: machine[:ip]
+ config.vm.network :private_network, ip: machine[:ip_os]
+
+ if machine[:name] == 'devstack'
+ config.vm.network "forwarded_port", guest: 80, host: 8080
+
+ config.vm.synced_folder ".", synced_folder_main, type: "rsync", rsync__exclude: "Vagrantfile"
+
+ config.vm.provision "enable_ipv6", type: :shell, run: "always", inline: $enable_ipv6
+ config.vm.provision "setup_devstack", type: :shell, privileged: false, inline: $setup_devstack, args: os_config
+ end
+
+ if machine[:name] == 'operator'
+ config.vm.synced_folder ".", synced_folder_main, type: "rsync", rsync__exclude: "Vagrantfile"
+ config.vm.synced_folder host_folder_ansible, synced_folder_ansible, type: "rsync"
+
+ config.vm.provision "setup_py", type: :shell, inline: $setup_py
+ config.vm.provision "setup_openstackclient", type: :shell, inline: $setup_openstackclient
+ config.vm.provision "create_os_clouds_admin", type: :shell, run: "always" do |s|
+ s.inline = $create_os_clouds
+ s.args = [os_admin, os_clouds_template, os_clouds_config]
+ end
+ config.vm.provision "setup_openstacksdk", type: :shell, privileged: false, inline: $setup_openstacksdk
+ config.vm.provision "create_os_clouds", type: :shell, run: "always" do |s|
+ s.privileged = false
+ s.inline = $create_os_clouds
+ s.args = [os_user, os_clouds_template, os_clouds_config]
+ end
+
+ config.vm.post_up_message = operation_post_msg
+ config.vm.provision "add_os_image", type: :shell, run: "never" do |s|
+ s.inline = $add_os_image
+ s.args = [image_url, image_name]
+ end
+ config.vm.provision "run_playbook_create", type: :shell, run: "never" do |s|
+ s.privileged = false
+ s.inline = $run_playbook
+ s.args = "create.yml"
+ end
+ config.vm.provision "run_playbook_destroy", type: :shell, run: "never" do |s|
+ s.privileged = false
+ s.inline = $run_playbook
+ s.args = "destroy.yml"
+ end
+ end
+ end
+ end
+end
diff --git a/deployment/noheat/infra-openstack/vagrant/config/clouds.yaml b/deployment/noheat/infra-openstack/vagrant/config/clouds.yaml
new file mode 100644
index 000000000..f4a009302
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/config/clouds.yaml
@@ -0,0 +1,12 @@
+clouds:
+ openstack:
+ auth:
+ auth_url: http://172.17.5.200/identity
+ username: "${OS_USERNAME}"
+ password: "default123456!"
+ project_name: "demo"
+ project_domain_name: "Default"
+ user_domain_name: "Default"
+ region_name: "RegionOne"
+ interface: "public"
+ identity_api_version: 3
diff --git a/deployment/noheat/infra-openstack/vagrant/config/local.conf b/deployment/noheat/infra-openstack/vagrant/config/local.conf
new file mode 100644
index 000000000..c301d853c
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/config/local.conf
@@ -0,0 +1,6 @@
+[[local|localrc]]
+PUBLIC_INTERFACE=eth2
+ADMIN_PASSWORD=default123456!
+DATABASE_PASSWORD=$ADMIN_PASSWORD
+RABBIT_PASSWORD=$ADMIN_PASSWORD
+SERVICE_PASSWORD=$ADMIN_PASSWORD
diff --git a/deployment/noheat/infra-openstack/vagrant/test/Makefile b/deployment/noheat/infra-openstack/vagrant/test/Makefile
new file mode 100644
index 000000000..403263dfc
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/Makefile
@@ -0,0 +1,12 @@
+rwildcard = $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $2,$d))
+
+.PHONY: test
+test: $(patsubst %.test,%.stdout,$(call rwildcard,,%.test))
+
+%.stdout: %.test
+ ./$< > $@ 2> $(patsubst %.stdout,%.stderr,$@) \
+ || (touch --date=@0 $@; false)
+ git diff --exit-code --src-prefix=expected/ --dst-prefix=actual/ \
+ $@ $(patsubst %.stdout,%.stderr,$@) \
+ || (touch --date=@0 $@; false)
+
diff --git a/deployment/noheat/infra-openstack/vagrant/test/README.rst b/deployment/noheat/infra-openstack/vagrant/test/README.rst
new file mode 100644
index 000000000..03d9ea101
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/README.rst
@@ -0,0 +1,31 @@
+==============================
+ Vagrant: simple test harness
+==============================
+
+Use ``make`` and ``git diff`` for a simple test harness for Vagrant-based environment.
+
+Prerequisites
+-------------
+
+Dependencies
+~~~~~~~~~~~~
+
+- make: tested on 4.1
+- git: tested on 2.17.1
+
+
+Running
+-------
+
+Command
+~~~~~~~
+
+.. code-block:: shell
+
+ $ make test
+
+
+Credit
+------
+
+This is based on https://chrismorgan.info/blog/make-and-git-diff-test-harness blog post.
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_host.stderr b/deployment/noheat/infra-openstack/vagrant/test/create_host.stderr
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_host.stderr
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_host.stdout b/deployment/noheat/infra-openstack/vagrant/test/create_host.stdout
new file mode 100644
index 000000000..25c23dda2
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_host.stdout
@@ -0,0 +1 @@
+"operator0"
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_host.test b/deployment/noheat/infra-openstack/vagrant/test/create_host.test
new file mode 100755
index 000000000..f2a1ab909
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_host.test
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+export HOST_NAME='operator0'
+
+export VAGRANT_CWD='..'
+
+set_up() {
+ vagrant up
+ vagrant provision --provision-with=run_playbook_destroy
+ vagrant provision --provision-with=run_playbook_create
+}
+
+tear_down() {
+ vagrant provision --provision-with=run_playbook_destroy
+}
+
+check() {
+ local host="$1"
+ vagrant ssh operator --no-tty -c \
+ "export OS_CLOUD=openstack; openstack server list -fcsv" \
+ | grep "$host" \
+ | cut -d',' -f2
+}
+
+set_up >/dev/null # drop provisioning output
+check "$HOST_NAME"
+tear_down >/dev/null # drop provisioning output
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_keypair.stderr b/deployment/noheat/infra-openstack/vagrant/test/create_keypair.stderr
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_keypair.stderr
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_keypair.stdout b/deployment/noheat/infra-openstack/vagrant/test/create_keypair.stdout
new file mode 100644
index 000000000..363825389
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_keypair.stdout
@@ -0,0 +1 @@
+"onap_ci_lab"
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_keypair.test b/deployment/noheat/infra-openstack/vagrant/test/create_keypair.test
new file mode 100755
index 000000000..e402fa69a
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_keypair.test
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+export KEYPAIR_NAME='onap_ci_lab'
+
+export VAGRANT_CWD='..'
+
+set_up() {
+ vagrant up
+ vagrant provision --provision-with=run_playbook_destroy
+ vagrant provision --provision-with=run_playbook_create
+}
+
+tear_down() {
+ vagrant provision --provision-with=run_playbook_destroy
+}
+
+check() {
+ local key="$1"
+ vagrant ssh operator --no-tty -c \
+ "export OS_CLOUD=openstack; openstack keypair list -fcsv" \
+ | grep "$key" \
+ | cut -d',' -f1
+}
+
+set_up >/dev/null # drop provisioning output
+check "$KEYPAIR_NAME"
+tear_down >/dev/null # drop provisioning output
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_network.stderr b/deployment/noheat/infra-openstack/vagrant/test/create_network.stderr
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_network.stderr
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_network.stdout b/deployment/noheat/infra-openstack/vagrant/test/create_network.stdout
new file mode 100644
index 000000000..363825389
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_network.stdout
@@ -0,0 +1 @@
+"onap_ci_lab"
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_network.test b/deployment/noheat/infra-openstack/vagrant/test/create_network.test
new file mode 100755
index 000000000..d81a12fa6
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_network.test
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+export NETWORK_NAME='onap_ci_lab'
+
+export VAGRANT_CWD='..'
+
+set_up() {
+ vagrant up
+ vagrant provision --provision-with=run_playbook_destroy
+ vagrant provision --provision-with=run_playbook_create
+}
+
+tear_down() {
+ vagrant provision --provision-with=run_playbook_destroy
+}
+
+check() {
+ local net="$1"
+ vagrant ssh operator --no-tty -c \
+ "export OS_CLOUD=openstack; openstack network list -fcsv" \
+ | grep "$net" \
+ | cut -d',' -f2
+}
+
+set_up >/dev/null # drop provisioning output
+check "$NETWORK_NAME"
+tear_down >/dev/null # drop provisioning output
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.stderr b/deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.stderr
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.stderr
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.stdout b/deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.stdout
new file mode 100644
index 000000000..363825389
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.stdout
@@ -0,0 +1 @@
+"onap_ci_lab"
diff --git a/deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.test b/deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.test
new file mode 100755
index 000000000..6ac7fdc85
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/create_securitygroup.test
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+export SECURITYGROUP_NAME='onap_ci_lab'
+
+export VAGRANT_CWD='..'
+
+set_up() {
+ vagrant up
+ vagrant provision --provision-with=run_playbook_destroy
+ vagrant provision --provision-with=run_playbook_create
+}
+
+tear_down() {
+ vagrant provision --provision-with=run_playbook_destroy
+}
+
+check() {
+ local secgrp="$1"
+ vagrant ssh operator --no-tty -c \
+ "export OS_CLOUD=openstack; openstack security group list -fcsv" \
+ | grep "$secgrp" \
+ | cut -d',' -f2
+}
+
+set_up >/dev/null # drop provisioning output
+check "$SECURITYGROUP_NAME"
+tear_down >/dev/null # drop provisioning output
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_host.stderr b/deployment/noheat/infra-openstack/vagrant/test/destroy_host.stderr
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_host.stderr
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_host.stdout b/deployment/noheat/infra-openstack/vagrant/test/destroy_host.stdout
new file mode 100644
index 000000000..30d7e153a
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_host.stdout
@@ -0,0 +1 @@
+Host operator0 not found.
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_host.test b/deployment/noheat/infra-openstack/vagrant/test/destroy_host.test
new file mode 100755
index 000000000..8217081b1
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_host.test
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+export HOST_NAME='operator0'
+
+export VAGRANT_CWD='..'
+
+set_up() {
+ vagrant up
+ vagrant provision --provision-with=run_playbook_create
+ vagrant provision --provision-with=run_playbook_destroy
+}
+
+check() {
+ local host="$1"
+ vagrant ssh operator --no-tty -c \
+ "export OS_CLOUD=openstack; openstack server list -fcsv" \
+ | grep "$host" \
+ || echo "Host ${host} not found."
+}
+
+set_up >/dev/null # drop provisioning output
+check "$HOST_NAME"
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.stderr b/deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.stderr
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.stderr
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.stdout b/deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.stdout
new file mode 100644
index 000000000..df6e49297
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.stdout
@@ -0,0 +1 @@
+Keypair onap_ci_lab not found.
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.test b/deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.test
new file mode 100755
index 000000000..42132b347
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_keypair.test
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+export KEYPAIR_NAME='onap_ci_lab'
+
+export VAGRANT_CWD='..'
+
+set_up() {
+ vagrant up
+ vagrant provision --provision-with=run_playbook_create
+ vagrant provision --provision-with=run_playbook_destroy
+}
+
+check() {
+ local key="$1"
+ vagrant ssh operator --no-tty -c \
+ "export OS_CLOUD=openstack; openstack keypair list -fcsv" \
+ | grep "$key" \
+ || echo "Keypair ${key} not found."
+}
+
+set_up >/dev/null # drop provisioning output
+check "$KEYPAIR_NAME"
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_network.stderr b/deployment/noheat/infra-openstack/vagrant/test/destroy_network.stderr
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_network.stderr
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_network.stdout b/deployment/noheat/infra-openstack/vagrant/test/destroy_network.stdout
new file mode 100644
index 000000000..d48081495
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_network.stdout
@@ -0,0 +1 @@
+Network onap_ci_lab not found.
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_network.test b/deployment/noheat/infra-openstack/vagrant/test/destroy_network.test
new file mode 100755
index 000000000..182d7dcaf
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_network.test
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+export NETWORK_NAME='onap_ci_lab'
+
+export VAGRANT_CWD='..'
+
+set_up() {
+ vagrant up
+ vagrant provision --provision-with=run_playbook_create
+ vagrant provision --provision-with=run_playbook_destroy
+}
+
+check() {
+ local net="$1"
+ vagrant ssh operator --no-tty -c \
+ "export OS_CLOUD=openstack; openstack network list -fcsv" \
+ | grep "$net" \
+ || echo "Network ${net} not found."
+}
+
+set_up >/dev/null # drop provisioning output
+check "$NETWORK_NAME"
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.stderr b/deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.stderr
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.stderr
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.stdout b/deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.stdout
new file mode 100644
index 000000000..7adb2f89a
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.stdout
@@ -0,0 +1 @@
+Security group onap_ci_lab not found.
diff --git a/deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.test b/deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.test
new file mode 100755
index 000000000..ce65f1f08
--- /dev/null
+++ b/deployment/noheat/infra-openstack/vagrant/test/destroy_securitygroup.test
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+export SECURITYGROUP_NAME='onap_ci_lab'
+
+export VAGRANT_CWD='..'
+
+set_up() {
+ vagrant up
+ vagrant provision --provision-with=run_playbook_create
+ vagrant provision --provision-with=run_playbook_destroy
+}
+
+check() {
+ local secgrp="$1"
+ vagrant ssh operator --no-tty -c \
+ "export OS_CLOUD=openstack; openstack security group list -fcsv" \
+ | grep "$secgrp" \
+ || echo "Security group ${secgrp} not found."
+}
+
+set_up >/dev/null # drop provisioning output
+check "$SECURITYGROUP_NAME"
diff --git a/deployment/noheat/requirements.txt b/deployment/noheat/requirements.txt
new file mode 100644
index 000000000..8ef36fc05
--- /dev/null
+++ b/deployment/noheat/requirements.txt
@@ -0,0 +1,3 @@
+wheel==0.37.1
+openstacksdk==0.61.0
+ansible-core==2.13.5
diff --git a/deployment/noheat/requirements.yml b/deployment/noheat/requirements.yml
new file mode 100644
index 000000000..2a185e6b9
--- /dev/null
+++ b/deployment/noheat/requirements.yml
@@ -0,0 +1,10 @@
+---
+collections:
+ - name: ansible.posix
+ version: 1.4.0
+ - name: community.general
+ version: 5.8.0
+ - name: community.crypto
+ version: 2.8.0
+ - name: openstack.cloud
+ version: 1.10.0