Change-Id: Ia8c6d2d286193cdad1c3d59037d6acf095385edb Signed-off-by: Dmitriy Rabotyagov <dmitriy.rabotyagov@cleura.com>
584 lines
22 KiB
ReStructuredText
584 lines
22 KiB
ReStructuredText
.. _quickstart-aio:
|
|
|
|
===============
|
|
Quickstart: AIO
|
|
===============
|
|
|
|
All-in-one (AIO) builds are a great way to perform an OpenStack-Ansible build
|
|
for:
|
|
|
|
* a development environment
|
|
* an overview of how all of the OpenStack services fit together
|
|
* a simple lab deployment
|
|
|
|
Although AIO builds aren't recommended for large production deployments,
|
|
they're great for smaller proof-of-concept deployments.
|
|
|
|
Absolute minimum server resources (currently used for gate checks):
|
|
|
|
* 8 vCPU's
|
|
* 50GB free disk space on the root partition
|
|
* 8GB RAM
|
|
|
|
Recommended server resources:
|
|
|
|
* CPU/motherboard that supports `hardware-assisted virtualization`_
|
|
* 8 CPU Cores
|
|
* 80GB free disk space on the root partition, or 60GB+ on a blank
|
|
secondary disk. Using a secondary disk requires the use of the
|
|
``bootstrap_host_data_disk_device`` parameter. Please see
|
|
:ref:`building-an-aio` for more details.
|
|
* 16GB RAM
|
|
|
|
It is `possible` to perform AIO builds within a virtual machine for
|
|
demonstration and evaluation, but your virtual machines will perform poorly
|
|
unless nested virtualization is available. For production workloads, multiple
|
|
nodes for specific roles are recommended.
|
|
|
|
.. _hardware-assisted virtualization: https://en.wikipedia.org/wiki/Hardware-assisted_virtualization
|
|
|
|
.. _building-an-aio:
|
|
|
|
Building an AIO
|
|
---------------
|
|
|
|
Overview
|
|
~~~~~~~~
|
|
|
|
There are three steps to running an AIO build, with an optional first step
|
|
should you need to customize your build:
|
|
|
|
* Prepare the host
|
|
* Bootstrap Ansible and the required roles
|
|
* Bootstrap the AIO configuration
|
|
* Run playbooks
|
|
|
|
Prepare the host
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
When building an AIO on a new server, it is recommended that all
|
|
system packages are upgraded and then reboot into the new kernel:
|
|
|
|
.. note:: Execute the following commands and scripts as the root user.
|
|
|
|
.. code-block:: shell-session
|
|
|
|
## Ubuntu / Debian
|
|
# apt-get update
|
|
# apt-get dist-upgrade
|
|
# reboot
|
|
|
|
.. code-block:: shell-session
|
|
|
|
## CentOS Stream / Rocky Linux
|
|
# dnf upgrade
|
|
# dnf install git-core
|
|
# systemctl stop firewalld
|
|
# systemctl mask firewalld
|
|
# reboot
|
|
|
|
.. note::
|
|
|
|
Before rebooting, in ``/etc/sysconfig/selinux``, make sure that
|
|
``SELINUX=enforcing`` is changed to ``SELINUX=disabled``.
|
|
SELinux enabled is not currently supported in OpenStack-Ansible
|
|
for CentOS Stream or Rocky Linux due to a lack of maintainers for the feature.
|
|
|
|
.. note::
|
|
|
|
If you are installing with limited connectivity, please review :ref:`Installing
|
|
with limited connectivity <limited-connectivity>` before proceeding.
|
|
|
|
Bootstrap Ansible and the required roles
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Start by cloning the OpenStack-Ansible repository and changing into the
|
|
repository root directory:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# git clone https://opendev.org/openstack/openstack-ansible \
|
|
/opt/openstack-ansible
|
|
# cd /opt/openstack-ansible
|
|
|
|
Next switch the applicable branch/tag to be deployed from. Note that
|
|
deploying from the head of a branch may result in an unstable build due to
|
|
changes in flight and upstream OpenStack changes. For a test (for example,
|
|
not a development) build it is usually best to checkout the latest tagged
|
|
version.
|
|
|
|
.. parsed-literal::
|
|
|
|
# # List all existing tags.
|
|
# git tag -l
|
|
|
|
# # Checkout the stable branch and find just the latest tag
|
|
# git checkout |current_release_git_branch_name|
|
|
# git describe --abbrev=0 --tags
|
|
|
|
# # Checkout the latest tag from either method of retrieving the tag.
|
|
# git checkout |latest_tag|
|
|
|
|
.. note::
|
|
The |current_release_formal_name| release is only compatible with
|
|
Debian 12 (bookworm), Debian 13 (trixie), Ubuntu 24.04 (Noble Numbat),
|
|
CentOS 10 Stream and derivatives of RHEL 10 such as Rocky Linux.
|
|
|
|
The next step is to bootstrap Ansible and the Ansible roles for the
|
|
development environment.
|
|
|
|
Run the following to bootstrap Ansible and the required roles:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# scripts/bootstrap-ansible.sh
|
|
|
|
.. note::
|
|
You might encounter an error while running the Ansible bootstrap script
|
|
when building some of the Python extensions (like pycrypto) which says:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
configure: error: cannot run C compiled programs.
|
|
|
|
The reason of this failure might be resulting from a noexec mount flag
|
|
used for the filesystem associated with /tmp which you can check by
|
|
running the following command:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# mount | grep $(df /tmp | tail -n +2 | awk '{print $1}') | grep noexec
|
|
|
|
If this is the case you can specify an alternate path which does not
|
|
have this mount option set:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# TMPDIR=/var/tmp scripts/bootstrap-ansible.sh
|
|
|
|
Bootstrap the AIO configuration
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
In order for all the services to run, the host must be prepared with the
|
|
appropriate disks partitioning, packages, network configuration and
|
|
configurations for the OpenStack Deployment.
|
|
|
|
By default the AIO bootstrap scripts deploy a base set of OpenStack services
|
|
with sensible defaults for the purpose of a gate check, development or testing
|
|
system.
|
|
|
|
Review the `bootstrap-host role defaults`_ file to see various configuration
|
|
options. Deployers have the option to change how the host is bootstrapped.
|
|
This is useful when you wish the AIO to make use of a secondary data disk,
|
|
or when using this role to bootstrap a multi-node development environment.
|
|
|
|
.. _bootstrap-host role defaults: https://opendev.org/openstack/openstack-ansible/src/tests/roles/bootstrap-host/defaults/main.yml
|
|
|
|
The bootstrap script is pre-set to pass the environment variable
|
|
``BOOTSTRAP_OPTS`` as an additional option to the bootstrap process. For
|
|
example, if you wish to set the bootstrap to re-partition a specific
|
|
secondary storage device (``/dev/sdb``), which will erase all of the data
|
|
on the device, then execute:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# export BOOTSTRAP_OPTS="bootstrap_host_data_disk_device=sdb"
|
|
|
|
Additional options may be implemented by simply concatenating them with
|
|
a space between each set of options, for example:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# export BOOTSTRAP_OPTS="bootstrap_host_data_disk_device=sdb"
|
|
# export BOOTSTRAP_OPTS="${BOOTSTRAP_OPTS} bootstrap_host_data_disk_fs_type=xfs"
|
|
|
|
If you are installing with limited connectivity, or you don't have default
|
|
route set, you will need to define interface for outgoing connections manually
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# export BOOTSTRAP_OPTS="bootstrap_host_public_interface=eth1"
|
|
|
|
For the default AIO scenario, the AIO configuration preparation is completed by
|
|
executing:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# scripts/bootstrap-aio.sh
|
|
|
|
To add OpenStack Services over and above the bootstrap-aio default services
|
|
for the applicable scenario, copy the ``conf.d`` files with the ``.aio`` file
|
|
extension into ``/etc/openstack_deploy`` and rename then to ``.yml`` files.
|
|
For example, in order to enable the OpenStack Telemetry services, execute the
|
|
following:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# cd /opt/openstack-ansible/
|
|
# cp etc/openstack_deploy/conf.d/{aodh,gnocchi,ceilometer}.yml.aio /etc/openstack_deploy/conf.d/
|
|
# for f in $(ls -1 /etc/openstack_deploy/conf.d/*.aio); do mv -v ${f} ${f%.*}; done
|
|
|
|
It is possible to also do this (and change other defaults) during the bootstrap
|
|
script initial execution by changing the SCENARIO environment variable before
|
|
running the script. The key word 'aio' will ensure that a basic set of
|
|
OpenStack services (cinder, glance, horizon, neutron, nova) will be deployed.
|
|
The key words 'lxc' can be used to set the container back-end,
|
|
while the key word 'metal' will deploy all services without containers. In
|
|
order to implement any other services, add the name of the conf.d file name
|
|
without the `.yml.aio` extension into the SCENARIO environment variable. Each
|
|
key word should be delimited by an underscore. For example, the following will
|
|
implement an AIO with barbican, cinder, glance, horizon, neutron, and nova. It
|
|
will set the cinder storage back-end to ceph and will make use of LXC as the
|
|
container back-end.
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# export SCENARIO='aio_lxc_barbican_ceph_ovs'
|
|
# scripts/bootstrap-aio.sh
|
|
|
|
To add any global overrides, over and above the defaults for the applicable
|
|
scenario, edit ``/etc/openstack_deploy/user_variables.yml``. In order to
|
|
understand the various ways that you can override the default behaviour
|
|
set out in the roles, playbook and group variables, see :ref:`user-overrides`.
|
|
|
|
See the :deploy_guide:`Deployment Guide <index.html>` for a more detailed break
|
|
down of how to implement your own configuration rather than to use the AIO
|
|
bootstrap.
|
|
|
|
Run playbooks
|
|
~~~~~~~~~~~~~
|
|
|
|
Finally, run the playbooks by executing:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# openstack-ansible openstack.osa.setup_hosts
|
|
# openstack-ansible openstack.osa.setup_infrastructure
|
|
# openstack-ansible openstack.osa.setup_openstack
|
|
|
|
The installation process will take a while to complete, but here are some
|
|
general estimates:
|
|
|
|
* Bare metal systems with SSD storage: ~ 30-50 minutes
|
|
* Virtual machines with SSD storage: ~ 45-60 minutes
|
|
* Systems with traditional hard disks: ~ 90-120 minutes
|
|
|
|
Once the playbooks have fully executed, it is possible to experiment with
|
|
various settings changes in ``/etc/openstack_deploy/user_variables.yml`` and
|
|
only run individual playbooks. For example, to run the playbook for the
|
|
Keystone service, execute:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# cd /opt/openstack-ansible/playbooks
|
|
# openstack-ansible os-keystone-install.yml
|
|
|
|
Interacting with an AIO
|
|
-----------------------
|
|
|
|
Once an AIO has been deployed, you most likely want to interact with it. You
|
|
can do this via the web interface or one of the many clients or libraries that
|
|
exist for OpenStack.
|
|
|
|
Using a GUI
|
|
~~~~~~~~~~~
|
|
|
|
The Horizon web interface provides a graphical interface for interacting with
|
|
the AIO deployment. By default, the Horizon API is available on port 443 of the
|
|
host (or port 80, if SSL certificate configuration was disabled). As such, to
|
|
interact with Horizon, simply browse to the IP of the host.
|
|
|
|
.. note::
|
|
|
|
If the AIO was deployed in a cloud VM, you may need to configure security
|
|
groups or firewall rules to allow access to the HTTP(S) ports. For example,
|
|
if the AIO was deployed in an OpenStack VM, you can create and apply a
|
|
suitable security group for interacting with Horizon like so:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
$ openstack security group create http \
|
|
--description 'Allow HTTP and HTTPS access'
|
|
$ openstack security group rule create http \
|
|
--protocol tcp --dst-port 80 --remote-ip 0.0.0.0/0
|
|
$ openstack security group rule create http \
|
|
--protocol tcp --dst-port 443 --remote-ip 0.0.0.0/0
|
|
$ openstack server add security group $SERVER http
|
|
|
|
A list of service ports can be found in the `OpenStack Install Guide`__.
|
|
|
|
.. __: https://docs.openstack.org/install-guide/firewalls-default-ports.html
|
|
|
|
This will present a login page. By default, OpenStack-Ansible create a user
|
|
called ``admin``. The password will be the value of the
|
|
``keystone_auth_admin_password`` variable. If you did not configure this
|
|
variable, OpenStack-Ansible auto-generates one. You can view the configured
|
|
password in the ``/etc/openstack_deploy/user_secrets.yml`` file.
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# grep admin_pass /etc/openstack_deploy/user_secrets.yml
|
|
heat_stack_domain_admin_password: <redacted>
|
|
keystone_auth_admin_password: <redacted>
|
|
radosgw_admin_password: <redacted>
|
|
|
|
Using this username and password combination, log in to Horizon.
|
|
|
|
Using a client or library
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
There are a variety of clients and libraries available for interacting with an
|
|
OpenStack deployment, including as `openstackclient`__, `openstacksdk`__, or
|
|
`gophercloud`__. These are typically configured using either environment
|
|
variables sourced from an ``openrc`` file or the newer ``clouds.yaml`` file.
|
|
|
|
.. __: https://opendev.org/openstack/python-openstackclient
|
|
.. __: https://opendev.org/openstack/openstacksdk
|
|
.. __: https://github.com/gophercloud/gophercloud
|
|
|
|
OpenStack-Ansible provides the ``openstack_openrc`` role for creating these
|
|
configuration files as well as a number of utilities such as *openstackclient*.
|
|
If the AIO deployment using the ``lxc`` scenario (the default), these will be
|
|
availably in the utility container.
|
|
|
|
.. code-block:: shell-session
|
|
|
|
$ lxc-attach -n `lxc-ls -1 | grep utility`
|
|
|
|
# ls /root/openrc
|
|
/root/openrc
|
|
|
|
# ls /root/.config/openstack/clouds.yaml
|
|
/root/.config/openstack/clouds.yaml
|
|
|
|
# export OS_CLOUD=default
|
|
# openstack project list -c Name -f value
|
|
service
|
|
admin
|
|
|
|
Alternatively, if the AIO was deployed using the ``metal`` scenario, these
|
|
files will be available on the host itself.
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# ls /root/openrc
|
|
/root/openrc
|
|
|
|
# ls /root/.config/openstack/clouds.yaml
|
|
/root/.config/openstack/clouds.yaml
|
|
|
|
If you wish to access the AIO deployment from another host - perhaps your local
|
|
workstation - you will need either an ``openrc`` file or ``clouds.yaml`` file.
|
|
You can download an ``openrc`` file from Horizon: simply click the User
|
|
dropdown in the top-right corner and select ``OpenStack RC File``.
|
|
|
|
.. important::
|
|
|
|
You may be tempted to copy the ``openrc`` or ``clouds.yaml`` files created
|
|
by the ``openstack_openrc`` role. However, these files use the ``internal``
|
|
`interface`__ by default. This interface use the management network
|
|
(``172.29.236.0/22``) , which is not routable from outside the host. If you
|
|
wish to use these files, you will need to change the interface to
|
|
``public``.
|
|
|
|
.. __: https://docs.openstack.org/keystone/latest/contributor/service-catalog.html#endpoints
|
|
|
|
.. note::
|
|
|
|
If the AIO was deployed in a cloud VM, you may need to configure security
|
|
groups or firewall rules to allow access to the various sevice ports. For
|
|
example, if the AIO was deployed in an OpenStack VM, you can create and
|
|
apply a suitable security group for interacting the core services like so:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
$ openstack security group create openstack-apis \
|
|
--description 'Allow access to various OpenStack services'
|
|
$ for port in 8774 8776 9292 9696 5000 8780; do
|
|
openstack security group rule create openstack-apis \
|
|
--protocol tcp --dst-port ${port}:${port} --remote-ip 0.0.0.0/0
|
|
done
|
|
$ openstack server add security group $SERVER openstack-apis
|
|
|
|
A list of service ports can be found in the `OpenStack Install Guide`__.
|
|
|
|
.. __: https://docs.openstack.org/install-guide/firewalls-default-ports.html
|
|
|
|
.. note::
|
|
|
|
If you have enabled SSL certificate configuration (default), all services
|
|
will use self-signed certificates. While the host is configured to trust
|
|
these certificates, this is not the case for other hosts. This will result
|
|
in HTTPS errors when attempting to interact with the cloud. To resolve this
|
|
issue, you will need to manually configure certificates on other hosts or
|
|
ignore SSL issues. To use the self-signed certificate, first copy it to the
|
|
other hosts. The name and location of the generated certificate are
|
|
configured by the ``pki_authorities`` and ``pki_trust_store_location``
|
|
variables respectively, which are used by the ``pki`` role provided by
|
|
`ansible-role-pki`__. On an Ubuntu 24.04 host, these will default to
|
|
``ExampleCorpRoot`` and ``/usr/local/share/ca-certificates``, respectively.
|
|
For example:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
$ scp aio:/usr/local/share/ca-certificates/ExampleCorpRoot.crt ~/.config/openstack/aio.crt
|
|
|
|
.. __: https://opendev.org/openstack/ansible-role-pki
|
|
|
|
Once this is done, configure the ``cacert`` value in the the definition for
|
|
your cloud in ``clouds.yaml``. For example:
|
|
|
|
.. code-block:: yaml
|
|
|
|
clouds:
|
|
aio:
|
|
# ...
|
|
cacert: /home/<username>/.config/openstack/aio.crt
|
|
|
|
Alternatively, you can simply ignore SSL issues by setting ``verify: false``
|
|
in the definition for your cloud in ``clouds.yaml``. This will disable SSL
|
|
verification entirely for this cloud. For example:
|
|
|
|
.. code-block:: yaml
|
|
|
|
clouds:
|
|
aio:
|
|
# ...
|
|
verify: false
|
|
|
|
Finally, you can also opt to disable SSL certificate configuration during
|
|
initial deployment or opt to use an external certificate authority for
|
|
signing, such as Let's Encrypt. Both topics are outside the scope of this
|
|
document.
|
|
|
|
More information about SSL certificate configuration can be found in the
|
|
:ref:`securing-services-with-ssl-certificates`.
|
|
|
|
Once one of these files have been created, you can use it to interact with your
|
|
deployment using most standard clients and libraries. For example, to list
|
|
available projects using *openstackclient*:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
$ export OS_CLOUD=aio
|
|
$ openstack project list -c Name -f value
|
|
service
|
|
admin
|
|
|
|
Rebooting an AIO
|
|
----------------
|
|
|
|
As the AIO includes all three cluster members of MariaDB/Galera, the cluster
|
|
has to be re-initialized after the host is rebooted.
|
|
|
|
This is done by executing the following:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# cd /opt/openstack-ansible/playbooks
|
|
# openstack-ansible -e galera_ignore_cluster_state=true galera-install.yml
|
|
|
|
If this fails to get the database cluster back into a running state, then
|
|
please make use of the :ref:`galera-cluster-recovery`
|
|
section in the :ref:`operations-guide`.
|
|
|
|
Rebuilding an AIO
|
|
-----------------
|
|
|
|
Sometimes it may be useful to destroy all the containers and rebuild the AIO.
|
|
While it is preferred that the AIO is entirely destroyed and rebuilt, this
|
|
isn't always practical. As such the following may be executed instead:
|
|
|
|
.. code-block:: shell-session
|
|
|
|
# # Move to the playbooks directory.
|
|
# cd /opt/openstack-ansible/playbooks
|
|
|
|
# # Destroy all of the running containers.
|
|
# openstack-ansible lxc-containers-destroy.yml
|
|
|
|
# # On the host stop all of the services that run locally and not
|
|
# # within a container.
|
|
# for i in \
|
|
$(ls /etc/init \
|
|
| grep -e "nova\|swift\|neutron\|cinder" \
|
|
| awk -F'.' '{print $1}'); do \
|
|
service $i stop; \
|
|
done
|
|
|
|
# # Uninstall the core services that were installed.
|
|
# for i in $(pip freeze | grep -e "nova\|neutron\|keystone\|swift\|cinder"); do \
|
|
pip uninstall -y $i; done
|
|
|
|
# # Remove crusty directories.
|
|
# rm -rf /openstack /etc/{neutron,nova,swift,cinder} \
|
|
/var/log/{neutron,nova,swift,cinder}
|
|
|
|
# # Remove the pip configuration files on the host
|
|
# rm -rf /root/.pip
|
|
|
|
# # Remove the apt package manager proxy
|
|
# rm /etc/apt/apt.conf.d/00apt-cacher-proxy
|
|
|
|
Should an existing AIO environment need to be reinstalled, the most efficient
|
|
method is to destroy the host operating system and start over. For this reason,
|
|
AIOs are best run inside of some form of virtual machine or cloud guest.
|
|
|
|
Reference Diagram for an AIO Build
|
|
----------------------------------
|
|
|
|
Here is a basic diagram that attempts to illustrate what the resulting AIO
|
|
deployment looks like.
|
|
|
|
This diagram is not to scale and is not even 100% accurate, this diagram was
|
|
built for informational purposes only and should **ONLY** be used as such.
|
|
|
|
.. code-block:: text
|
|
|
|
------->[ ETH0 == Public Network ]
|
|
|
|
|
V [ * ] Socket Connections
|
|
[ HOST MACHINE ] [ <>v^ ] Network Connections
|
|
* ^ *
|
|
| | |-------------------------------------------------------
|
|
| | |
|
|
| |---------------->[ HAProxy ] |
|
|
| ^ |
|
|
| | |
|
|
| V |
|
|
| (BR-Interfaces)<------ |
|
|
| ^ * | |
|
|
*-[ LXC ]*--*----------------------|-----|------|----| |
|
|
| | | | | | | |
|
|
| | | | | | | |
|
|
| | | | | | | |
|
|
| | | | V * | |
|
|
| * | | [ Galera x3 ] |
|
|
| [ Memcached ]<------------| | | |
|
|
*-------*[ Rsyslog ]<--------------|--| | * |
|
|
| [ Repos Server x3 ]<------| ---|-->[ RabbitMQ x3 ] |
|
|
| [ Horizon x2 ]<-----------| | | |
|
|
| [ Nova api ec2 ]<---------|--| | |
|
|
| [ Nova api os ]<----------|->| | |
|
|
| [ Nova console ]<---------| | | |
|
|
| [ Nova Cert ]<------------|->| | |
|
|
| [ Cinder api ]<-----------|->| | |
|
|
| [ Glance api ]<-----------|->| | |
|
|
| [ Heat apis ]<------------|->| | [ Loop back devices ]*-*
|
|
| [ Heat engine ]<----------|->| | \ \ |
|
|
| ------>[ Nova api metadata ] | | | { LVM } { XFS x3 } |
|
|
| | [ Nova conductor ]<-------| | | * * |
|
|
| |----->[ Nova scheduler ]--------|->| | | | |
|
|
| | [ Keystone x3 ]<----------|->| | | | |
|
|
| | |--->[ Neutron agents ]*-------|--|---------------------------*
|
|
| | | [ Neutron server ]<-------|->| | | |
|
|
| | | |->[ Swift proxy ]<----------- | | | |
|
|
*-|-|-|-*[ Cinder volume ]*----------------------* | |
|
|
| | | | | | |
|
|
| | | ----------------------------------------- | |
|
|
| | ----------------------------------------- | | |
|
|
| | -------------------------| | | | |
|
|
| | | | | | |
|
|
| | V | | * |
|
|
---->[ Compute ]*[ Neutron OpenvSwitch ]<---| |->[ Swift storage ]-
|