diff --git a/doc/source/_images/vagrant-devstack.svg b/doc/source/_images/vagrant-devstack.svg
new file mode 100644
index 000000000..5a5f9d4d8
--- /dev/null
+++ b/doc/source/_images/vagrant-devstack.svg
@@ -0,0 +1,347 @@
+
+
+
+
diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst
index 0b768f23e..8d806357b 100644
--- a/doc/source/contributor/index.rst
+++ b/doc/source/contributor/index.rst
@@ -30,6 +30,7 @@ Developer Info
api_extensions.rst
tacker_functional_test.rst
dashboards.rst
+ vagrant_devstack.rst
Code Documentation
------------------
diff --git a/doc/source/contributor/vagrant_devstack.rst b/doc/source/contributor/vagrant_devstack.rst
new file mode 100644
index 000000000..f683fa67c
--- /dev/null
+++ b/doc/source/contributor/vagrant_devstack.rst
@@ -0,0 +1,209 @@
+..
+ Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
+ All Rights Reserved.
+
+ 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.
+
+Devstack Installation with Vagrant
+==================================
+
+This documentation is for introducing a deployment tool for Tacker.
+
+You can find a :doc:`basic installation ` for deploying
+OpenStack environment using ``devstack`` as a part of
+:doc:`Tacker Installation Guide`.
+This guide expects you have already setup your VMs and installed all
+packages required to run OpenStack.
+
+However, it's something annoying for beginners, or developers frequently
+cleanup their environment. You may want to use a tool to shortcut such a
+tasks. This tool enables you to deploy several usecases with minimal effort.
+
+How to Use
+----------
+
+Install Required Tools
+~~~~~~~~~~~~~~~~~~~~~~
+
+This installer consists of ``vagrant`` and ``ansible``.
+Please follow instructions on official sites for installation.
+
+* `vagrant `_
+* `ansible `_
+
+.. note::
+
+ In this documentation, it's supposed you use
+ `VirtualBox `_, but you can use any other
+ hypervisor supported by ``vagrant``.
+
+.. figure:: ../_images/vagrant-devstack.svg
+ :scale: 55
+
+You should install plugin ``vagrant-disksize`` before launching your VMs
+to enable to expand size of volume of VMs. It is because the default size
+of box is fixed and not enough for deploying Tacker.
+
+.. code-block:: console
+
+ $ vagrant plugin install vagrant-disksize
+
+Setup Configuration File
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. note::
+
+ Create your ssh key before running this tool to enable to direct login
+ with auto-generated ssh config although you can still do two step login
+ starts from ``vagrant ssh``. You can login to ``controller`` host with
+ auto-generated config ``ssh_config`` as below.
+
+ .. code-block:: console
+
+ $ ssh -F ssh_config controller
+
+Setup ``machines.yml`` which is a config file defines parameters of each
+VM you deploy.
+You can find some templates of ``machines.yml`` in ``samples`` directory.
+This config file should be placed at ``/path/to/tacker/vagrant/devstack``
+while running ``vagrant up``, or failed to run the command.
+
+.. code-block:: console
+
+ $ cd /path/to/tacker/vagrant/devstack
+ $ cp samples/machines.yml ./
+ $ YOUR_FAVORITE_EDITOR machines.yml
+
+As named as ``machines.yml``, it defines parameters of each VMs.
+There are two top sections in the file, ``global`` and ``machines``.
+The former one defines common parameters among the VMs, and later one
+is for each VM.
+
+.. note::
+ ``global`` is optional currently and only one parameter under the section
+ is ``ssh_pub_key`` for specifying its location explicitly. You don't need
+ to use it if your public key is ``$HOME/.ssh/id_rsa.pub``.
+
+
+Here is an example of ``machine.yml``. It's is for single node usecase
+and ``machines`` has only one entry.
+
+.. literalinclude:: ../../../vagrant/devstack/samples/machines.yml
+ :language: yaml
+
+There are several parameters for each VM supported in this tool.
+
+.. list-table::
+ :widths: 30 125
+ :header-rows: 1
+
+ * - Attribute
+ - Description
+ * - hostname
+ - Any hostname for convenience, such as ``controller`` or ``compute``.
+ * - provider
+ - Vagrant box provider.
+ * - box
+ - Name of the box.
+ * - nof_cpus
+ - The number of CPUs assigned to the VM.
+ * - mem_size
+ - The size of memory assigned to the VM.
+ * - disk_size
+ - The size of disk assigned to the VM.
+ * - private_ips
+ - Series of private IPs.
+ * - public_ips
+ - Series of public IPs.
+ * - fwd_port_list
+ - Series of combination of ``guest`` and ``host`` ports for port
+ forwarding.
+
+You also update entries of IP addresses in the inventory file
+``hosts`` as you defined each ``private_ips`` in ``machines.yml``.
+
+Now, you are ready to fire up the VMs and deploying OpenStack with
+``ansible``.
+
+Deploy OpenStack with Devstack
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Run ``vagrant up`` so that launches VMs and create ``stack`` user on them.
+
+.. code-block:: console
+
+ $ vagrant up
+
+If ``vagrant up`` is completed successfully, you can login to the VMs as
+``stack`` user with your ssh public key.
+
+This tool provides ``ansible`` playbooks for setting up ``devstack``
+installation. You don't need to modify the playbooks usually, but
+configurable in ``group_vars/all.yml``. See :ref:`optional_config`
+describing how you configure the file.
+
+
+.. code-block:: console
+
+ $ ansible-playbook -i hosts site.yml
+
+After finished all tasks, you can login to the launched VMs. So, login to
+controller node and run ``stack.sh`` for installing OpenStack.
+You will find out that ``local.conf`` is already prepared for your
+environment.
+See instruction how to configure ``local.conf`` described in
+`DevStack Quick Start `_
+if you customize it furthermore by yourself.
+
+.. code-block:: console
+
+ $ ssh stack@192.168.33.11
+ $ cd devstack
+ $ YOUR_FAVORITE_EDITOR local.conf
+ $ ./stack.sh
+
+.. _optional_config:
+
+Options Configuration
+~~~~~~~~~~~~~~~~~~~~~
+
+There some parameters in ``group_vars/all.yml`` such as password on
+devstack or optional configurations. You don't need to update it usually.
+
+.. literalinclude:: ../../../vagrant/devstack/group_vars/all.yml
+ :language: yaml
+
+
+Developer Tools
+---------------
+
+In the playbools, installation of vim and some extra packages is included
+for developers. If you exclude such a developer tools, modify
+``group_vars/all.yml`` before running ``ansible-playbook`` command.
+
+.. list-table::
+ :widths: 30 125
+ :header-rows: 1
+
+ * - Parameter
+ - Description
+ * - use_vim_latest
+ - (Only for ubuntu) ``true`` or ``false`` for using the latest vim.
+ * - use_vim_extra_plugins
+ - ``true`` or ``false`` for installing vim packages including
+ language servers for python and bash.
+ * - use_extra_tools
+ - | ``true`` or ``false`` for using extra packages bellow.
+ | - jq
+ | - htop (Ubuntu only)
+ | - lnav (Ubuntu only)
diff --git a/vagrant/devstack/.gitignore b/vagrant/devstack/.gitignore
new file mode 100644
index 000000000..9ae9f9dad
--- /dev/null
+++ b/vagrant/devstack/.gitignore
@@ -0,0 +1,9 @@
+/machines.yml
+/helper/git_setup.sh
+
+/.vagrant/*
+*.log
+
+# except auto-generated file.
+roles/**/controller/templates/gitconfig.j2
+ssh_config
diff --git a/vagrant/devstack/README.md b/vagrant/devstack/README.md
new file mode 100644
index 000000000..68d089d3f
--- /dev/null
+++ b/vagrant/devstack/README.md
@@ -0,0 +1,83 @@
+# vagrant-devstack
+
+## What is this
+
+Deployment tool for devstack for testing multi-VM OpenStack environment,
+consists of vagrant and ansible.
+
+It only supports Ubuntu on VirtualBox currently.
+
+
+## How to use
+
+### Requirements
+
+You need to install required software before running this tool. Please follow
+instructions on official sites for installation.
+
+* [VirtualBox](https://www.virtualbox.org/)
+* [vagrant](https://www.vagrantup.com/)
+* [ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html)
+
+Before launching your VMs, you should should install plugin `vagrant-disksize`
+for expanding size of volume of VM. It is because the default size of box
+provided from Ubuntu, 10GB or so, is not enough for deploying devstack
+environment. It's required for expanding the volume size.
+
+```sh
+$ vagrant plugin install vagrant-disksize
+```
+
+### Configure and Fire Up VMs
+
+Before launching VMs with vagrant, configure `machines.yml`, which defines
+parameters of each VM you deploy. It should be placed at project root, or failed
+to run `vagrant up`. You can use template files in `samples` directory.
+
+```sh
+$ cp samples/machines.yml .
+$ YOUR_FAVORITE_EDITOR machines.yml
+```
+
+You should take care about `private_ips` which is used in `hosts` for
+`ansible-playbook` as explained later.
+
+You should confirm you have a SSH public key before you run vagrant. If your key
+is different from `~/.ssh/id_rsa.pub`, update `ssh_pub_key` in `machines.yml`.
+
+Run `vagrant up` after configurations are done. It launches VMs and create a
+user `stack` on them.
+
+```sh
+$ vagrant up
+```
+
+If `vagrant up` is completed successfully, you are ready to login to VMs as
+`stack` user with your SSH public key.
+
+### Setup Devstack
+
+This tool provides ansible playbooks for setting up devstack. You should update
+entries of IP addresses in `hosts` as you defined `private_ips` in
+`machines.yml`.
+
+There are some parameters in `group_vars/all.yml` such as password on devstack
+or optional configurations. You don't need to update it usually.
+
+```sh
+$ ansible-playbook -i hosts site.yml
+```
+
+After finished ansible's tasks, you can login to launched VMs. So, login to
+controller node and run `stack.sh` for installing OpenStack. You will find that
+`local.conf` is prepared for your environment by using its example.
+See instruction how to configure `local.conf` described in
+[DevStack Quick Start](https://docs.openstack.org/devstack/latest/)
+if you customize it by yourself.
+
+```sh
+$ ssh stack@192.168.33.11
+$ cd devstack
+$ YOUR_FAVORITE_EDITOR local.conf
+$ ./stack.sh
+```
diff --git a/vagrant/devstack/Vagrantfile b/vagrant/devstack/Vagrantfile
new file mode 100644
index 000000000..7b37e305f
--- /dev/null
+++ b/vagrant/devstack/Vagrantfile
@@ -0,0 +1,119 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# All Vagrant configuration is done below. The "2" in Vagrant.configure
+# configures the configuration version (we support older styles for
+# backwards compatibility). Please don't change it unless you know what
+# you're doing.
+
+require "yaml"
+load "lib/machine.rb"
+load "lib/vd_utils.rb"
+
+vd_config = YAML.load(open("machines.yml"))
+
+ssh_pub_key = VdUtils.ssh_pub_key(vd_config)
+machines = Machines.new(vd_config["machines"])
+
+# Check if you have already downloaded target box.
+box_list = []
+`vagrant box list`.each_line {|l|
+ box_list << l.split(" ")[0]
+}
+
+# If you don't have the box, download it.
+machines.each do |m|
+ if not (box_list.include? m.box)
+ puts "There is no box '#{m.box}' for '#{m.provider}'"
+ puts "Run 'vagrant box add #{m.box}' first"
+ end
+end
+
+Vagrant.configure("2") do |config|
+ machines.each do |machine|
+ config.vm.define machine.hostname do |server|
+ server.vm.box = machine.box
+ server.vm.hostname = machine.hostname
+
+ # server.vm.box_check_update = false
+
+ machine.private_ips.each do |ipaddr|
+ server.vm.network "private_network", ip: ipaddr
+ end
+
+ if machine.public_ips != nil
+ machine.public_ips.each do |ipaddr|
+ server.vm.network "public_network", ip: ipaddr
+ end
+ end
+
+ if machine.fwd_port_list != nil
+ machine.fwd_port_list.each do |fp|
+ ["tcp", "udp"].each do |prot|
+ server.vm.network "forwarded_port",
+ guest: fp["guest"], host: fp["host"],
+ auto_correct: true, protocol: prot
+ end
+ end
+ end
+
+ if Vagrant.has_plugin?("vagrant-proxyconf")
+ server.proxy.http = ENV["http_proxy"]
+ server.proxy.https = ENV["https_proxy"]
+ if ENV["no_proxy"] != ""
+ server.proxy.no_proxy = ENV["no_proxy"] +
+ "," + machine.private_ips.join(",")
+ end
+ end
+
+ if Vagrant.has_plugin?("vagrant-disksize")
+ server.disksize.size = "#{machine.disk_size}GB"
+ end
+
+ # TODO(yasufum) This configuration reported in [1] is required to avoid
+ # timeout for ssh login to focal64 because of setting up public key in the
+ # VM. This issue is only happened on focal, and not for bionic and xenial.
+ # Remove this config after the problem is fixed in the focal image.
+ # [1] https://bugs.launchpad.net/cloud-images/+bug/1829625
+ if machine.box == "ubuntu/focal64"
+ server.vm.provider 'virtualbox' do |v|
+ v.customize ["modifyvm", :id, "--uart1", "0x3F8", "4"]
+ v.customize ["modifyvm", :id, "--uartmode1", "file", "./ttyS0.log"]
+ end
+ end
+
+ if machine.ssh_forward_x11 == true
+ server.ssh.forward_x11 = true
+ end
+
+ server.vm.provider machine.provider do |vb|
+ # # Display the VirtualBox GUI when booting the machine
+ # vb.gui = true
+ #
+ # # Customize the amount of memory on the VM:
+ #vb.customize ["modifyhd", "disk id", "--resize", "size in megabytes"]
+ vb.cpus = "#{machine.nof_cpus}"
+ vb.memory = "#{machine.mem_size * 1024}"
+ end
+
+ # NOTE: remove `python3-launchpadlib` which causes many warinings, and
+ # run autoremove to clean related packages.
+ server.vm.provision "shell", inline: <<-SHELL
+ useradd -s /bin/bash -d /opt/stack -m stack
+ echo "stack ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/stack
+
+ # Permission of `stack` directory is 0700 on CentOS 8, but it cause an
+ # error in a sanity check for the permission while running devstack
+ # installatino.
+ chmod 755 /opt/stack
+
+ mkdir -p /opt/stack/.ssh
+ echo "#{ssh_pub_key}" >> /opt/stack/.ssh/authorized_keys
+ chown -R stack:stack /opt/stack/.ssh
+ SHELL
+
+ VdUtils.setup_git_config
+ VdUtils.setup_ssh_config(vd_config)
+ end
+ end
+end
diff --git a/vagrant/devstack/ansible.cfg b/vagrant/devstack/ansible.cfg
new file mode 100644
index 000000000..f28d89a07
--- /dev/null
+++ b/vagrant/devstack/ansible.cfg
@@ -0,0 +1,5 @@
+[defaults]
+deprecation_warnings = False
+
+[ssh_connection]
+ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
diff --git a/vagrant/devstack/group_vars/all.yml b/vagrant/devstack/group_vars/all.yml
new file mode 100644
index 000000000..56f56e325
--- /dev/null
+++ b/vagrant/devstack/group_vars/all.yml
@@ -0,0 +1,28 @@
+---
+# 1. Devstack params
+# common
+admin_password: devstack
+database_password: devstack
+rabbit_password: devstack
+service_password: devstack
+
+# controller
+service_token: devstack
+
+# compute nodes
+service_host: 192.168.33.11
+floating_range: 192.168.33.128/25
+fixed_range: 10.4.128.0/20
+
+# 2. Configure optional tools on controller node
+
+# Use the latest vim on `ppa:jonathonf/vim`, and use plugins with
+# vim-plug.
+use_vim_latest: true
+use_vim_extra_plugins: true
+
+# Clone tacker in addition to devstack.
+use_tacker: true
+
+# Use tools useful for developing.
+use_extra_tools: true
diff --git a/vagrant/devstack/helper/install_vagrant_libvirt_pkgs.sh b/vagrant/devstack/helper/install_vagrant_libvirt_pkgs.sh
new file mode 100755
index 000000000..d5507f0c2
--- /dev/null
+++ b/vagrant/devstack/helper/install_vagrant_libvirt_pkgs.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+sudo apt-get build-dep vagrant ruby-libvirt -y
+sudo apt-get install qemu libvirt-bin ebtables dnsmasq-base -y
+sudo apt-get install libxslt-dev libxml2-dev libvirt-dev zlib1g-dev ruby-dev -y
+
+vagrant plugin install vagrant-libvirt
diff --git a/vagrant/devstack/hosts b/vagrant/devstack/hosts
new file mode 100644
index 000000000..66e4ab425
--- /dev/null
+++ b/vagrant/devstack/hosts
@@ -0,0 +1,9 @@
+[ubuntu-focal.controller]
+192.168.33.11
+
+[ubuntu-focal.compute]
+#192.168.33.12
+#192.168.33.13
+
+[centos-stream8.controller]
+#192.168.33.11
diff --git a/vagrant/devstack/lib/machine.rb b/vagrant/devstack/lib/machine.rb
new file mode 100644
index 000000000..a76c6b67a
--- /dev/null
+++ b/vagrant/devstack/lib/machine.rb
@@ -0,0 +1,38 @@
+require "yaml"
+
+class Machines < Array
+
+ class Machine
+ attr_reader :hostname, :provider, :box, :nof_cpus, :mem_size, :disk_size,
+ :private_ips, :public_ips, :ssh_forward_x11, :fwd_port_list
+
+ def initialize(
+ hostname="controller", provider="virtualbox", box="ubuntu/focal64",
+ nof_cpus=2, mem_size=4, disk_size=10,
+ private_ips=["192.168.33.11"], public_ips=nil, ssh_forward_x11=false,
+ fwd_port_list=nil)
+ @hostname = hostname
+ @provider = provider
+ @box = box
+ @nof_cpus = nof_cpus
+ @mem_size = mem_size
+ @disk_size = disk_size
+ @private_ips = private_ips
+ @public_ips = public_ips
+ @ssh_forward_x11 = ssh_forward_x11
+ @fwd_port_list = fwd_port_list
+ end
+ end
+
+ def initialize(machines_attr)
+ machines_attr.each_with_index do |m, idx|
+ self[idx] = Machine.new(
+ m["hostname"], m["provider"], m["box"],
+ m["nof_cpus"], m["mem_size"], m["disk_size"],
+ m["private_ips"], m["public_ips"],
+ m["ssh_forward_x11"],
+ m["fwd_port_list"])
+ end
+ end
+
+end
diff --git a/vagrant/devstack/lib/vagrant_boxes.yml b/vagrant/devstack/lib/vagrant_boxes.yml
new file mode 100644
index 000000000..800d31cec
--- /dev/null
+++ b/vagrant/devstack/lib/vagrant_boxes.yml
@@ -0,0 +1,13 @@
+boxes:
+ ubuntu:
+ "20.04":
+ virtualbox: ubuntu/focal64
+ "18.04":
+ virtualbox: ubuntu/bionic64
+ libvirt: generic/ubuntu1804
+ "16.04":
+ virtualbox: ubuntu/xenial64
+ libvirt: yk0/ubuntu-xenial
+ centos:
+ stream8:
+ virtualbox: centos/stream8
diff --git a/vagrant/devstack/lib/vd_utils.rb b/vagrant/devstack/lib/vd_utils.rb
new file mode 100644
index 000000000..12d6c24a5
--- /dev/null
+++ b/vagrant/devstack/lib/vd_utils.rb
@@ -0,0 +1,79 @@
+# Util method in vagrant-devstack
+
+require "fileutils"
+
+module VdUtils
+
+ # Get the contents of SSH public key to upload it to VMs.
+ def ssh_pub_key(config)
+ default_key_path = "~/.ssh/id_rsa.pub"
+
+ if config["global"] != nil
+ if config["global"]["ssh_pub_key"]
+ key_path = File.expand_path(
+ config["global"]["ssh_pub_key"].gsub("$HOME", "~"))
+ end
+ end
+
+ key_path = File.expand_path(default_key_path) if key_path == nil
+
+ begin
+ ssh_pub_key = open(key_path).read.chomp
+ rescue => e
+ puts e
+ end
+
+ return ssh_pub_key
+ end
+
+
+ def setup_git_config()
+ src = "~/.gitconfig"
+
+ Dir.glob("roles/**/controller").each do |target_dir|
+ dst = "#{target_dir}/templates/gitconfig.j2"
+
+ gitconfig = File.expand_path src
+ if File.exists? gitconfig
+ FileUtils.copy(gitconfig, dst)
+ end
+ end
+ end
+
+
+ # Generate local ssh config file used by ssh with `-F` option.
+ def setup_ssh_config(config)
+ dst = File.expand_path "#{__dir__}/../ssh_config"
+
+ if config["machines"] != nil
+ entries = []
+ config["machines"].each do |m|
+ entries << {"Host" => m["hostname"],
+ "HostName" => m["private_ips"][0],
+ "User" => "stack"}
+ end
+
+ str = ""
+ entries.each do |ent|
+ ent.each do |k, v|
+ if k == "Host"
+ str += "#{k} #{v}\n"
+ else
+ str += " #{k} #{v}\n"
+ end
+ end
+ end
+ str.chomp
+
+ str += "Host *\n" +
+ " StrictHostKeyChecking no\n" +
+ " UserKnownHostsFile=/dev/null\n"
+
+ open(dst, "w+") {|f|
+ f.write(str)
+ }
+ end
+ end
+
+ module_function :ssh_pub_key, :setup_git_config, :setup_ssh_config
+end
diff --git a/vagrant/devstack/roles/centos-stream8/compute/tasks/main.yml b/vagrant/devstack/roles/centos-stream8/compute/tasks/main.yml
new file mode 100644
index 000000000..7efaf8b22
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/compute/tasks/main.yml
@@ -0,0 +1,6 @@
+---
+- include: basic_pkgs.yml
+ tags: basic_pkgs
+
+- include: devstack.yml
+ tags: devstack
diff --git a/vagrant/devstack/roles/centos-stream8/compute/templates/local.conf.j2 b/vagrant/devstack/roles/centos-stream8/compute/templates/local.conf.j2
new file mode 100644
index 000000000..51fadc645
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/compute/templates/local.conf.j2
@@ -0,0 +1,22 @@
+[[local|localrc]]
+HOST_IP={{ ansible_host }}
+FIXED_RANGE={{ fixed_range }}
+FLOATING_RANGE={{ floating_range }}
+LOGFILE=/opt/stack/logs/stack.sh.log
+
+ADMIN_PASSWORD={{ admin_password }}
+DATABASE_PASSWORD={{ database_password }}
+RABBIT_PASSWORD={{ rabbit_password }}
+SERVICE_PASSWORD={{ service_password }}
+
+DATABASE_TYPE=mysql
+SERVICE_HOST={{ service_host }}
+MYSQL_HOST=$SERVICE_HOST
+RABBIT_HOST=$SERVICE_HOST
+GLANCE_HOSTPORT=$SERVICE_HOST:9292
+
+ENABLED_SERVICES=n-cpu,q-agt,c-vol,placement-client
+NOVA_VNC_ENABLED=True
+NOVNCPROXY_URL="http://$SERVICE_HOST:6080/vnc_lite.html"
+VNCSERVER_LISTEN=$HOST_IP
+VNCSERVER_PROXYCLIENT_ADDRESS=$VNCSERVER_LISTEN
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/basic_pkgs.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/basic_pkgs.yml
new file mode 100644
index 000000000..c6f63e72a
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/basic_pkgs.yml
@@ -0,0 +1,14 @@
+---
+- name: install basic packages
+ become: yes
+ yum: name={{ item }} update_cache=yes
+ with_items:
+ - python3
+ - python3-devel
+ - python3-pip
+ - git
+ - vim
+
+- name: install git-review with pip
+ become: yes
+ pip: name=git-review
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/devstack.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/devstack.yml
new file mode 100644
index 000000000..359001f4d
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/devstack.yml
@@ -0,0 +1,22 @@
+---
+- name: update git config
+ git_config:
+ scope: global
+ name: 'url.https://.insteadOf'
+ value: 'git://'
+
+- name: git clone devstack
+ git:
+ repo=https://opendev.org/openstack/devstack.git
+ dest={{ ansible_env.HOME }}/devstack
+
+- name: install os-testr
+ become: yes
+ pip:
+ name: os-testr
+ state: latest
+
+- name: install tox
+ become: yes
+ pip:
+ name: tox
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/extra_tools.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/extra_tools.yml
new file mode 100644
index 000000000..2bd6aecba
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/extra_tools.yml
@@ -0,0 +1,6 @@
+---
+- name: install extra packages
+ become: yes
+ yum: name={{ item }}
+ with_items:
+ - jq
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/git_config.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/git_config.yml
new file mode 100644
index 000000000..ae50d2e21
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/git_config.yml
@@ -0,0 +1,4 @@
+---
+- name: copy .gitconfig on host to VM
+ template: src=templates/gitconfig.j2 dest={{ ansible_env.HOME }}/.gitconfig
+ mode=664
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/kubernetes.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/kubernetes.yml
new file mode 100644
index 000000000..bd139c696
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/kubernetes.yml
@@ -0,0 +1,10 @@
+---
+- name: put yum repo for k8s
+ become: yes
+ template: src=templates/kubernetes.repo.j2
+ dest=/etc/yum.repos.d/kubernetes.repo
+ mode=755
+
+- name: install k8s
+ become: yes
+ dnf: name=kubeadm update_cache=yes
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/main.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/main.yml
new file mode 100644
index 000000000..f7c366e53
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/main.yml
@@ -0,0 +1,21 @@
+---
+- include: basic_pkgs.yml
+- include: set_path_env.yml
+- include: git_config.yml
+
+- include: python3_specific_vers.yml
+
+- include: vim_extra_plugins.yml
+ when: use_vim_extra_plugins == true
+
+- include: kubernetes.yml
+
+- include: ovn.yml
+
+- include: devstack.yml
+
+- include: setup_tacker.yml
+ when: use_tacker == true
+
+- include: extra_tools.yml
+ when: use_extra_tools == true
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/ovn.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/ovn.yml
new file mode 100644
index 000000000..3dfc0e4c7
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/ovn.yml
@@ -0,0 +1,24 @@
+---
+- name: install ovn via centos-openstack
+ become: yes
+ yum: name={{ item }} update_cache=yes
+ with_items:
+ - centos-release-openstack-victoria
+
+- name: install ovn
+ become: yes
+ yum: name={{ item }} update_cache=yes
+ with_items:
+ - openvswitch
+ - openvswitch-ovn-common
+ - openvswitch-ovn-central
+ - openvswitch-ovn-host
+
+- name: activate ovs and ovn
+ become: yes
+ systemd: enabled=yes state=started name={{ item }}
+ with_items:
+ - ovn-northd.service
+ - ovn-controller.service
+ - ovs-vswitchd.service
+ - ovsdb-server.service
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/python3_specific_vers.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/python3_specific_vers.yml
new file mode 100644
index 000000000..ad24170fb
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/python3_specific_vers.yml
@@ -0,0 +1,9 @@
+---
+- name: install python3 other than default version
+ become: yes
+ yum: name={{ item }}
+ with_items:
+ - python38
+ - python38-devel
+ - python39
+ - python39-devel
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/set_path_env.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/set_path_env.yml
new file mode 100644
index 000000000..892e7124f
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/set_path_env.yml
@@ -0,0 +1,5 @@
+---
+- name: set PATH for '.local/bin'
+ lineinfile:
+ line="export PATH=$HOME/.local/bin:$PATH:/sbin"
+ dest={{ ansible_env.HOME }}/.bashrc
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/setup_tacker.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/setup_tacker.yml
new file mode 100644
index 000000000..16d3f84c2
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/setup_tacker.yml
@@ -0,0 +1,65 @@
+---
+- name: git clone tacker
+ git:
+ repo=https://opendev.org/openstack/tacker.git
+ dest={{ ansible_env.HOME }}/tacker
+
+- name: copy local.conf
+ shell: cp {{ ansible_env.HOME }}/tacker/devstack/{{ item }} \
+ {{ ansible_env.HOME }}/devstack/{{ item }}
+ with_items:
+ - local.conf.example
+ - local.conf.kubernetes
+
+- name: update HOST_IP in devstack/local.conf.example
+ lineinfile:
+ path={{ ansible_env.HOME }}/devstack/{{ item }}
+ line='HOST_IP={{ ansible_host }}'
+ regexp='^HOST_IP=127\.0\.0\.1'
+ with_items:
+ - local.conf.example
+ - local.conf.kubernetes
+
+- name: update other params in devstack/local.conf.example
+ lineinfile:
+ path={{ ansible_env.HOME }}/devstack/local.conf.example
+ line={{ item.line }}
+ regexp={{ item.regexp }}
+ with_items:
+ - line: 'ADMIN_PASSWORD={{ admin_password }}'
+ regexp: '^ADMIN_PASSWORD=devstack'
+ - line: 'MYSQL_PASSWORD={{ database_password }}'
+ regexp: '^MYSQL_PASSWORD=devstack'
+ - line: 'RABBIT_PASSWORD={{ rabbit_password }}'
+ regexp: '^RABBIT_PASSWORD=devstack'
+ - line: 'SERVICE_PASSWORD={{ service_password }}'
+ regexp: '^SERVICE_PASSWORD=\$ADMIN_PASSWORD'
+ - line: 'SERVICE_TOKEN={{ service_token }}'
+ regexp: '^SERVICE_TOKEN=devstack'
+
+- name: update HOST_IP in devstack/local.conf.kubernetes
+ lineinfile:
+ path={{ ansible_env.HOME }}/devstack/local.conf.kubernetes
+ line='HOST_IP={{ service_host }}'
+ regexp='^HOST_IP=127\.0\.0\.1'
+
+- name: update other params in devstack/local.conf.kubernetes
+ lineinfile:
+ path={{ ansible_env.HOME }}/devstack/local.conf.kubernetes
+ line={{ item.line }}
+ regexp={{ item.regexp }}
+ with_items:
+ - line: 'ADMIN_PASSWORD={{ admin_password }}'
+ regexp: '^ADMIN_PASSWORD=devstack'
+ - line: 'MYSQL_PASSWORD={{ database_password }}'
+ regexp: '^MYSQL_PASSWORD=devstack'
+ - line: 'RABBIT_PASSWORD={{ rabbit_password }}'
+ regexp: '^RABBIT_PASSWORD=devstack'
+ - line: 'SERVICE_PASSWORD={{ service_password }}'
+ regexp: '^SERVICE_PASSWORD=\$ADMIN_PASSWORD'
+ - line: 'SERVICE_TOKEN={{ service_token }}'
+ regexp: '^SERVICE_TOKEN=devstack'
+
+- name: use local.conf.example as local.conf
+ shell: cp {{ ansible_env.HOME }}/devstack/local.conf.example \
+ {{ ansible_env.HOME }}/devstack/local.conf
diff --git a/vagrant/devstack/roles/centos-stream8/controller/tasks/vim_extra_plugins.yml b/vagrant/devstack/roles/centos-stream8/controller/tasks/vim_extra_plugins.yml
new file mode 100644
index 000000000..4a976052a
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/tasks/vim_extra_plugins.yml
@@ -0,0 +1,35 @@
+---
+- name: create dir for plug.vim
+ file: path={{ ansible_env.HOME }}/.vim/autoload state=directory
+
+- name: download plug.vim
+ get_url: url=https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
+ dest={{ ansible_env.HOME }}/.vim/autoload/plug.vim
+
+- name: vimrc
+ template: src=templates/vimrc.j2 dest={{ ansible_env.HOME }}/.vimrc
+ mode=664
+
+- name: install exuberant-ctags
+ become: yes
+ yum: name=ctags
+
+- name: install npm
+ become: yes
+ yum: name=npm
+
+- name: install bash-language-server
+ become: yes
+ npm:
+ name: bash-language-server
+ global: yes
+
+# required for python-language-server
+- name: install gcc-c++
+ become: yes
+ yum: name=gcc-c++
+
+- name: install python-language-server
+ become: yes
+ pip:
+ name: python-language-server[all]
diff --git a/vagrant/devstack/roles/centos-stream8/controller/templates/kubernetes.repo.j2 b/vagrant/devstack/roles/centos-stream8/controller/templates/kubernetes.repo.j2
new file mode 100644
index 000000000..65eda50b5
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/templates/kubernetes.repo.j2
@@ -0,0 +1,7 @@
+[kubernetes]
+name=Kubernetes
+baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
+enabled=1
+gpgcheck=1
+repo_gpgcheck=1
+gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
diff --git a/vagrant/devstack/roles/centos-stream8/controller/templates/vimrc.j2 b/vagrant/devstack/roles/centos-stream8/controller/templates/vimrc.j2
new file mode 100644
index 000000000..222d8acd4
--- /dev/null
+++ b/vagrant/devstack/roles/centos-stream8/controller/templates/vimrc.j2
@@ -0,0 +1,159 @@
+" Specify a directory for plugins
+" - For Neovim: stdpath('data') . '/plugged'
+" - Avoid using standard Vim directory names like 'plugin'
+call plug#begin('~/.vim/plugged')
+
+" Make sure you use single quotes
+
+" Shorthand notation; fetches https://github.com/junegunn/vim-easy-align
+Plug 'junegunn/vim-easy-align'
+
+" Any valid git URL is allowed
+Plug 'https://github.com/junegunn/vim-github-dashboard.git'
+
+" Multiple Plug commands can be written in a single line using | separators
+Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets'
+
+" On-demand loading
+Plug 'preservim/nerdtree', { 'on': 'NERDTreeToggle' }
+Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
+
+" Using a non-master branch
+Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' }
+
+" Using a tagged release; wildcard allowed (requires git 1.9.2 or above)
+"Plug 'fatih/vim-go', { 'tag': '*' }
+
+" Plugin options
+"Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' }
+Plug 'nsf/gocode'
+
+" Plugin outside ~/.vim/plugged with post-update hook
+Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
+Plug 'junegunn/fzf.vim'
+let g:fzf_command_prefix = 'Fzf'
+
+" Unmanaged plugin (manually installed and updated)
+"Plug '~/my-prototype-plugin'
+
+Plug 'tpope/vim-sensible'
+Plug 'tpope/vim-surround'
+Plug 'tpope/vim-fugitive'
+Plug 'thinca/vim-quickrun'
+Plug 'ctrlpvim/ctrlp.vim'
+Plug 'flazz/vim-colorschemes'
+Plug 'thinca/vim-quickrun'
+
+Plug 'jpo/vim-railscasts-theme'
+Plug 'godlygeek/tabular'
+Plug 'plasticboy/vim-markdown'
+let g:vim_markdown_folding_disabled = 1
+
+Plug 'dense-analysis/ale'
+
+Plug 'vim-scripts/taglist.vim'
+let Tlist_Use_Right_Window = 1
+
+Plug 'prabirshrestha/async.vim'
+Plug 'prabirshrestha/vim-lsp'
+Plug 'prabirshrestha/asyncomplete.vim'
+Plug 'prabirshrestha/asyncomplete-lsp.vim'
+Plug 'natebosch/vim-lsc'
+Plug 'thomasfaingnaert/vim-lsp-snippets'
+Plug 'thomasfaingnaert/vim-lsp-ultisnips'
+let g:lsp_async_completion = 1
+
+Plug 'tyru/current-func-info.vim'
+Plug 'yasufum/vim-os-unittestr'
+
+" Initialize plugin system
+call plug#end()
+
+syntax on
+set number
+set relativenumber
+set shiftwidth=4
+set tabstop=4
+set expandtab
+set showcmd
+set showmatch
+set hlsearch
+set laststatus=2
+set encoding=utf-8
+set fileencoding=utf-8
+set termencoding=utf-8
+set autoindent
+set scrolloff=4
+set smartcase
+set textwidth=80
+set colorcolumn=+1
+
+set visualbell t_vb=
+set noerrorbells
+
+set path+=**
+set wildmenu
+
+colorscheme delek
+"colorscheme railscasts
+
+autocmd FileType python set textwidth=79
+autocmd FileType gitcommit set textwidth=72
+
+nnoremap ;
+nnoremap :NERDTreeToggle
+" enable line numbers
+let NERDTreeShowLineNumbers=1
+" make sure relative line number is used
+autocmd FileType nerdtree setlocal relativenumber
+
+""" Open vimrc from ':Conf' command.
+function! s:open_vimrc() abort
+ new ~/.vimrc
+endfunction
+command! Conf call s:open_vimrc()
+
+function! s:configure_lsp() abort
+ setlocal omnifunc=lsp#complete
+ nnoremap :LspDefinition
+ nnoremap :LspHover
+ "nnoremap
+ nnoremap d :LspDefinition
+ nnoremap r :LspReferences
+ nnoremap t :LspTypeDefinition
+ nnoremap s :LspDocumentSymbol
+ nnoremap S :LspWorkspaceSymbol
+ nnoremap f :LspDocumentFormat
+ vnoremap f :LspDocumentRangeFormat
+ nnoremap h :LspHover
+ nnoremap i :LspImplementation
+ nnoremap e :LspNextError
+ nnoremap E :LspPreviousError
+ nnoremap N :LspRename
+endfunction
+
+" Do ALE diagnostic
+let g:lsp_diagnostics_enabled = 0
+
+if executable('pyls')
+ autocmd User lsp_setup call lsp#register_server({
+ \ 'name': 'pyls',
+ \ 'cmd': { server_info -> ['pyls'] },
+ \ 'whitelist': ['python'],
+ \ 'workspace_config': {'pyls': {'plugins': {
+ \ 'pycodestyle': {'enabled': v:false},
+ \ 'jedi_definition': {'follow_imports': v:true, 'follow_builtin_imports': v:true},}}}
+ \})
+ "autocmd BufWritePre *.py LspDocumentFormatSync
+ autocmd FileType python call s:configure_lsp()
+endif
+
+if executable('bash-language-server')
+ au User lsp_setup call lsp#register_server({
+ \ 'name': 'bash-language-server',
+ \ 'cmd': {server_info->[&shell, &shellcmdflag, 'bash-language-server start']},
+ \ 'whitelist': ['sh'],
+ \ })
+ "autocmd BufWritePre *.sh LspDocumentFormatSync
+ autocmd FileType sh call s:configure_lsp()
+endif
diff --git a/vagrant/devstack/roles/ubuntu-focal/compute/tasks/basic_pkgs.yml b/vagrant/devstack/roles/ubuntu-focal/compute/tasks/basic_pkgs.yml
new file mode 100644
index 000000000..c9f3d523b
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/compute/tasks/basic_pkgs.yml
@@ -0,0 +1,6 @@
+---
+- name: install basic packages
+ become: yes
+ apt: name={{ item }} update_cache=yes
+ with_items:
+ - git
diff --git a/vagrant/devstack/roles/ubuntu-focal/compute/tasks/devstack.yml b/vagrant/devstack/roles/ubuntu-focal/compute/tasks/devstack.yml
new file mode 100644
index 000000000..ae0f3362b
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/compute/tasks/devstack.yml
@@ -0,0 +1,15 @@
+---
+- name: update git config
+ git_config:
+ scope: global
+ name: 'url.https://.insteadOf'
+ value: 'git://'
+
+- name: git clone devstack
+ git:
+ repo=https://opendev.org/openstack/devstack.git
+ dest={{ ansible_env.HOME }}/devstack
+
+- name: put local.conf
+ template: src=templates/local.conf.j2 dest={{ ansible_env.HOME }}/devstack/local.conf
+ mode=665
diff --git a/vagrant/devstack/roles/ubuntu-focal/compute/tasks/main.yml b/vagrant/devstack/roles/ubuntu-focal/compute/tasks/main.yml
new file mode 100644
index 000000000..7efaf8b22
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/compute/tasks/main.yml
@@ -0,0 +1,6 @@
+---
+- include: basic_pkgs.yml
+ tags: basic_pkgs
+
+- include: devstack.yml
+ tags: devstack
diff --git a/vagrant/devstack/roles/ubuntu-focal/compute/templates/local.conf.j2 b/vagrant/devstack/roles/ubuntu-focal/compute/templates/local.conf.j2
new file mode 100644
index 000000000..3e83cfd43
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/compute/templates/local.conf.j2
@@ -0,0 +1,22 @@
+[[local|localrc]]
+HOST_IP={{ ansible_host }}
+FIXED_RANGE={{ fixed_range }}
+FLOATING_RANGE={{ floating_range }}
+LOGFILE=/opt/stack/logs/stack.sh.log
+
+ADMIN_PASSWORD={{ admin_password }}
+DATABASE_PASSWORD={{ database_password }}
+RABBIT_PASSWORD={{ rabbit_password }}
+SERVICE_PASSWORD={{ service_password }}
+
+DATABASE_TYPE=mysql
+SERVICE_HOST={{ service_host }}
+MYSQL_HOST=$SERVICE_HOST
+RABBIT_HOST=$SERVICE_HOST
+GLANCE_HOSTPORT=$SERVICE_HOST:9292
+
+ENABLED_SERVICES=n-cpu,c-vol,placement-client
+NOVA_VNC_ENABLED=True
+NOVNCPROXY_URL="http://$SERVICE_HOST:6080/vnc_lite.html"
+VNCSERVER_LISTEN=$HOST_IP
+VNCSERVER_PROXYCLIENT_ADDRESS=$VNCSERVER_LISTEN
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/basic_pkgs.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/basic_pkgs.yml
new file mode 100644
index 000000000..519a34296
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/basic_pkgs.yml
@@ -0,0 +1,16 @@
+---
+- name: install basic packages
+ become: yes
+ apt: name={{ item }} update_cache=yes
+ with_items:
+ - python3
+ - python3-dev
+ - python3-pip
+ - bridge-utils
+ - git
+ - git-review
+
+- name: upgrade apt packages
+ become: yes
+ apt:
+ upgrade: safe
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/devstack.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/devstack.yml
new file mode 100644
index 000000000..9934aafc5
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/devstack.yml
@@ -0,0 +1,20 @@
+---
+- name: update git config
+ git_config:
+ scope: global
+ name: 'url.https://.insteadOf'
+ value: 'git://'
+
+- name: git clone devstack
+ git:
+ repo=https://opendev.org/openstack/devstack.git
+ dest={{ ansible_env.HOME }}/devstack
+
+- name: install os-testr
+ pip:
+ name: os-testr
+ state: latest
+
+- name: install tox
+ pip:
+ name: tox
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/extra_tools.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/extra_tools.yml
new file mode 100644
index 000000000..2e6886545
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/extra_tools.yml
@@ -0,0 +1,8 @@
+---
+- name: install extra packages
+ become: yes
+ apt: name={{ item }}
+ with_items:
+ - jq
+ - htop
+ - lnav
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/git_config.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/git_config.yml
new file mode 100644
index 000000000..ae50d2e21
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/git_config.yml
@@ -0,0 +1,4 @@
+---
+- name: copy .gitconfig on host to VM
+ template: src=templates/gitconfig.j2 dest={{ ansible_env.HOME }}/.gitconfig
+ mode=664
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/main.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/main.yml
new file mode 100644
index 000000000..d3830ad59
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/main.yml
@@ -0,0 +1,23 @@
+---
+# Without removing this package, failed to install while running scripts.
+- include: remove_useless_pkgs.yml
+
+- include: basic_pkgs.yml
+- include: set_path_env.yml
+- include: git_config.yml
+
+- include: python3_specific_vers.yml
+
+- include: vim_latest.yml
+ when: use_vim_latest == true
+
+- include: vim_extra_plugins.yml
+ when: use_vim_extra_plugins == true
+
+- include: devstack.yml
+
+- include: setup_tacker.yml
+ when: use_tacker == true
+
+- include: extra_tools.yml
+ when: use_extra_tools == true
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/python3_specific_vers.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/python3_specific_vers.yml
new file mode 100644
index 000000000..7c319a9ee
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/python3_specific_vers.yml
@@ -0,0 +1,9 @@
+---
+- name: install python3 other than default version
+ become: yes
+ apt: name={{ item }}
+ with_items:
+ - python3.8
+ - python3.8-dev
+ - python3.9
+ - python3.9-dev
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/remove_useless_pkgs.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/remove_useless_pkgs.yml
new file mode 100644
index 000000000..843e532c7
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/remove_useless_pkgs.yml
@@ -0,0 +1,11 @@
+---
+- name: remove useless python3-launchpadlib
+ become: yes
+ apt:
+ name: python3-launchpadlib
+ state: absent
+
+- name: cleanup with autoremove
+ become: yes
+ apt:
+ autoremove: yes
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/set_path_env.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/set_path_env.yml
new file mode 100644
index 000000000..892e7124f
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/set_path_env.yml
@@ -0,0 +1,5 @@
+---
+- name: set PATH for '.local/bin'
+ lineinfile:
+ line="export PATH=$HOME/.local/bin:$PATH:/sbin"
+ dest={{ ansible_env.HOME }}/.bashrc
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/setup_tacker.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/setup_tacker.yml
new file mode 100644
index 000000000..16d3f84c2
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/setup_tacker.yml
@@ -0,0 +1,65 @@
+---
+- name: git clone tacker
+ git:
+ repo=https://opendev.org/openstack/tacker.git
+ dest={{ ansible_env.HOME }}/tacker
+
+- name: copy local.conf
+ shell: cp {{ ansible_env.HOME }}/tacker/devstack/{{ item }} \
+ {{ ansible_env.HOME }}/devstack/{{ item }}
+ with_items:
+ - local.conf.example
+ - local.conf.kubernetes
+
+- name: update HOST_IP in devstack/local.conf.example
+ lineinfile:
+ path={{ ansible_env.HOME }}/devstack/{{ item }}
+ line='HOST_IP={{ ansible_host }}'
+ regexp='^HOST_IP=127\.0\.0\.1'
+ with_items:
+ - local.conf.example
+ - local.conf.kubernetes
+
+- name: update other params in devstack/local.conf.example
+ lineinfile:
+ path={{ ansible_env.HOME }}/devstack/local.conf.example
+ line={{ item.line }}
+ regexp={{ item.regexp }}
+ with_items:
+ - line: 'ADMIN_PASSWORD={{ admin_password }}'
+ regexp: '^ADMIN_PASSWORD=devstack'
+ - line: 'MYSQL_PASSWORD={{ database_password }}'
+ regexp: '^MYSQL_PASSWORD=devstack'
+ - line: 'RABBIT_PASSWORD={{ rabbit_password }}'
+ regexp: '^RABBIT_PASSWORD=devstack'
+ - line: 'SERVICE_PASSWORD={{ service_password }}'
+ regexp: '^SERVICE_PASSWORD=\$ADMIN_PASSWORD'
+ - line: 'SERVICE_TOKEN={{ service_token }}'
+ regexp: '^SERVICE_TOKEN=devstack'
+
+- name: update HOST_IP in devstack/local.conf.kubernetes
+ lineinfile:
+ path={{ ansible_env.HOME }}/devstack/local.conf.kubernetes
+ line='HOST_IP={{ service_host }}'
+ regexp='^HOST_IP=127\.0\.0\.1'
+
+- name: update other params in devstack/local.conf.kubernetes
+ lineinfile:
+ path={{ ansible_env.HOME }}/devstack/local.conf.kubernetes
+ line={{ item.line }}
+ regexp={{ item.regexp }}
+ with_items:
+ - line: 'ADMIN_PASSWORD={{ admin_password }}'
+ regexp: '^ADMIN_PASSWORD=devstack'
+ - line: 'MYSQL_PASSWORD={{ database_password }}'
+ regexp: '^MYSQL_PASSWORD=devstack'
+ - line: 'RABBIT_PASSWORD={{ rabbit_password }}'
+ regexp: '^RABBIT_PASSWORD=devstack'
+ - line: 'SERVICE_PASSWORD={{ service_password }}'
+ regexp: '^SERVICE_PASSWORD=\$ADMIN_PASSWORD'
+ - line: 'SERVICE_TOKEN={{ service_token }}'
+ regexp: '^SERVICE_TOKEN=devstack'
+
+- name: use local.conf.example as local.conf
+ shell: cp {{ ansible_env.HOME }}/devstack/local.conf.example \
+ {{ ansible_env.HOME }}/devstack/local.conf
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/vim_extra_plugins.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/vim_extra_plugins.yml
new file mode 100644
index 000000000..1567b2cef
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/vim_extra_plugins.yml
@@ -0,0 +1,29 @@
+---
+- name: create dir for plug.vim
+ file: path={{ ansible_env.HOME }}/.vim/autoload state=directory
+
+- name: download plug.vim
+ get_url: url=https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
+ dest={{ ansible_env.HOME }}/.vim/autoload/plug.vim
+
+- name: vimrc
+ template: src=templates/vimrc.j2 dest={{ ansible_env.HOME }}/.vimrc
+ mode=664
+
+- name: install exuberant-ctags
+ become: yes
+ apt: name=exuberant-ctags
+
+- name: install npm
+ become: yes
+ apt: name=npm
+
+- name: install bash-language-server
+ become: yes
+ npm:
+ name: bash-language-server
+ global: yes
+
+- name: install python-language-server
+ pip:
+ name: python-language-server[all]
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/tasks/vim_latest.yml b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/vim_latest.yml
new file mode 100644
index 000000000..e243fd35d
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/tasks/vim_latest.yml
@@ -0,0 +1,8 @@
+---
+- name: add apt repo ppa:jonathonf/vim
+ become: yes
+ apt_repository: repo='ppa:jonathonf/vim'
+
+- name: install vim
+ become: yes
+ apt: name=vim
diff --git a/vagrant/devstack/roles/ubuntu-focal/controller/templates/vimrc.j2 b/vagrant/devstack/roles/ubuntu-focal/controller/templates/vimrc.j2
new file mode 100644
index 000000000..222d8acd4
--- /dev/null
+++ b/vagrant/devstack/roles/ubuntu-focal/controller/templates/vimrc.j2
@@ -0,0 +1,159 @@
+" Specify a directory for plugins
+" - For Neovim: stdpath('data') . '/plugged'
+" - Avoid using standard Vim directory names like 'plugin'
+call plug#begin('~/.vim/plugged')
+
+" Make sure you use single quotes
+
+" Shorthand notation; fetches https://github.com/junegunn/vim-easy-align
+Plug 'junegunn/vim-easy-align'
+
+" Any valid git URL is allowed
+Plug 'https://github.com/junegunn/vim-github-dashboard.git'
+
+" Multiple Plug commands can be written in a single line using | separators
+Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets'
+
+" On-demand loading
+Plug 'preservim/nerdtree', { 'on': 'NERDTreeToggle' }
+Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
+
+" Using a non-master branch
+Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' }
+
+" Using a tagged release; wildcard allowed (requires git 1.9.2 or above)
+"Plug 'fatih/vim-go', { 'tag': '*' }
+
+" Plugin options
+"Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' }
+Plug 'nsf/gocode'
+
+" Plugin outside ~/.vim/plugged with post-update hook
+Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
+Plug 'junegunn/fzf.vim'
+let g:fzf_command_prefix = 'Fzf'
+
+" Unmanaged plugin (manually installed and updated)
+"Plug '~/my-prototype-plugin'
+
+Plug 'tpope/vim-sensible'
+Plug 'tpope/vim-surround'
+Plug 'tpope/vim-fugitive'
+Plug 'thinca/vim-quickrun'
+Plug 'ctrlpvim/ctrlp.vim'
+Plug 'flazz/vim-colorschemes'
+Plug 'thinca/vim-quickrun'
+
+Plug 'jpo/vim-railscasts-theme'
+Plug 'godlygeek/tabular'
+Plug 'plasticboy/vim-markdown'
+let g:vim_markdown_folding_disabled = 1
+
+Plug 'dense-analysis/ale'
+
+Plug 'vim-scripts/taglist.vim'
+let Tlist_Use_Right_Window = 1
+
+Plug 'prabirshrestha/async.vim'
+Plug 'prabirshrestha/vim-lsp'
+Plug 'prabirshrestha/asyncomplete.vim'
+Plug 'prabirshrestha/asyncomplete-lsp.vim'
+Plug 'natebosch/vim-lsc'
+Plug 'thomasfaingnaert/vim-lsp-snippets'
+Plug 'thomasfaingnaert/vim-lsp-ultisnips'
+let g:lsp_async_completion = 1
+
+Plug 'tyru/current-func-info.vim'
+Plug 'yasufum/vim-os-unittestr'
+
+" Initialize plugin system
+call plug#end()
+
+syntax on
+set number
+set relativenumber
+set shiftwidth=4
+set tabstop=4
+set expandtab
+set showcmd
+set showmatch
+set hlsearch
+set laststatus=2
+set encoding=utf-8
+set fileencoding=utf-8
+set termencoding=utf-8
+set autoindent
+set scrolloff=4
+set smartcase
+set textwidth=80
+set colorcolumn=+1
+
+set visualbell t_vb=
+set noerrorbells
+
+set path+=**
+set wildmenu
+
+colorscheme delek
+"colorscheme railscasts
+
+autocmd FileType python set textwidth=79
+autocmd FileType gitcommit set textwidth=72
+
+nnoremap ;
+nnoremap :NERDTreeToggle
+" enable line numbers
+let NERDTreeShowLineNumbers=1
+" make sure relative line number is used
+autocmd FileType nerdtree setlocal relativenumber
+
+""" Open vimrc from ':Conf' command.
+function! s:open_vimrc() abort
+ new ~/.vimrc
+endfunction
+command! Conf call s:open_vimrc()
+
+function! s:configure_lsp() abort
+ setlocal omnifunc=lsp#complete
+ nnoremap :LspDefinition
+ nnoremap :LspHover
+ "nnoremap
+ nnoremap d :LspDefinition
+ nnoremap r :LspReferences
+ nnoremap t :LspTypeDefinition
+ nnoremap s :LspDocumentSymbol
+ nnoremap S :LspWorkspaceSymbol
+ nnoremap f :LspDocumentFormat
+ vnoremap f :LspDocumentRangeFormat
+ nnoremap h :LspHover
+ nnoremap i :LspImplementation
+ nnoremap e :LspNextError
+ nnoremap E :LspPreviousError
+ nnoremap N :LspRename
+endfunction
+
+" Do ALE diagnostic
+let g:lsp_diagnostics_enabled = 0
+
+if executable('pyls')
+ autocmd User lsp_setup call lsp#register_server({
+ \ 'name': 'pyls',
+ \ 'cmd': { server_info -> ['pyls'] },
+ \ 'whitelist': ['python'],
+ \ 'workspace_config': {'pyls': {'plugins': {
+ \ 'pycodestyle': {'enabled': v:false},
+ \ 'jedi_definition': {'follow_imports': v:true, 'follow_builtin_imports': v:true},}}}
+ \})
+ "autocmd BufWritePre *.py LspDocumentFormatSync
+ autocmd FileType python call s:configure_lsp()
+endif
+
+if executable('bash-language-server')
+ au User lsp_setup call lsp#register_server({
+ \ 'name': 'bash-language-server',
+ \ 'cmd': {server_info->[&shell, &shellcmdflag, 'bash-language-server start']},
+ \ 'whitelist': ['sh'],
+ \ })
+ "autocmd BufWritePre *.sh LspDocumentFormatSync
+ autocmd FileType sh call s:configure_lsp()
+endif
diff --git a/vagrant/devstack/samples/machines-2nodes.yml b/vagrant/devstack/samples/machines-2nodes.yml
new file mode 100644
index 000000000..9ba596103
--- /dev/null
+++ b/vagrant/devstack/samples/machines-2nodes.yml
@@ -0,0 +1,35 @@
+global:
+ # (optional) Path of your SSH public key. Default is "~/.ssh/id_rsa.pub".
+ #ssh_pub_key: "~/.ssh/id_rsa.pub"
+
+machines:
+
+ - hostname: controller
+ provider: virtualbox
+ box: ubuntu/focal64
+ nof_cpus: 2
+ mem_size: 4
+ disk_size: 20
+ private_ips:
+ - 192.168.33.11
+ public_ips:
+ fwd_port_list:
+ - guest: 80
+ host: 10080
+ - guest: 6081
+ host: 6081
+
+ - hostname: compute
+ provider: virtualbox
+ box: ubuntu/focal64
+ nof_cpus: 4
+ mem_size: 8
+ disk_size: 50
+ private_ips:
+ - 192.168.34.11
+ public_ips:
+ fwd_port_list:
+ - guest: 80
+ host: 10081
+ - guest: 6081
+ host: 6081
diff --git a/vagrant/devstack/samples/machines.yml b/vagrant/devstack/samples/machines.yml
new file mode 100644
index 000000000..8f7cf3c1c
--- /dev/null
+++ b/vagrant/devstack/samples/machines.yml
@@ -0,0 +1,21 @@
+global:
+ # (optional) Path of your SSH public key. Default is "~/.ssh/id_rsa.pub".
+ #ssh_pub_key: "~/.ssh/id_rsa.pub"
+
+machines:
+
+ - hostname: controller
+ provider: virtualbox
+ # Supported boxes are `ubuntu/focal64`, `centos/stream8`.
+ box: ubuntu/focal64
+ nof_cpus: 4
+ mem_size: 8
+ disk_size: 50
+ private_ips:
+ - 192.168.33.11
+ public_ips:
+ fwd_port_list:
+ - guest: 80
+ host: 10080
+ - guest: 6081
+ host: 6081
diff --git a/vagrant/devstack/site.yaml b/vagrant/devstack/site.yaml
new file mode 100644
index 000000000..ce386bc60
--- /dev/null
+++ b/vagrant/devstack/site.yaml
@@ -0,0 +1,18 @@
+---
+- name: ubuntu-focal controller node
+ hosts: ubuntu-focal.controller
+ remote_user: stack
+ roles:
+ - ubuntu-focal/controller
+
+- name: ubuntu-focal compute nodes
+ hosts: ubuntu-focal.compute
+ remote_user: stack
+ roles:
+ - ubuntu-focal/compute
+
+- name: centos-stream8 controller node
+ hosts: centos-stream8.controller
+ remote_user: stack
+ roles:
+ - centos-stream8/controller