Step #2 - Retiring Nova-docker : Remove Project Content

Depends-On: I7adcc29cac151ec55f6cc322a880189e0e827db1
Change-Id: I0f46c700c8c6a6495ebb64e9976218bc2fb83b65
This commit is contained in:
Davanum Srinivas 2017-02-07 07:56:55 -05:00 committed by Davanum Srinivas (dims)
parent 034a4842fc
commit 64426d814b
57 changed files with 10 additions and 5449 deletions

View File

@ -1,7 +0,0 @@
[run]
branch = True
source = novadocker
omit = novadocker/tests/*,novadocker/openstack/*
[report]
ignore_errors = True

53
.gitignore vendored
View File

@ -1,53 +0,0 @@
*.py[cod]
# C extensions
*.so
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
./lib
lib64
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
nosetests.xml
.testrepository
subunit.log
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Complexity
output/*.html
output/*/index.html
# Sphinx
doc/build
# pbr generates these
AUTHORS
ChangeLog
# Editors
*~
*.swp
*.swo

View File

@ -1,4 +0,0 @@
[gerrit]
host=review.openstack.org
port=29418
project=openstack/nova-docker.git

View File

@ -1,3 +0,0 @@
# Format is:
# <preferred e-mail> <other e-mail 1>
# <preferred e-mail> <other e-mail 2>

View File

@ -1,7 +0,0 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -1,21 +0,0 @@
=============
Contributing
=============
If you would like to contribute to the development of OpenStack,
you must follow the steps in the "If you're a developer, start here"
section of this page:
http://wiki.openstack.org/HowToContribute
Once those steps have been completed, changes to OpenStack
should be submitted for review via the Gerrit tool, following
the workflow documented at:
http://wiki.openstack.org/GerritWorkflow
Pull requests submitted through GitHub will be ignored.
Bugs should be filed on Launchpad, not GitHub:
https://bugs.launchpad.net/nova-docker

View File

@ -1,4 +0,0 @@
nova-docker Style Commandments
===============================================
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/

175
LICENSE
View File

@ -1,175 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

View File

@ -1,140 +1,13 @@
===============================
nova-docker
===============================
This project is no longer maintained.
Docker driver for OpenStack Nova.
The contents of this repository are still available in the Git
source code management system. To see the contents of this
repository before it reached its end of life, please check out the
previous commit with "git checkout HEAD^1".
Free software: Apache license
For an alternative project, please see OpenStack Zun at
http://git.openstack.org/cgit/openstack/zun/tree/README.rst
----------------------------
Installation & Configuration
----------------------------
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1. Install the python modules.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For example::
$ python setup.py install
Note: There are better and cleaner ways of managing Python modules, such as
using distribution packages or 'pip'. The setup.py file and Debian's stdeb,
for instance, may be used to create Debian/Ubuntu packages.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2. Enable the driver in Nova's configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In nova.conf::
compute_driver=novadocker.virt.docker.DockerDriver
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3. Optionally tune site-specific settings.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In nova.conf::
[docker]
# Commented out. Uncomment these if you'd like to customize:
## vif_driver=novadocker.virt.docker.vifs.DockerGenericVIFDriver
## snapshots_directory=/var/tmp/my-snapshot-tempdir
--------------------------
Uploading Images to Glance
--------------------------
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1. Enable the driver in Glance's configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In glance-api.conf::
container_formats=ami,ari,aki,bare,ovf,ova,docker
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2. Save docker images to Glance
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Images may now be saved directly to Glance::
$ docker pull busybox
$ docker save busybox | openstack image create busybox --public --container-format docker --disk-format raw
**Note:** At present, only administrators should be allowed to manage images.
With devstack you can make yourself administrator by sourcing openrc as::
source openrc admin
Once done you can go back to a user::
source openrc demo
The name of the image in Glance should be explicitly set to the same name
as the image as it is known to Docker. In the example above, an image has
been tagged in Docker as 'busybox'. Matching this is the '--name busybox'
argument to *glance image-create*. If these names do not align, the image
will not be bootable.
**Note:** There should be a long lived process running in the docker image,
otherwise the instance will not be able to spawn successfully. This can be
done by using CMD or ENTRYPOINT in DockerFile:
https://docs.docker.com/reference/builder/
or specifing the command through glance image property 'os_command_line' for
test::
glance image-update --property os_command_line='/usr/sbin/sshd -D' $IMAGE_ID
^^^^^^^^^^^^^^^^^^^^^
3. Generate a keypair
^^^^^^^^^^^^^^^^^^^^^
You can optionally create a keypair to use in your docker images::
nova keypair-add mykey > mykey.pem
^^^^^^^^^^^^^^^^^^^^^
4. Start a container
^^^^^^^^^^^^^^^^^^^^^
Start a new container. This uses the key created above::
nova boot --flavor m1.small --image busybox --key-name mykey test1
^^^^^^^^^^^^^^^^^^^^^
5. ssh into container
^^^^^^^^^^^^^^^^^^^^^
You can check the IP address of the container by using::
nova list
And then ssh into it::
ssh -i ../devstack/mykey.pem cirros@<IP ADDRESS>
-----
Notes
-----
* Earlier releases of this driver required the deployment of a private docker
registry. This is no longer required. Images are now saved and loaded from
Glance.
* Images loaded from Glance may do bad things. Only allow administrators to
add images. Users may create snapshots of their containers, generating images
in Glance -- these images are managed and thus safe.
----------
Contact Us
----------
Join us in #nova-docker on Freenode IRC
--------
Features
--------
* TODO
For any further questions, please email
openstack-dev@lists.openstack.org or join #openstack-dev on
Freenode.

View File

@ -1 +0,0 @@
[python: **.py]

View File

@ -1,16 +0,0 @@
The contrib/devstack/ directory contains the files necessary to integrate Docker Nova driver with devstack.
To install::
$ git clone https://git.openstack.org/openstack/nova-docker /opt/stack/nova-docker
$ git clone https://git.openstack.org/openstack-dev/devstack /opt/stack/devstack
# Note : only needed until we can make use of configure_nova_hypervisor_rootwrap
$ git clone https://git.openstack.org/openstack/nova /opt/stack/nova
$ cd /opt/stack/nova-docker
$ ./contrib/devstack/prepare_devstack.sh
Run devstack as normal::
$ ./stack.sh

View File

@ -1,32 +0,0 @@
#!/bin/bash
#
# 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.
# This script is executed inside gate_hook.sh
INSTALLDIR=${INSTALLDIR:-/opt/stack}
source $INSTALLDIR/devstack/functions-common
LOGDIR=/opt/stack/logs
if is_ubuntu; then
# Find and collect docker daemon logs
sudo find /var/log/ -name "docker*" -print -exec sudo cp {} $LOGDIR \;
elif is_fedora; then
# fetch the docker logs from the journal
sudo journalctl _SYSTEMD_UNIT=docker.service | sudo tee -a $LOGDIR/docker.service.log > /dev/null
sudo journalctl _SYSTEMD_UNIT=docker.socket | sudo tee -a $LOGDIR/docker.socket.log > /dev/null
fi
# Copy logs from the containers
sudo mkdir -p $LOGDIR/containers/
sudo find /var/lib/docker/containers/ -name "*.log" -print -exec sudo cp {} $LOGDIR/containers/ \;

View File

@ -1,43 +0,0 @@
#!/bin/bash
set -xe
SCRIPTDIR=$(readlink -f $(dirname $0))
# TODO : This should be removed once PATH contains sbin
# https://review.openstack.org/#/c/91655/
export PATH=$PATH:/usr/local/sbin:/usr/sbin
sudo useradd -U -s /bin/bash -d /opt/stack/new -m stack || true
sudo useradd -U -s /bin/bash -m tempest || true
export INSTALLDIR=$BASE/new
bash -xe $SCRIPTDIR/prepare_devstack.sh
export DEVSTACK_GATE_VIRT_DRIVER=docker
export KEEP_LOCALRC=1
export DEVSTACK_GATE_TEMPEST_REGEX='^(?!.*?(boto|volume|resize|suspend|rescue|cinder|migrate|object_storage)).*'
export DEVSTACK_GATE_TEMPEST=1
export DEVSTACK_GATE_TEMPEST_FULL=0
export DEVSTACK_GATE_TROVE=0
source $INSTALLDIR/devstack-gate/functions.sh
source $INSTALLDIR/devstack/functions-common
if is_ubuntu; then
apt_get update
install_package --force-yes linux-image-extra-`uname -r`
fi
trap exit_trap EXIT
function exit_trap {
local r=$?
if [[ "$r" -eq "0" ]]; then
echo "All tests run successfully"
else
echo "ERROR! some tests failed, please see detailed output"
fi
echo "Collecting docker-specific logs"
bash -x $SCRIPTDIR/copy_logs_hook.sh
}
$INSTALLDIR/devstack-gate/devstack-vm-gate.sh

View File

@ -1,129 +0,0 @@
# lib/nova_plugins/hypervisor-docker
# Configure the Docker hypervisor
# Enable with:
#
# VIRT_DRIVER=docker
# Dependencies:
#
# - ``functions`` file
# - ``nova`` and ``glance`` configurations
# install_nova_hypervisor - install any external requirements
# configure_nova_hypervisor - make configuration changes, including those to other services
# start_nova_hypervisor - start any external services
# stop_nova_hypervisor - stop any external services
# cleanup_nova_hypervisor - remove transient data and cache
# Save trace setting
MY_XTRACE=$(set +o | grep xtrace)
set -o xtrace
# Defaults
# --------
# Set up default repos
NOVA_DOCKER_REPO=${NOVA_DOCKER_REPO:-${GIT_BASE}/openstack/nova-docker.git}
NOVA_DOCKER_BRANCH=${NOVA_DOCKER_BRANCH:-master}
# Set up default directories
DOCKER_DIR=$DEST/nova-docker
DOCKER_UNIX_SOCKET=/var/run/docker.sock
DOCKER_PID_FILE=/var/run/docker.pid
DOCKER_REGISTRY_PORT=${DOCKER_REGISTRY_PORT:-5042}
DOCKER_IMAGE_NAME=${DOCKER_IMAGE_NAME:-cirros}
DOCKER_REGISTRY_IMAGE=${DOCKER_REGISTRY_IMAGE:-registry}
DOCKER_REGISTRY_IMAGE_NAME=registry
DOCKER_APT_REPO=${DOCKER_APT_REPO:-https://apt.dockerproject.org/repo}
# Entry Points
# ------------
# clean_nova_hypervisor - Clean up an installation
function cleanup_nova_hypervisor {
stop_service docker
# Clean out work area
sudo rm -rf /var/lib/docker
# remove docker bits from nova
rm $NOVA_DIR/nova/virt/docker
rm $NOVA_DIR/etc/nova/rootwrap.d/docker.filters
}
# configure_nova_hypervisor - Set config files, create data dirs, etc
function configure_nova_hypervisor {
iniset $NOVA_CONF DEFAULT compute_driver novadocker.virt.docker.driver.DockerDriver
iniset $GLANCE_API_CONF DEFAULT container_formats ami,ari,aki,bare,ovf,docker
}
# is_docker_running - Return 0 (true) if Docker is running, otherwise 1
function is_docker_running {
local docker_pid
if [ -f "$DOCKER_PID_FILE" ]; then
docker_pid=$(cat "$DOCKER_PID_FILE")
fi
if [[ -z "$docker_pid" ]] || ! ps -p "$docker_pid" | grep [d]ocker; then
return 1
fi
return 0
}
# install_nova_hypervisor() - Install external components
function install_nova_hypervisor {
setup_develop $DOCKER_DIR
# TODO : move into configure_nova_hypervisor_rootwrap if
# https://review.openstack.org/#/c/84839/ is merged
}
# start_nova_hypervisor - Start any required external services
function start_nova_hypervisor {
# Make sure Docker is installed
if ! ( is_package_installed docker || is_package_installed docker-io || is_package_installed docker-engine ) ; then
die $LINENO "Docker is not installed. Please run tools/docker/install_docker.sh"
fi
if ! (is_docker_running); then
die $LINENO "Docker not running"
fi
# Gather some information
docker version
docker -D info
# push the rootwrap
sudo cp $DOCKER_DIR/etc/nova/rootwrap.d/docker.filters /etc/nova/rootwrap.d/docker.filters
echo "Checking default image for docker..."
if ! (glance image-show "$DEFAULT_IMAGE_NAME"); then
echo "Pulling $DOCKER_IMAGE_NAME..."
# Dance around the image that got renamed
docker pull ewindisch/$DOCKER_IMAGE_NAME
docker tag ewindisch/$DOCKER_IMAGE_NAME:latest $DOCKER_IMAGE_NAME
echo "Saving $DOCKER_IMAGE_NAME to glance..."
TOKEN=$(openstack token issue -c id -f value)
docker save $DOCKER_IMAGE_NAME | openstack --os-token $TOKEN --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT image create $DEFAULT_IMAGE_NAME --public --container-format docker --disk-format raw
fi
}
# stop_nova_hypervisor - Stop any external services
function stop_nova_hypervisor {
# Stop the docker registry container
docker stop $DOCKER_REGISTRY_IMAGE_NAME
docker rm $DOCKER_REGISTRY_IMAGE_NAME
}
# Restore xtrace
$MY_XTRACE
# Local variables:
# mode: shell-script
# End:

View File

@ -1,15 +0,0 @@
#!/bin/bash
#
# 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.
# This script is executed inside post_test_hook function in devstack gate.

View File

@ -1,15 +0,0 @@
#!/bin/bash
#
# 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.
# This script is executed inside pre_test_hook function in devstack gate.

View File

@ -1,14 +0,0 @@
#!/bin/bash
set -xe
env
NOVADOCKERDIR=$(readlink -f $(dirname $0)/../..)
INSTALLDIR=${INSTALLDIR:-/opt/stack}
cp $NOVADOCKERDIR/contrib/devstack/lib/nova_plugins/hypervisor-docker $INSTALLDIR/devstack/lib/nova_plugins/
cat - <<-EOF >> $INSTALLDIR/devstack/localrc
enable_plugin nova-docker https://git.openstack.org/openstack/nova-docker
GITDIR['nova-docker']=$INSTALLDIR/nova-docker
EOF

View File

@ -1,2 +0,0 @@
[[local|localrc]]
enable_plugin docker-service https://github.com/dims/devstack-plugin-docker

View File

@ -1,78 +0,0 @@
#!/bin/bash
# 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.
# Save trace setting
XTRACE=$(set +o | grep xtrace)
set -o xtrace
DOCKER_UNIX_SOCKET=/var/run/docker.sock
# main loop
if [[ "$1" == "stack" && "$2" == "install" ]]; then
echo_summary "Running stack install"
elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
echo_summary "Running stack post-config"
wget http://get.docker.com -O install_docker.sh
sudo chmod 777 install_docker.sh
sudo bash -x install_docker.sh
sudo rm install_docker.sh
if is_fedora; then
install_package socat dnsmasq
fi
# CentOS/RedHat distros don't start the services just after the package
# is installed if it is not explicitily set. So the script fails on
# them in this killall because there is nothing to kill.
sudo killall docker || true
# Enable debug level logging
if [ -f "/etc/default/docker" ]; then
sudo cat /etc/default/docker
sudo sed -i 's/^.*DOCKER_OPTS=.*$/DOCKER_OPTS=\"--debug --storage-opt dm.override_udev_sync_check=true\"/' /etc/default/docker
sudo cat /etc/default/docker
fi
if [ -f "/etc/sysconfig/docker" ]; then
sudo cat /etc/sysconfig/docker
sudo sed -i 's/^.*OPTIONS=.*$/OPTIONS=--debug --selinux-enabled/' /etc/sysconfig/docker
sudo cat /etc/sysconfig/docker
fi
if [ -f "/usr/lib/systemd/system/docker.service" ]; then
sudo cat /usr/lib/systemd/system/docker.service
sudo sed -i 's/docker daemon/docker daemon --debug/' /usr/lib/systemd/system/docker.service
sudo cat /usr/lib/systemd/system/docker.service
sudo systemctl daemon-reload
fi
# Start the daemon - restart just in case the package ever auto-starts...
restart_service docker
echo "Waiting for docker daemon to start..."
DOCKER_GROUP=$(groups | cut -d' ' -f1)
CONFIGURE_CMD="while ! /bin/echo -e 'GET /version HTTP/1.0\n\n' | socat - unix-connect:$DOCKER_UNIX_SOCKET 2>/dev/null | grep -q '200 OK'; do
# Set the right group on docker unix socket before retrying
sudo chgrp $DOCKER_GROUP $DOCKER_UNIX_SOCKET
sudo chmod g+rw $DOCKER_UNIX_SOCKET
sleep 1
done"
if ! timeout $SERVICE_TIMEOUT sh -c "$CONFIGURE_CMD"; then
die $LINENO "docker did not start"
fi
fi
if [[ "$1" == "unstack" ]]; then
echo_summary "Running unstack"
stop_service docker
fi
# Restore xtrace
$XTRACE

View File

@ -1,4 +0,0 @@
export VIRT_DRIVER=docker
export DEFAULT_IMAGE_NAME=cirros
export NON_STANDARD_REQS=1
export IMAGE_URLS=" "

View File

@ -1,75 +0,0 @@
# -*- coding: utf-8 -*-
# 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.
import os
import sys
sys.path.insert(0, os.path.abspath('../..'))
# -- General configuration ----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
# 'sphinx.ext.intersphinx',
'oslosphinx'
]
# autodoc generation is a bit aggressive and a nuisance when doing heavy
# text edit cycles.
# execute "export SPHINX_DEBUG=1" in your terminal to disable
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'nova-docker'
copyright = u'2013, OpenStack Foundation'
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
add_module_names = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output --------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
# html_theme_path = ["."]
# html_theme = '_theme'
# html_static_path = ['static']
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
# [howto/manual]).
latex_documents = [
('index',
'%s.tex' % project,
u'%s Documentation' % project,
u'OpenStack Foundation', 'manual'),
]
# Example configuration for intersphinx: refer to the Python standard library.
# intersphinx_mapping = {'http://docs.python.org/': None}

View File

@ -1 +0,0 @@
.. include:: ../../CONTRIBUTING.rst

View File

@ -1,24 +0,0 @@
.. nova-docker documentation master file, created by
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to nova-docker's documentation!
========================================================
Contents:
.. toctree::
:maxdepth: 2
readme
installation
usage
contributing
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -1,12 +0,0 @@
============
Installation
============
At the command line::
$ pip install nova-docker
Or, if you have virtualenvwrapper installed::
$ mkvirtualenv nova-docker
$ pip install nova-docker

View File

@ -1 +0,0 @@
.. include:: ../../README.rst

View File

@ -1,7 +0,0 @@
========
Usage
========
To use nova-docker in a project::
import novadocker

View File

@ -1,6 +0,0 @@
# nova-rootwrap command filters for setting up network in the docker driver
# This file should be owned by (and only-writeable by) the root user
[Filters]
# nova/virt/docker/driver.py: 'ln', '-sf', '/var/run/netns/.*'
ln: CommandFilter, /bin/ln, root

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
# 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.
import pbr.version
__version__ = pbr.version.VersionInfo(
'nova-docker').version_string()

View File

@ -1,46 +0,0 @@
# Copyright 2014 IBM Corp.
#
# 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.
"""oslo.i18n integration module.
See http://docs.openstack.org/developer/oslo.i18n/usage.html .
"""
import oslo_i18n
DOMAIN = 'nova-docker'
_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN)
# The primary translation function using the well-known name "_"
_ = _translators.primary
# Translators for log levels.
#
# The abbreviated names are meant to reflect the usual use of a short
# name like '_'. The "L" is for "log" and the other letter comes from
# the level.
_LI = _translators.log_info
_LW = _translators.log_warning
_LE = _translators.log_error
_LC = _translators.log_critical
def translate(value, user_locale):
return oslo_i18n.translate(value, user_locale)
def get_available_languages():
return oslo_i18n.get_available_languages(DOMAIN)

View File

@ -1,153 +0,0 @@
# Translations template for nova-docker.
# Copyright (C) 2015 ORGANIZATION
# This file is distributed under the same license as the nova-docker
# project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2015.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: nova-docker 0.1.1.dev112\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2015-09-03 15:09-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.0\n"
#: novadocker/virt/docker/driver.py:121
msgid ""
"Docker daemon is not running or is not reachable (check the rights on "
"/var/run/docker.sock)"
msgstr ""
#: novadocker/virt/docker/driver.py:231
msgid "Cannot find any PID under container \"{0}\""
msgstr ""
#: novadocker/virt/docker/driver.py:307
#, python-format
msgid ""
"Hostname has changed from %(old)s to %(new)s. A restart is required to "
"take effect."
msgstr ""
#: novadocker/virt/docker/driver.py:363
msgid "Image container format not supported ({0})"
msgstr ""
#: novadocker/virt/docker/driver.py:385
#, python-format
msgid "Cannot load repository file from shared directory: %s"
msgstr ""
#: novadocker/virt/docker/driver.py:404
#, python-format
msgid "Cannot load repository file: %s"
msgstr ""
#: novadocker/virt/docker/driver.py:406
msgid "Cannot load repository file: {0}"
msgstr ""
#: novadocker/virt/docker/driver.py:444 novadocker/virt/docker/driver.py:604
#, python-format
msgid "Cannot setup network: %s"
msgstr ""
#: novadocker/virt/docker/driver.py:446 novadocker/virt/docker/driver.py:606
msgid "Cannot setup network: {0}"
msgstr ""
#: novadocker/virt/docker/driver.py:481
msgid "Cannot create container"
msgstr ""
#: novadocker/virt/docker/driver.py:531
#, python-format
msgid "Cannot stop container: %s"
msgstr ""
#: novadocker/virt/docker/driver.py:573
msgid "Cannot destroy the container network during reboot {0}"
msgstr ""
#: novadocker/virt/docker/driver.py:586
msgid "Cannot setup network on reboot: {0}"
msgstr ""
#: novadocker/virt/docker/driver.py:628
#, python-format
msgid "Error pause container: %s"
msgstr ""
#: novadocker/virt/docker/driver.py:630
msgid "Cannot pause container: {0}"
msgstr ""
#: novadocker/virt/docker/driver.py:644
#, python-format
msgid "Error unpause container: %s"
msgstr ""
#: novadocker/virt/docker/driver.py:646
msgid "Cannot unpause container: {0}"
msgstr ""
#: novadocker/virt/docker/driver.py:702
#, python-format
msgid "Error saving image: %s"
msgstr ""
#: novadocker/virt/docker/driver.py:704
msgid "Error saving image: {0}"
msgstr ""
#: novadocker/virt/docker/network.py:36
#, python-format
msgid "Cannot remove network namespace, netns id: %s"
msgstr ""
#: novadocker/virt/docker/network.py:46
msgid "Cannot find fixed ip"
msgstr ""
#: novadocker/virt/docker/network.py:53
msgid "Cannot find gateway"
msgstr ""
#: novadocker/virt/docker/opencontrail.py:70 novadocker/virt/docker/vifs.py:106
#: novadocker/virt/docker/vifs.py:131 novadocker/virt/docker/vifs.py:160
#: novadocker/virt/docker/vifs.py:308
msgid "Failed to setup the network, rolling back"
msgstr ""
#: novadocker/virt/docker/opencontrail.py:128
msgid "Failed to attach the network, rolling back"
msgstr ""
#: novadocker/virt/docker/opencontrail.py:155
msgid "Failed to attach vif"
msgstr ""
#: novadocker/virt/docker/opencontrail.py:172
msgid "Delete port failed"
msgstr ""
#: novadocker/virt/docker/vifs.py:55 novadocker/virt/docker/vifs.py:321
msgid "vif_type parameter must be present for this vif_driver implementation"
msgstr ""
#: novadocker/virt/docker/vifs.py:71 novadocker/virt/docker/vifs.py:337
#, python-format
msgid "Unexpected vif_type=%s"
msgstr ""
#: novadocker/virt/docker/vifs.py:355 novadocker/virt/docker/vifs.py:363
#: novadocker/virt/docker/vifs.py:374 novadocker/virt/docker/vifs.py:397
msgid "Failed while unplugging vif"
msgstr ""

View File

@ -1,33 +0,0 @@
# -*- coding: utf-8 -*-
# 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.
# TODO(mikal): move eventlet imports to nova.__init__ once we move to PBR
import os
import sys
# NOTE(mikal): All of this is because if dnspython is present in your
# environment then eventlet monkeypatches socket.getaddrinfo() with an
# implementation which doesn't work for IPv6. What we're checking here is
# that the magic environment variable was set when the import happened.
if ('eventlet' in sys.modules and
os.environ.get('EVENTLET_NO_GREENDNS', '').lower() != 'yes'):
raise ImportError('eventlet imported before nova/cmd/__init__ '
'(env var set to %s)'
% os.environ.get('EVENTLET_NO_GREENDNS'))
os.environ['EVENTLET_NO_GREENDNS'] = 'yes'
import eventlet
eventlet.monkey_patch(os=False)

View File

@ -1,235 +0,0 @@
# Copyright (c) 2013 dotCloud, Inc.
# 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.
import inspect
import time
import uuid
from oslo_utils import timeutils
from six import moves
from novadocker.virt.docker import client as docker_client
class MockClient(object):
def __init__(self, endpoint=None):
self._containers = {}
self.name = None
# Fake repository
self._repository = {'image_with_cmd':
{'ContainerConfig':
{'Cmd': 'echo Test'}},
'image_without_cmd':
{'ContainerConfig':
{'Cmd': None}}}
self._images = {'snap-1':
{'ContainerConfig':
{'Cmd': None}}}
self._image_data = {'snap-1': 'dummy'}
self._setup_decorators()
def _setup_decorators(self):
for name, member in inspect.getmembers(self, inspect.ismethod):
if not name.startswith('_'):
setattr(self, name, docker_client.filter_data(member))
def _fake_id(self):
return uuid.uuid4().hex + uuid.uuid4().hex
def _image_name(self, image_name):
"""Split full image name to host and image name."""
if '/' in image_name:
host, image_name = image_name.split('/', 1)
return image_name
def _is_image_exists(self, image_name):
"""Check whether Images is listed in self._repository."""
image_name = self._image_name(image_name)
if image_name in self._repository:
return image_name in self._images
return True
def _is_daemon_running(self):
return True
def containers(self, all=True, filters=None):
containers = []
for container_id in self._containers.iterkeys():
containers.append({
'Status': 'Exit 0',
'Created': int(time.time()),
'Image': 'ubuntu:12.04',
'Ports': '',
'Command': 'bash ',
'Id': container_id
})
if filters and filters.get('name'):
if (self._containers[container_id]['Config']['name'] ==
filters.get('name')):
return [{'Id': container_id}]
return containers
def create_container(self, image_name, **args):
self.name = args['name']
data = {
'Hostname': args['hostname'],
'User': '',
'MemorySwap': 0,
'AttachStdin': False,
'AttachStdout': False,
'AttachStderr': False,
'PortSpecs': None,
'Tty': True,
'OpenStdin': True,
'StdinOnce': False,
'Env': None,
'Cmd': [],
'Dns': None,
'Image': image_name,
'Volumes': {},
'VolumesFrom': '',
'CpuShares': args['cpu_shares'],
'NetworkDisabled': args['network_disabled']
}
data.update(args)
if not self._is_image_exists(data['Image']):
return None
container_id = self._fake_id()
self._containers[container_id] = {
'Id': container_id,
'running': False,
'Config': data
}
return container_id
def start(self, container_id, binds=None, dns=None, privileged=False):
if container_id not in self._containers:
return False
self._containers[container_id]['running'] = True
return True
def inspect_image(self, image_name):
if not self._is_image_exists(image_name):
return None
image_name = self._image_name(image_name)
if image_name in self._images:
return self._images[image_name]
return {'ContainerConfig': {'Cmd': None}}
def inspect_container(self, container_id):
if container_id not in self._containers:
return
container = self._containers[container_id]
info = {
'Args': [],
'Config': container['Config'],
'Created': str(timeutils.utcnow()),
'Id': container_id,
'Image': self._fake_id(),
'NetworkSettings': {
'Bridge': '',
'Gateway': '',
'IPAddress': '',
'IPPrefixLen': 0,
'PortMapping': None
},
'Path': 'bash',
'ResolvConfPath': '/etc/resolv.conf',
'State': {
'ExitCode': 0,
'Ghost': False,
'Pid': 0,
'Running': container['running'],
'StartedAt': str(timeutils.utcnow())
},
'SysInitPath': '/tmp/docker',
'Volumes': {},
}
return info
def stop(self, container_id, timeout=None):
if container_id not in self._containers:
return False
self._containers[container_id]['running'] = False
return True
def kill(self, container_id):
if container_id not in self._containers:
return False
self._containers[container_id]['running'] = False
return True
def remove_container(self, container_id, force=False):
if container_id not in self._containers:
return False
# Docker doesn't allow to destroy a running container.
if self._containers[container_id]['running']:
return False
del self._containers[container_id]
return True
def unpause(self, container_id):
if container_id not in self._containers:
return False
self._containers[container_id]['paused'] = False
return True
def pause(self, container_id):
if container_id not in self._containers:
return False
self._containers[container_id]['paused'] = True
return True
def commit(self, container_id, repository=None, tag=None):
if container_id not in self._containers:
return False
return True
def get_container_logs(self, container_id):
if container_id not in self._containers:
return False
return '\n'.join([
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ',
'Vivamus ornare mi sit amet orci feugiat, nec luctus magna ',
'vehicula. Quisque diam nisl, dictum vitae pretium id, ',
'consequat eget sapien. Ut vehicula tortor non ipsum ',
'consectetur, at tincidunt elit posuere. In ut ligula leo. ',
'Donec eleifend accumsan mi, in accumsan metus. Nullam nec ',
'nulla eu risus vehicula porttitor. Sed purus ligula, ',
'placerat nec metus a, imperdiet viverra turpis. Praesent ',
'dapibus ornare massa. Nam ut hendrerit nunc. Interdum et ',
'malesuada fames ac ante ipsum primis in faucibus. ',
'Fusce nec pellentesque nisl.'])
def get_image(self, name):
if (name not in self._images or
name not in self._image_data):
raise Exception("Image not found - %s" % name)
return moves.StringIO(self._image_data[name])
def load_image(self, name, data):
self._image_data[name] = data
def load_repository_file(self, name, path):
pass
def ping(self):
return True

View File

@ -1,583 +0,0 @@
# Copyright (c) 2013 dotCloud, Inc.
# 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.
import contextlib
import os
import socket
import eventlet
import mock
from oslo_config import cfg
from oslo_config import fixture as config_fixture
from oslo_utils import units
from nova.compute import manager
from nova.compute import task_states
from nova import context
from nova import exception
from nova import test
import nova.tests.unit.image.fake
from nova.tests.unit import matchers
from nova.tests.unit import utils
from nova.tests.unit.virt import test_virt_drivers
from novadocker.tests.virt.docker import mock_client
import novadocker.virt.docker
from novadocker.virt.docker import driver as docker_driver
from novadocker.virt.docker import hostinfo
from novadocker.virt.docker import network
class DockerDriverTestCase(test_virt_drivers._VirtDriverTestCase,
test.TestCase):
driver_module = 'novadocker.virt.docker.DockerDriver'
def setUp(self):
super(DockerDriverTestCase, self).setUp()
self.mock_client = mock_client.MockClient()
self.stubs.Set(novadocker.virt.docker.driver.DockerDriver, 'docker',
self.mock_client)
def fake_plug_vifs(self, instance, network_info):
return
self.stubs.Set(novadocker.virt.docker.driver.DockerDriver,
'plug_vifs',
fake_plug_vifs)
def fake_attach_vifs(self, instance, network_info):
return
self.stubs.Set(novadocker.virt.docker.driver.DockerDriver,
'_attach_vifs',
fake_attach_vifs)
# Note: using mock.object.path on class throws
# errors in test_virt_drivers
def fake_teardown_network(container_id):
return
self.stubs.Set(network, 'teardown_network', fake_teardown_network)
self.context = context.RequestContext('fake_user', 'fake_project')
self.connection.init_host(None)
self.fixture = self.useFixture(
config_fixture.Config(novadocker.virt.docker.driver.CONF))
def test_live_migration(self):
self.skipTest('Live migration is not implemented.')
def test_driver_capabilities(self):
self.assertFalse(self.connection.capabilities['has_imagecache'])
self.assertFalse(self.connection.capabilities['supports_recreate'])
# NOTE(bcwaldon): This exists only because _get_running_instance on the
# base class will not let us set a custom disk/container_format.
def _get_running_instance(self, obj=True):
instance_ref = utils.get_test_instance(obj=obj)
network_info = utils.get_test_network_info()
network_info[0]['network']['subnets'][0]['meta']['dhcp_server'] = \
'1.1.1.1'
image_info = utils.get_test_image_object(None, instance_ref)
image_info.disk_format = 'raw'
image_info.container_format = 'docker'
self.connection.spawn(self.ctxt, instance_ref, image_info,
[], 'herp', network_info=network_info)
return instance_ref, network_info
@mock.patch.object(hostinfo, 'get_total_vcpus', return_value=1)
@mock.patch.object(hostinfo, 'get_vcpus_used', return_value=0)
def test_get_host_stats(self, mock_total, mock_used):
memory = {
'total': 4 * units.Mi,
'used': 1 * units.Mi
}
self.mox.StubOutWithMock(socket, 'gethostname')
self.mox.StubOutWithMock(hostinfo, 'get_memory_usage')
socket.gethostname().AndReturn('foo')
hostinfo.get_memory_usage().AndReturn(memory)
socket.gethostname().AndReturn('bar')
hostinfo.get_memory_usage().AndReturn(memory)
self.mox.ReplayAll()
self.assertEqual('foo',
self.connection.get_host_stats()['host_hostname'])
self.assertEqual('foo',
self.connection.get_host_stats()['host_hostname'])
def test_get_available_resource(self):
memory = {
'total': 4 * units.Mi,
'used': 1 * units.Mi
}
disk = {
'total': 50 * units.Gi,
'available': 25 * units.Gi,
'used': 25 * units.Gi
}
# create the mocks
with contextlib.nested(
mock.patch.object(hostinfo, 'get_total_vcpus',
return_value=1),
mock.patch.object(hostinfo, 'get_vcpus_used',
return_value=0),
mock.patch.object(hostinfo, 'get_memory_usage',
return_value=memory),
mock.patch.object(hostinfo, 'get_disk_usage',
return_value=disk)
) as (
get_total_vcpus,
get_vcpus_used,
get_memory_usage,
get_disk_usage
):
# run the code
stats = self.connection.get_available_resource(nodename='test')
# make our assertions
get_memory_usage.assert_called_once_with()
get_disk_usage.assert_called_once_with()
expected_stats = {
'vcpus': 1,
'vcpus_used': 0,
'memory_mb': 4,
'memory_mb_used': 1,
'local_gb': 50L,
'local_gb_used': 25L,
'disk_available_least': 25L,
'hypervisor_type': 'docker',
'hypervisor_version': 1000,
'hypervisor_hostname': 'test',
'cpu_info': '?',
'numa_topology': None,
'supported_instances': [("i686", "docker", "exe"),
("x86_64", "docker", "exe")]
}
self.assertEqual(expected_stats, stats)
def _test_start_container_with_network_events(self, neutron_failure=None):
generated_events = []
def wait_timeout():
event = mock.MagicMock()
if neutron_failure == 'timeout':
raise eventlet.timeout.Timeout()
elif neutron_failure == 'error':
event.status = 'failed'
else:
event.status = 'completed'
return event
def fake_prepare(instance, event_name):
m = mock.MagicMock()
m.instance = instance
m.event_name = event_name
m.wait.side_effect = wait_timeout
generated_events.append(m)
return m
virtapi = manager.ComputeVirtAPI(mock.MagicMock())
prepare = virtapi._compute.instance_events.prepare_for_instance_event
prepare.side_effect = fake_prepare
drvr = novadocker.virt.docker.driver.DockerDriver(virtapi)
instance_href = utils.get_test_instance()
container_id = self.connection._find_container_by_uuid(
instance_href['uuid']).get('id')
vifs = [{'id': 'vif1', 'active': False},
{'id': 'vif2', 'active': False}]
@mock.patch.object(drvr, '_extract_dns_entries')
@mock.patch.object(drvr, 'plug_vifs')
@mock.patch.object(drvr, '_attach_vifs')
@mock.patch.object(self.mock_client, 'start')
@mock.patch.object(self.mock_client, 'kill')
@mock.patch.object(self.mock_client, 'remove_container')
def test_start(remove_container, kill, start, attach_vif, plug_vifs,
extract_dns_entries):
drvr._start_container(container_id, instance_href,
vifs)
plug_vifs.assert_called_with(instance_href, vifs)
attach_vif.assert_called_with(instance_href, vifs)
if neutron_failure and cfg.CONF.vif_plugging_is_fatal:
kill.assert_called_once_with(container_id)
remove_container.assert_called_once_with(container_id,
Force=True)
test_start()
if nova.utils.is_neutron() and cfg.CONF.vif_plugging_timeout:
prepare.assert_has_calls([
mock.call(instance_href, 'network-vif-plugged-vif1'),
mock.call(instance_href, 'network-vif-plugged-vif2')])
for event in generated_events:
if neutron_failure and generated_events.index(event) != 0:
self.assertEqual(0, event.call_count)
else:
self.assertEqual(0, prepare.call_count)
@mock.patch('nova.utils.is_neutron', return_value=True)
def test_start_container_with_network_events(self, is_neutron):
self._test_start_container_with_network_events()
@mock.patch('nova.utils.is_neutron', return_value=True)
def test_start_container_with_network_events_nowait(self, is_neutron):
self.flags(vif_plugging_timeout=0)
self._test_start_container_with_network_events()
@mock.patch('nova.utils.is_neutron', return_value=True)
def test_start_container_with_network_events_failed_timeout_non_fatal(
self, is_neutron):
self.flags(vif_plugging_is_fatal=False)
self._test_start_container_with_network_events(
neutron_failure='timeout')
@mock.patch('nova.utils.is_neutron', return_value=True)
def test_start_container_with_network_events_failed_timeout_fatal(
self, is_neutron):
self.assertRaises(exception.InstanceDeployFailure,
self._test_start_container_with_network_events,
neutron_failure='timeout')
@mock.patch('nova.utils.is_neutron', return_value=True)
def test_start_container_with_network_events_failed_error_non_fatal(
self, is_neutron):
self.flags(vif_plugging_is_fatal=False)
self._test_start_container_with_network_events(
neutron_failure='error')
@mock.patch('nova.utils.is_neutron', return_value=True)
def test_start_container_with_network_events_failed_error_fatal(
self, is_neutron):
self.assertRaises(exception.InstanceDeployFailure,
self._test_start_container_with_network_events,
neutron_failure='error')
@mock.patch('nova.utils.is_neutron', return_value=False)
def test_start_container_with_network_events_non_neutron(self,
is_neutron):
self._test_start_container_with_network_events()
def test_create_container(self, image_info=None, instance_href=None,
network_info=None):
if instance_href is None:
instance_href = utils.get_test_instance()
if image_info is None:
image_info = utils.get_test_image_object(None, instance_href)
image_info.disk_format = 'raw'
image_info.container_format = 'docker'
self.connection.spawn(self.context, instance_href, image_info,
'fake_files', 'fake_password',
network_info=network_info)
self._assert_cpu_shares(instance_href)
self.assertEqual(self.mock_client.name, "nova-{0}".format(
instance_href['uuid']))
def test_create_container_empty_cmd(self, image_info=None,
instance_href=None,
network_info=None):
if instance_href is None:
instance_href = utils.get_test_instance()
if image_info is None:
image_info = utils.get_test_image_object(None, instance_href)
image_info.disk_format = 'raw'
image_info.container_format = 'docker'
with mock.patch.object(self.mock_client, 'create_container') as mc:
self.connection.spawn(self.context, instance_href, image_info,
'fake_files', 'fake_password',
network_info=network_info)
self.assertIsNone(mc.call_args[1].get('command'))
@mock.patch.object(novadocker.virt.docker.driver.DockerDriver,
'_inject_key', return_value='/tmp/.ssh')
def test_create_container_inject_key(self, mock_inject_key):
self.fixture.config(inject_key=True, group='docker')
instance_href = utils.get_test_instance()
instance_href.key_data = 'my_key'
image_info = utils.get_test_image_object(None, instance_href)
image_info.disk_format = 'raw'
image_info.container_format = 'docker'
with mock.patch.object(self.mock_client, 'create_container'):
with mock.patch.object(self.mock_client, 'start') as ms:
self.connection.spawn(self.context, instance_href, image_info,
'fake_files', 'fake_password',
network_info=None)
command = ms.call_args[1]
expected = {'binds': {'/tmp/.ssh':
{'bind': '/root/.ssh', 'ro': True}},
'dns': None,
'privileged': False}
self.assertEqual(expected, command)
def test_create_container_glance_cmd(self, image_info=None,
instance_href=None,
network_info=None):
if instance_href is None:
instance_href = utils.get_test_instance()
if image_info is None:
image_info = utils.get_test_image_object(None, instance_href)
image_info.disk_format = 'raw'
image_info.container_format = 'docker'
image_info.properties.os_command_line = 'uname'
with mock.patch.object(self.mock_client, 'create_container') as mc:
self.connection.spawn(self.context, instance_href, image_info,
'fake_files', 'fake_password',
network_info=network_info)
command = mc.call_args[1]['command']
self.assertEqual('uname', command)
def test_create_container_vcpus_2(self, image_info=None):
flavor = utils.get_test_flavor(options={
'name': 'vcpu_2',
'flavorid': 'vcpu_2',
'vcpus': 2
})
instance_href = utils.get_test_instance(flavor=flavor)
if image_info is None:
image_info = utils.get_test_image_object(None, instance_href)
image_info.disk_format = 'raw'
image_info.container_format = 'docker'
self.connection.spawn(self.context, instance_href, image_info,
'fake_files', 'fake_password')
self._assert_cpu_shares(instance_href, vcpus=2)
self.assertEqual(self.mock_client.name, "nova-{0}".format(
instance_href['uuid']))
def _assert_cpu_shares(self, instance_href, vcpus=4):
container_id = self.connection._find_container_by_uuid(
instance_href['uuid']).get('id')
container_info = self.connection.docker.inspect_container(container_id)
self.assertEqual(vcpus * 1024, container_info['Config']['CpuShares'])
@mock.patch('novadocker.virt.docker.driver.DockerDriver.plug_vifs',
side_effect=Exception)
def test_create_container_net_setup_fails(self, mock_plug_vifs):
self.assertRaises(exception.InstanceDeployFailure,
self.test_create_container,
network_info=utils.get_test_network_info())
self.assertEqual(0, len(self.mock_client.containers()))
def test_create_container_wrong_image(self):
instance_href = utils.get_test_instance()
image_info = utils.get_test_image_object(None, instance_href)
image_info.disk_format = 'raw'
image_info.container_format = 'invalid_format'
self.assertRaises(exception.InstanceDeployFailure,
self.test_create_container,
image_info, instance_href)
@mock.patch.object(novadocker.virt.docker.driver.DockerDriver,
'cleanup')
@mock.patch.object(novadocker.virt.docker.driver.DockerDriver,
'_find_container_by_uuid',
return_value={'id': 'fake_id'})
def test_destroy_container(self, byuuid_mock, cleanup_mock):
instance = utils.get_test_instance()
self.connection.destroy(self.context, instance, 'fake_networkinfo')
cleanup_mock.assert_called_with(self.context, instance,
'fake_networkinfo', None, True)
@mock.patch.object(network, 'teardown_network')
@mock.patch.object(novadocker.virt.docker.driver.DockerDriver,
'unplug_vifs')
@mock.patch.object(novadocker.virt.docker.driver.DockerDriver,
'_find_container_by_uuid',
return_value={'id': 'fake_id'})
def test_cleanup_container(self, byuuid_mock, unplug_mock, teardown_mock):
instance = utils.get_test_instance()
self.connection.cleanup(self.context, instance, 'fake_networkinfo')
byuuid_mock.assert_called_with(instance['uuid'])
teardown_mock.assert_called_with('fake_id')
@mock.patch.object(novadocker.virt.docker.driver.DockerDriver,
'unplug_vifs')
@mock.patch.object(novadocker.virt.docker.driver.DockerDriver,
'_find_container_by_uuid',
return_value={})
def test_cleanup_container_notfound(self, byuuid_mock, unplug_mock):
instance = utils.get_test_instance()
self.connection.cleanup(self.context, instance, 'fake_networkinfo')
byuuid_mock.assert_called_with(instance['uuid'])
unplug_mock.assert_called_once_with(instance, 'fake_networkinfo')
def test_soft_delete_restore_container(self):
instance_href = utils.get_test_instance()
image_info = utils.get_test_image_object(None, instance_href)
image_info.disk_format = 'raw'
image_info.container_format = 'docker'
self.connection.spawn(self.context, instance_href, image_info,
'fake_files', 'fake_password')
container_id = self.connection._find_container_by_uuid(
instance_href['uuid']).get('id')
self.connection.soft_delete(instance_href)
info = self.connection.docker.inspect_container(container_id)
self.assertFalse(info['State']['Running'])
self.connection.restore(instance_href)
info = self.connection.docker.inspect_container(container_id)
self.assertTrue(info['State']['Running'])
def test_get_memory_limit_from_sys_meta_in_object(self):
instance = utils.get_test_instance(obj=True)
limit = self.connection._get_memory_limit_bytes(instance)
self.assertEqual(512 * units.Mi, limit)
def test_get_memory_limit_from_sys_meta_in_db_instance(self):
instance = utils.get_test_instance(obj=False)
limit = self.connection._get_memory_limit_bytes(instance)
self.assertEqual(2048 * units.Mi, limit)
def test_list_instances(self):
instance_href = utils.get_test_instance()
image_info = utils.get_test_image_object(None, instance_href)
image_info.disk_format = 'raw'
image_info.container_format = 'docker'
self.connection.spawn(self.context, instance_href, image_info,
'fake_files', 'fake_password')
instances = self.connection.list_instances()
self.assertIn(instance_href.name, instances)
def test_list_instances_none(self):
instances = self.connection.list_instances()
self.assertIsInstance(instances, list)
self.assertFalse(instances)
def test_list_instances_no_inspect_race(self):
"""Assures containers that cannot be inspected are not listed."""
instance_href = utils.get_test_instance()
image_info = utils.get_test_image_object(None, instance_href)
image_info.disk_format = 'raw'
image_info.container_format = 'docker'
self.connection.spawn(self.context, instance_href, image_info,
'fake_files', 'fake_password')
with mock.patch.object(self.mock_client, 'inspect_container',
return_value={}):
instances = self.connection.list_instances()
self.assertFalse(instances)
def test_find_container_pid(self):
driver = novadocker.virt.docker.driver.DockerDriver(None)
with mock.patch.object(driver.docker,
"inspect_container") as inspect_container:
inspect_container.return_value = {'State': {'Pid': '12345'}}
pid = driver._find_container_pid("fake_container_id")
self.assertEqual(pid, '12345')
def test_get_console_output_with_no_container(self):
driver = novadocker.virt.docker.driver.DockerDriver(None)
with mock.patch.object(driver,
"_get_container_id") as get_container_id:
get_container_id.return_value = None
logs = driver.get_console_output(None, None)
self.assertEqual('', logs)
@mock.patch.object(novadocker.virt.docker.driver.DockerDriver,
'_find_container_by_uuid',
return_value={'id': 'fake_id'})
def test_snapshot(self, byuuid_mock):
# Use mix-case to test that mixed-case image names succeed.
snapshot_name = 'tEsT-SnAp'
expected_calls = [
{'args': (),
'kwargs':
{'task_state': task_states.IMAGE_PENDING_UPLOAD}},
{'args': (),
'kwargs':
{'task_state': task_states.IMAGE_UPLOADING,
'expected_state': task_states.IMAGE_PENDING_UPLOAD}}]
func_call_matcher = matchers.FunctionCallMatcher(expected_calls)
instance_ref = utils.get_test_instance()
properties = {'instance_id': instance_ref['id'],
'user_id': str(self.context.user_id)}
sent_meta = {'name': snapshot_name, 'is_public': False,
'status': 'creating', 'properties': properties}
# Because the docker driver doesn't push directly into Glance, we
# cannot check that the images are correctly configured in the
# fake image service, but we can ensuring naming and other
# conventions are accurate.
image_service = nova.tests.unit.image.fake.FakeImageService()
recv_meta = image_service.create(context, sent_meta)
with mock.patch.object(self.mock_client, 'load_image'):
with mock.patch.object(self.mock_client, 'get_image'):
self.connection.snapshot(self.context, instance_ref,
recv_meta['id'],
func_call_matcher.call)
snapshot = image_service.show(context, recv_meta['id'])
self.assertEqual(snapshot['properties']['image_state'],
'available')
self.assertEqual(snapshot['status'], 'active')
self.assertEqual(snapshot['disk_format'], 'raw')
self.assertEqual(snapshot['container_format'], 'docker')
self.assertEqual(snapshot['name'], snapshot_name)
def test_get_image_name(self):
instance_ref = utils.get_test_instance()
image_info = utils.get_test_image_object(None, instance_ref)
image_info.container_format = 'docker'
image_info.name = 'MiXeDcAsE-image'
repo = self.connection._get_image_name(self.context,
instance_ref, image_info)
# image_name = repo.split("/")[1]
self.assertEqual(image_info.name, repo)
def test_get_host_uptime_returns_exec_result(self):
result = '4294967296'
with mock.patch('nova.utils.execute',
return_value=(result, None)):
uptime = self.connection.get_host_uptime()
self.assertEqual(result, uptime)
def test_get_dns_entries(self):
driver = docker_driver.DockerDriver(object)
network_info = utils.get_test_network_info()
self.assertEqual(['192.168.122.1', '192.168.122.2'],
driver._extract_dns_entries(network_info))
@mock.patch.object(os.path, 'exists', return_value=True)
def test_pull_missing_image_with_shared_dir(self, mock_os):
self.fixture.config(shared_directory='/fake_dir', group='docker')
instance_ref = utils.get_test_instance()
image_info = utils.get_test_image_object(None, instance_ref)
image_info.name = 'fake_name'
image_info.id = 'fake_id'
with mock.patch.object(self.mock_client, 'load_repository_file') as f:
with mock.patch.object(self.mock_client, 'inspect_image') as i:
i.return_value = 'fake_image'
image = self.connection._pull_missing_image(self.context,
image_info,
instance_ref)
f.assert_called_once_with('fake_name', '/fake_dir/fake_id')
i.assert_called_once_with('fake_name')
self.assertEqual('fake_image', image)
def test_find_container_by_uuid(self):
instance_href = utils.get_test_instance()
image_info = utils.get_test_image_object(None, instance_href)
image_info.disk_format = 'raw'
image_info.container_format = 'docker'
self.connection.spawn(self.context, instance_href, image_info,
'fake_files', 'fake_password')
info = self.connection._find_container_by_uuid(instance_href['uuid'])
self.assertEqual(instance_href['name'], info['Config'].get('Hostname'))

View File

@ -1,111 +0,0 @@
# Copyright 2014 IBM Corp.
# 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.
import mock
from nova.network import model as network_model
from nova import test
from nova.virt import firewall
from novadocker.virt.docker import driver
class DockerFirewallDriverTestCase(test.TestCase):
REQUIRES_LOCKING = True
gateway_bridge_4 = network_model.IP(address='10.11.12.1', type='gateway')
dns_bridge_4 = network_model.IP(address='8.8.8.8', type=None)
ips_bridge_4 = [network_model.IP(address='101.168.1.9', type='fixed',
version=4)]
subnet_bridge_4 = network_model.Subnet(cidr='10.11.1.0/24',
dns=[dns_bridge_4],
gateway=gateway_bridge_4,
ips=ips_bridge_4,
routes=None)
network_bridge = network_model.Network(id='network-id-xxx-yyy-zzz',
bridge='br100',
label=None,
subnets=[subnet_bridge_4],
bridge_interface='eth0')
vif_bridge = network_model.VIF(id='920be2f4-2b98-411e-890a-69bcabb2a5a0',
address='00:11:22:33:44:55',
network=network_bridge,
type=network_model.VIF_TYPE_BRIDGE)
def setUp(self):
super(DockerFirewallDriverTestCase, self).setUp()
self.driver = driver.DockerDriver(None)
@mock.patch.object(firewall.NoopFirewallDriver, 'prepare_instance_filter',
create=True)
@mock.patch.object(firewall.NoopFirewallDriver, 'setup_basic_filtering',
create=True)
@mock.patch.object(firewall.NoopFirewallDriver, 'apply_instance_filter',
create=True)
def test_start_firewall(self, mock_aif, mock_sbf, mock_pif):
fake_inst = 'fake-inst'
fake_net_info = mock.ANY
self.driver._start_firewall(fake_inst, fake_net_info)
mock_aif.assert_called_once_with(fake_inst, fake_net_info)
mock_sbf.assert_called_once_with(fake_inst, fake_net_info)
mock_pif.assert_called_once_with(fake_inst, fake_net_info)
@mock.patch.object(firewall.NoopFirewallDriver, 'unfilter_instance',
create=True)
def test_stop_firewall(self, mock_ui):
fake_inst = 'fake-inst'
fake_net_info = mock.ANY
self.driver._stop_firewall(fake_inst, fake_net_info)
mock_ui.assert_called_once_with(fake_inst, fake_net_info)
@mock.patch.object(firewall.NoopFirewallDriver, 'prepare_instance_filter',
create=True)
@mock.patch.object(firewall.NoopFirewallDriver, 'setup_basic_filtering',
create=True)
@mock.patch.object(firewall.NoopFirewallDriver, 'apply_instance_filter',
create=True)
def test_plug_vifs_bridge(self, mock_aif, mock_sbf, mock_pif):
fake_net_info = [self.vif_bridge]
with mock.patch('nova.utils.execute'):
d = driver.DockerDriver(object)
fake_inst = {'name': 'fake_instance'}
d.plug_vifs(fake_inst, fake_net_info)
mock_aif.assert_called_once_with(fake_inst, fake_net_info)
mock_sbf.assert_called_once_with(fake_inst, fake_net_info)
mock_pif.assert_called_once_with(fake_inst, fake_net_info)
@mock.patch.object(firewall.NoopFirewallDriver, 'unfilter_instance',
create=True)
def test_unplug_vifs_ovs(self, mock_ui):
iface_id = '920be2f4-2b98-411e-890a-69bcabb2a5a0'
fake_net_info = [
{'network': {'bridge': 'br-int',
'subnets': [{'gateway': {'address': '10.11.12.1'},
'cidr': '10.11.12.0/24',
'ips': [{'address': '10.11.12.3',
'type': 'fixed', 'version': 4}]
}]},
'devname': 'tap920be2f4-2b',
'address': '00:11:22:33:44:55',
'id': iface_id,
'type': network_model.VIF_TYPE_OVS}]
with mock.patch('nova.utils.execute'):
d = driver.DockerDriver(object)
fake_inst = {'name': 'fake_instance', 'uuid': 'instance_uuid'}
d.unplug_vifs(fake_inst, fake_net_info)
mock_ui.assert_called_once_with(fake_inst, fake_net_info)

View File

@ -1,87 +0,0 @@
# Copyright (c) 2013 dotCloud, Inc.
# 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.
import mock
import multiprocessing
from nova import test
from novadocker.virt.docker import hostinfo
import psutil
class HostInfoTestCase(test.NoDBTestCase):
_FAKE_DISK_INFO = {'total_size': 100000,
'free_size': 50000,
'used_size': 50000}
def setUp(self):
super(HostInfoTestCase, self).setUp()
self.stubs.Set(hostinfo, 'statvfs', self.statvfs)
def statvfs(self):
diskinfo = psutil.namedtuple('usage', ('total', 'free', 'used'))
return diskinfo(self._FAKE_DISK_INFO['total_size'],
self._FAKE_DISK_INFO['free_size'],
self._FAKE_DISK_INFO['used_size'])
def test_get_disk_usage(self):
disk_usage = hostinfo.get_disk_usage()
self.assertEqual(disk_usage['total'],
self._FAKE_DISK_INFO['total_size'])
self.assertEqual(disk_usage['available'],
self._FAKE_DISK_INFO['free_size'])
self.assertEqual(disk_usage['used'],
self._FAKE_DISK_INFO['used_size'])
@mock.patch.object(multiprocessing, 'cpu_count')
def test_get_total_vcpus(self, mock_cpu_count):
mock_cpu_count.return_value = 1
cpu_count = hostinfo.get_total_vcpus()
self.assertEqual(mock_cpu_count.return_value, cpu_count)
def test_get_memory_usage(self):
fake_total_memory = 4096
fake_used_memory = 2048
with mock.patch.object(psutil,
'virtual_memory') as mock_virtual_memory:
mock_virtual_memory.return_value.total = fake_total_memory
mock_virtual_memory.return_value.used = fake_used_memory
usage = hostinfo.get_memory_usage()
self.assertEqual(fake_total_memory, usage['total'])
self.assertEqual(fake_used_memory, usage['used'])
@mock.patch('novadocker.virt.docker.hostinfo.get_mounts')
def test_find_cgroup_devices_path_centos(self, mock):
mock.return_value = [
'none /sys/fs/cgroup cgroup rw,relatime,perf_event,'
'blkio,net_cls,freezer,devices,memory,cpuacct,cpu,'
'cpuset 0 0']
path = hostinfo.get_cgroup_devices_path()
self.assertEqual('/sys/fs/cgroup', path)
@mock.patch('novadocker.virt.docker.hostinfo.get_mounts')
def test_find_cgroup_devices_path_ubuntu(self, mock):
mock.return_value = [
'cgroup /cgroup tmpfs rw,relatime,mode=755 0 0',
'cgroup /cgroup/devices cgroup rw,relatime,devices,' +
'clone_children 0 0']
path = hostinfo.get_cgroup_devices_path()
self.assertEqual('/cgroup/devices', path)

View File

@ -1,98 +0,0 @@
# Copyright 2014 OpenStack Foundation
# 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.
import uuid
from oslo_concurrency import processutils
from nova import exception
from nova import test
from nova import utils
from nova.tests.unit import utils as test_utils
from novadocker.virt.docker import network
import mock
class NetworkTestCase(test.NoDBTestCase):
@mock.patch.object(network, 'os')
@mock.patch.object(utils, 'execute')
def test_teardown_delete_network(self, utils_mock, mock_os):
id = "second-id"
utils_mock.return_value = ("first-id\nsecond-id\nthird-id\n", None)
network.teardown_network(id)
utils_mock.assert_called_with('ip', 'netns', 'delete', id,
run_as_root=True)
@mock.patch.object(network, 'os')
@mock.patch.object(utils, 'execute')
def test_teardown_network_not_in_list(self, utils_mock, mock_os):
utils_mock.return_value = ("first-id\nsecond-id\nthird-id\n", None)
network.teardown_network("not-in-list")
utils_mock.assert_called_with('ip', '-o', 'netns', 'list')
@mock.patch.object(network, 'os')
@mock.patch.object(utils, 'execute')
def test_teardown_network_hyperv(self, utils_mock, mock_os):
mock_os.name = 'nt'
network.teardown_network("fake_id")
self.assertFalse(utils_mock.execute.called)
@mock.patch.object(network, 'os')
@mock.patch.object(network, 'LOG')
@mock.patch.object(utils, 'execute',
side_effect=processutils.ProcessExecutionError)
def test_teardown_network_fails(self, utils_mock, log_mock, mock_os):
# Call fails but method should not fail.
# Error will be caught and logged.
utils_mock.return_value = ("first-id\nsecond-id\nthird-id\n", None)
id = "third-id"
network.teardown_network(id)
log_mock.warning.assert_called_with(mock.ANY, id)
def test_find_gateway(self):
instance = {'uuid': uuid.uuid4()}
network_info = test_utils.get_test_network_info()
first_net = network_info[0]['network']
first_net['subnets'][0]['gateway']['address'] = '10.0.0.1'
self.assertEqual('10.0.0.1', network.find_gateway(instance, first_net))
def test_cannot_find_gateway(self):
instance = {'uuid': uuid.uuid4()}
network_info = test_utils.get_test_network_info()
first_net = network_info[0]['network']
first_net['subnets'] = []
self.assertRaises(exception.InstanceDeployFailure,
network.find_gateway, instance, first_net)
def test_find_fixed_ip(self):
instance = {'uuid': uuid.uuid4()}
network_info = test_utils.get_test_network_info()
first_net = network_info[0]['network']
first_net['subnets'][0]['cidr'] = '10.0.0.0/24'
first_net['subnets'][0]['ips'][0]['type'] = 'fixed'
first_net['subnets'][0]['ips'][0]['address'] = '10.0.1.13'
self.assertEqual('10.0.1.13/24', network.find_fixed_ip(instance,
first_net))
def test_cannot_find_fixed_ip(self):
instance = {'uuid': uuid.uuid4()}
network_info = test_utils.get_test_network_info()
first_net = network_info[0]['network']
first_net['subnets'] = []
self.assertRaises(exception.InstanceDeployFailure,
network.find_fixed_ip, instance, first_net)

View File

@ -1,165 +0,0 @@
# Copyright (C) 2014 Juniper Networks, Inc
# 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.
import mock
import sys
class MockContrailVRouterApi(mock.MagicMock):
def __init__(self, *a, **kw):
super(MockContrailVRouterApi, self).__init__()
self._args = a
self._dict = kw
self._vifs = {}
def add_port(self, vm_uuid_str, vif_uuid_str, interface_name,
mac_address, **kwargs):
if vm_uuid_str not in self._vifs:
self._vifs[vif_uuid_str] = dict(vm=vm_uuid_str,
intf=interface_name,
mac=mac_address)
self._vifs[vm_uuid_str].update(kwargs)
return self._vifs[vif_uuid_str]
def delete_port(self, vif_uuid_str):
if vif_uuid_str in self._vifs:
del self._vifs[vif_uuid_str]
mock_pkg = mock.MagicMock(name='mock_contrail_vrouter_api')
mock_mod = mock.MagicMock(name='mock_vrouter_api')
mock_cls = mock.MagicMock(name='MockOpenContrailVIFDriver',
side_effect=MockContrailVRouterApi)
mock_mod.OpenContrailVIFDriver = mock_cls
mock_pkg.vrouter_api = mock_mod
sys.modules['contrail_vrouter_api'] = mock_pkg
sys.modules['contrail_vrouter_api.vrouter_api'] = mock_mod
from nova.network import model as network_model
from nova import test
from novadocker.virt.docker import driver as docker_driver
class DockerOpenContrailVIFDriverTestCase(test.TestCase):
def setUp(self):
super(DockerOpenContrailVIFDriverTestCase, self).setUp()
docker_driver.CONF.set_override(
'vif_driver',
'novadocker.virt.docker.opencontrail.OpenContrailVIFDriver',
group='docker')
def test_plug_vrouter(self):
vid = '920be1f4-2b98-411e-890a-69bcabb2a5a0'
address = '10.1.2.1'
calls = [
mock.call('ip', 'link', 'add', 'veth%s' % vid[:8],
'type', 'veth', 'peer', 'name',
'ns%s' % vid[:8], run_as_root=True),
mock.call('ip', 'link', 'set', 'ns%s' % vid[:8],
'address', address, run_as_root=True),
]
network_info = [network_model.VIF(id=vid, address=address)]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.plug_vifs({'name': 'fake_instance'}, network_info)
ex.assert_has_calls(calls)
def test_plug_two_vrouters(self):
vid1 = '921be2f4-2b98-411e-890a-69bcabb2a5a1'
address1 = '10.1.2.2'
vid2 = '922be3f4-2b98-411e-890a-69bcabb2a5a2'
address2 = '10.1.2.3'
calls = [
mock.call('ip', 'link', 'add', 'veth%s' % vid1[:8],
'type', 'veth', 'peer', 'name',
'ns%s' % vid1[:8], run_as_root=True),
mock.call('ip', 'link', 'set', 'ns%s' % vid1[:8],
'address', address1, run_as_root=True),
mock.call('ip', 'link', 'add', 'veth%s' % vid2[:8],
'type', 'veth', 'peer', 'name',
'ns%s' % vid2[:8], run_as_root=True),
mock.call('ip', 'link', 'set', 'ns%s' % vid2[:8],
'address', address2, run_as_root=True),
]
network_info = [network_model.VIF(id=vid1, address=address1),
network_model.VIF(id=vid2, address=address2)]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.plug_vifs({'name': 'fake_instance'}, network_info)
ex.assert_has_calls(calls)
@mock.patch.object(docker_driver.DockerDriver,
'_find_container_by_uuid',
return_value={'id': 'my_vm'})
@mock.patch.object(docker_driver.DockerDriver,
'_find_container_pid',
return_value=7890)
def test_attach_vrouter(self, mock_find_by_uuid, mock_find_pid):
vid = '920be1f5-2b98-411e-890a-69bcabb2a5a0'
if_remote_name = 'ns%s' % vid[:8]
if_local_name = 'veth%s' % vid[:8]
address = '10.1.2.1'
gateway = '1.1.1.254'
fixed_ip = '1.1.1.42/24'
calls = [
mock.call('mkdir', '-p', '/var/run/netns', run_as_root=True),
mock.call('ln', '-sf', '/proc/7890/ns/net',
'/var/run/netns/my_vm', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'my_vm', 'ip', 'link',
'set', 'lo', 'up', run_as_root=True),
mock.call('ip', 'link', 'set', if_remote_name, 'netns', 'my_vm',
run_as_root=True),
mock.call('ip', 'link', 'set', if_local_name, 'up',
run_as_root=True),
mock.call('ip', 'netns', 'exec', 'my_vm', 'ip', 'link',
'set', if_remote_name, 'address', address,
run_as_root=True),
mock.call('ip', 'netns', 'exec', 'my_vm', 'ifconfig',
if_remote_name, fixed_ip, run_as_root=True),
mock.call('ip', 'netns', 'exec', 'my_vm', 'ip',
'route', 'replace', 'default', 'via', gateway,
'dev', if_remote_name, run_as_root=True),
mock.call('ip', 'netns', 'exec', 'my_vm', 'ip', 'link',
'set', if_remote_name, 'up', run_as_root=True)
]
network_info = [network_model.VIF(id=vid, address=address,
network=network_model.Network(
id='virtual-network-1',
subnets=[network_model.Subnet(
cidr='1.1.1.0/24',
gateway=network_model.IP(
address=gateway,
type='gateway'),
ips=[network_model.IP(
address='1.1.1.42',
type='fixed',
version=4)]
)]
))]
instance = dict(name='fake_instance', display_name='fake_vm',
hostname='fake_vm', host='linux',
project_id='e2d2ddc6-4e0f-4cd4-b846-3bad53093ec6',
uuid='d4b817fb-7885-4649-bad7-89302dde12e1')
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver._attach_vifs(instance, network_info)
ex.assert_has_calls(calls)
def test_unplug_vrouter(self):
vid = '920be1f4-2b98-411e-890a-69bcabb2a5a0'
address = '10.1.2.1'
network_info = [network_model.VIF(id=vid, address=address)]
driver = docker_driver.DockerDriver(object)
driver.unplug_vifs({'name': 'fake_instance'}, network_info)

View File

@ -1,488 +0,0 @@
# Copyright (c) 2013 VMware, Inc.
# 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.
import mock
from nova.network import model as network_model
from nova import test
from novadocker.virt.docker import driver as docker_driver
from novadocker.virt.docker import vifs
class DockerGenericVIFDriverTestCase(test.TestCase):
REQUIRES_LOCKING = True
gateway_bridge_4 = network_model.IP(address='10.11.12.1', type='gateway')
dns_bridge_4 = network_model.IP(address='8.8.8.8', type=None)
ips_bridge_4 = [network_model.IP(address='101.168.1.9', type='fixed',
version=4)]
subnet_bridge_4 = network_model.Subnet(cidr='10.11.1.0/24',
dns=[dns_bridge_4],
gateway=gateway_bridge_4,
ips=ips_bridge_4,
routes=None)
network_bridge = network_model.Network(id='network-id-xxx-yyy-zzz',
bridge='br100',
label=None,
subnets=[subnet_bridge_4],
bridge_interface='eth0')
vif_bridge = network_model.VIF(id='920be2f4-2b98-411e-890a-69bcabb2a5a0',
address='00:11:22:33:44:55',
network=network_bridge,
type=network_model.VIF_TYPE_BRIDGE)
network_iovisor = network_model.Network(id='network-id-xxx-yyy-zzz',
bridge='br100',
label='net1',
subnets=[subnet_bridge_4],
bridge_interface='eth0')
vif_iovisor = network_model.VIF(id='920be2f4-2b98-411e-890a-69bcabb2a5a0',
address='00:11:22:33:44:55',
network=network_iovisor,
type=network_model.VIF_TYPE_IOVISOR)
def setUp(self):
super(DockerGenericVIFDriverTestCase, self).setUp()
def fake_fe_random_mac(self):
return 'fe:16:3e:ff:ff:ff'
self.stubs.Set(vifs.DockerGenericVIFDriver,
'_fe_random_mac',
fake_fe_random_mac)
def test_plug_vifs_bridge(self):
calls = [
mock.call('ip', 'link', 'add', 'name', 'tap920be2f4-2b',
'type', 'veth', 'peer', 'name', 'ns920be2f4-2b',
run_as_root=True),
mock.call('ip', 'link', 'set', 'tap920be2f4-2b', 'address',
'fe:16:3e:ff:ff:ff', run_as_root=True),
mock.call('brctl', 'addif', 'br100', 'tap920be2f4-2b',
run_as_root=True),
mock.call('ip', 'link', 'set', 'tap920be2f4-2b', 'up',
run_as_root=True)
]
network_info = [self.vif_bridge]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.plug_vifs({'name': 'fake_instance'}, network_info)
ex.assert_has_calls(calls)
def test_plug_vifs_bridge_two_interfaces(self):
calls = [
# interface 1
mock.call('ip', 'link', 'add', 'name', 'tap920be2f4-2b',
'type', 'veth', 'peer', 'name', 'ns920be2f4-2b',
run_as_root=True),
mock.call('ip', 'link', 'set', 'tap920be2f4-2b', 'address',
'fe:16:3e:ff:ff:ff', run_as_root=True),
mock.call('brctl', 'addif', 'br100', 'tap920be2f4-2b',
run_as_root=True),
mock.call('ip', 'link', 'set', 'tap920be2f4-2b', 'up',
run_as_root=True),
# interface 2
mock.call('ip', 'link', 'add', 'name', 'tap920be2f4-2b',
'type', 'veth', 'peer', 'name', 'ns920be2f4-2b',
run_as_root=True),
mock.call('ip', 'link', 'set', 'tap920be2f4-2b', 'address',
'fe:16:3e:ff:ff:ff', run_as_root=True),
mock.call('brctl', 'addif', 'br100', 'tap920be2f4-2b',
run_as_root=True),
mock.call('ip', 'link', 'set', 'tap920be2f4-2b', 'up',
run_as_root=True),
]
network_info = [self.vif_bridge, self.vif_bridge]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.plug_vifs({'name': 'fake_instance'}, network_info)
ex.assert_has_calls(calls)
def test_plug_vifs_ovs(self):
iface_id = '920be2f4-2b98-411e-890a-69bcabb2a5a0'
calls = [
mock.call('ip', 'link', 'add', 'name', 'tap920be2f4-2b',
'type', 'veth', 'peer', 'name', 'ns920be2f4-2b',
run_as_root=True),
mock.call('ovs-vsctl', '--timeout=120', '--', '--if-exists',
'del-port', 'tap920be2f4-2b', '--', 'add-port',
'br-int', 'tap920be2f4-2b',
'--', 'set', 'Interface', 'tap920be2f4-2b',
'external-ids:iface-id=%s' % iface_id,
'external-ids:iface-status=active',
'external-ids:attached-mac=00:11:22:33:44:55',
'external-ids:vm-uuid=instance_uuid',
run_as_root=True),
mock.call('ip', 'link', 'set', 'tap920be2f4-2b', 'up',
run_as_root=True),
]
network_info = [
{'network': {'bridge': 'br-int',
'subnets': [{'gateway': {'address': '10.11.12.1'},
'cidr': '10.11.12.0/24',
'ips': [{'address': '10.11.12.3',
'type': 'fixed', 'version': 4}]
}]},
'address': '00:11:22:33:44:55',
'id': iface_id,
'type': network_model.VIF_TYPE_OVS}]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.plug_vifs({'name': 'fake_instance',
'uuid': 'instance_uuid'}, network_info)
ex.assert_has_calls(calls)
def test_plug_vifs_ovs_hybrid(self):
iface_id = '920be2f4-2b98-411e-890a-69bcabb2a5a0'
calls = [
mock.call('brctl', 'addbr', 'qbr920be2f4-2b', run_as_root=True),
mock.call('brctl', 'setfd', 'qbr920be2f4-2b', 0, run_as_root=True),
mock.call('brctl', 'stp', 'qbr920be2f4-2b', 'off',
run_as_root=True),
mock.call('tee', "/sys/class/net/qbr920be2f4-2b/bridge/multicast_"
"snooping", run_as_root=True, process_input='0',
check_exit_code=[0, 1]),
mock.call('ip', 'link', 'add', 'qvb920be2f4-2b', 'type',
'veth', 'peer', 'name', 'qvo920be2f4-2b',
run_as_root=True),
mock.call('ip', 'link', 'set', 'qvb920be2f4-2b', 'up',
run_as_root=True),
mock.call('ip', 'link', 'set', 'qvb920be2f4-2b', 'promisc', 'on',
run_as_root=True),
mock.call('ip', 'link', 'set', 'qvo920be2f4-2b', 'up',
run_as_root=True),
mock.call('ip', 'link', 'set', 'qvo920be2f4-2b', 'promisc', 'on',
run_as_root=True),
mock.call('ip', 'link', 'set', 'qbr920be2f4-2b', 'up',
run_as_root=True),
mock.call('brctl', 'addif', 'qbr920be2f4-2b', 'qvb920be2f4-2b',
run_as_root=True),
mock.call('ovs-vsctl', '--timeout=120', '--', '--if-exists',
'del-port', 'qvo920be2f4-2b', '--', 'add-port',
'br-int', 'qvo920be2f4-2b', '--', 'set', 'Interface',
'qvo920be2f4-2b', "external-ids:iface-id=920be2f4-2b98-"
"411e-890a-69bcabb2a5a0",
'external-ids:iface-status=active',
'external-ids:attached-mac=00:11:22:33:44:55',
'external-ids:vm-uuid=instance_uuid', run_as_root=True),
mock.call('ip', 'link', 'add', 'name', 'tap920be2f4-2b', 'type',
'veth', 'peer', 'name', 'ns920be2f4-2b',
run_as_root=True),
mock.call('brctl', 'addif', 'qbr920be2f4-2b', 'tap920be2f4-2b',
run_as_root=True),
mock.call('ip', 'link', 'set', 'tap920be2f4-2b', 'up',
run_as_root=True),
]
network_info = [
{'network': {'bridge': 'br-int',
'subnets': [{'gateway': {'address': '10.11.12.1'},
'cidr': '10.11.12.0/24',
'ips': [{'address': '10.11.12.3',
'type': 'fixed', 'version': 4}]
}]},
'address': '00:11:22:33:44:55',
'id': iface_id,
'details': {'port_filter': True, 'ovs_hybrid_plug': True},
'type': network_model.VIF_TYPE_OVS}]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.plug_vifs({'name': 'fake_instance',
'uuid': 'instance_uuid'}, network_info)
ex.assert_has_calls(calls)
def test_unplug_vifs_ovs(self):
iface_id = '920be2f4-2b98-411e-890a-69bcabb2a5a0'
calls = [
mock.call('ovs-vsctl', '--timeout=120', '--', '--if-exists',
'del-port', 'br-int', 'tap920be2f4-2b',
run_as_root=True)
]
network_info = [
{'network': {'bridge': 'br-int',
'subnets': [{'gateway': {'address': '10.11.12.1'},
'cidr': '10.11.12.0/24',
'ips': [{'address': '10.11.12.3',
'type': 'fixed', 'version': 4}]
}]},
'devname': 'tap920be2f4-2b',
'address': '00:11:22:33:44:55',
'id': iface_id,
'type': network_model.VIF_TYPE_OVS}]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.unplug_vifs({'name': 'fake_instance',
'uuid': 'instance_uuid'}, network_info)
ex.assert_has_calls(calls)
def test_plug_vifs_midonet(self):
iface_id = '920be2f4-2b98-411e-890a-69bcabb2a5a0'
host_side_veth = 'tap920be2f4-2b'
calls = [
mock.call('ip', 'link', 'add', 'name', host_side_veth,
'type', 'veth', 'peer', 'name', 'ns920be2f4-2b',
run_as_root=True),
mock.call('ip', 'link', 'set', host_side_veth, 'up',
run_as_root=True),
mock.call('mm-ctl', '--bind-port', iface_id, host_side_veth,
run_as_root=True),
]
network_info = [{'id': iface_id,
'type': network_model.VIF_TYPE_MIDONET}]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.plug_vifs({'name': 'fake_instance',
'uuid': 'instance_uuid'}, network_info)
ex.assert_has_calls(calls)
def test_unplug_vifs_midonet(self):
iface_id = '920be2f4-2b98-411e-890a-69bcabb2a5a0'
calls = [
mock.call('mm-ctl', '--unbind-port', iface_id, run_as_root=True)
]
network_info = [{'id': iface_id,
'type': network_model.VIF_TYPE_MIDONET}]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.unplug_vifs({'name': 'fake_instance',
'uuid': 'instance_uuid'}, network_info)
ex.assert_has_calls(calls)
def test_plug_vifs_iovisor(self):
iface_id = '920be2f4-2b98-411e-890a-69bcabb2a5a0'
tenant_id = 'tenant1'
calls = [
mock.call('ip', 'link', 'add', 'name', 'tap920be2f4-2b', 'type',
'veth', 'peer', 'name', 'ns920be2f4-2b',
run_as_root=True),
mock.call('ifc_ctl', 'gateway', 'add_port', 'tap920be2f4-2b',
run_as_root=True),
mock.call('ifc_ctl', 'gateway', 'ifup', 'tap920be2f4-2b',
'access_vm', "net1_" + iface_id, '00:11:22:33:44:55',
'pgtag2=network-id-xxx-yyy-zzz',
'pgtag1=%s' % tenant_id, run_as_root=True),
mock.call('ip', 'link', 'set', 'tap920be2f4-2b', 'up',
run_as_root=True),
]
network_info = [self.vif_iovisor]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.plug_vifs({'name': 'fake_instance',
'uuid': 'instance_uuid',
'project_id': tenant_id}, network_info)
ex.assert_has_calls(calls)
def test_unplug_vifs_iovisor(self):
iface_id = '920be2f4-2b98-411e-890a-69bcabb2a5a0'
tenant_id = 'tenant1'
calls = [
mock.call('ifc_ctl', 'gateway', 'ifdown', 'tap920be2f4-2b',
'access_vm', 'net1_' + iface_id, '00:11:22:33:44:55',
run_as_root=True),
mock.call('ifc_ctl', 'gateway', 'del_port', 'tap920be2f4-2b',
run_as_root=True)
]
network_info = [self.vif_iovisor]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.unplug_vifs({'name': 'fake_instance',
'uuid': 'instance_uuid',
'project_id': tenant_id}, network_info)
ex.assert_has_calls(calls)
def test_plug_vifs_windows(self):
network_info = [{'type': 'hyperv'}]
fake_instance = mock.sentinel.instance
with mock.patch.object(vifs.DockerGenericVIFDriver,
'plug_windows') as mock_plug_windows:
driver = docker_driver.DockerDriver(object)
driver.plug_vifs(fake_instance, network_info)
mock_plug_windows.assert_called_once_with(
fake_instance, {'type': 'hyperv'})
def test_unplug_vifs_windows(self):
network_info = [{'type': 'hyperv'}]
fake_instance = mock.sentinel.instance
with mock.patch.object(vifs.DockerGenericVIFDriver,
'unplug_windows') as mock_unplug_windows:
driver = docker_driver.DockerDriver(object)
driver.unplug_vifs(fake_instance, network_info)
mock_unplug_windows.assert_called_once_with(
fake_instance, {'type': 'hyperv'})
def test_unplug_vifs_ovs_hybrid(self):
iface_id = '920be2f4-2b98-411e-890a-69bcabb2a5a0'
calls = [
mock.call('ovs-vsctl', '--timeout=120', '--', '--if-exists',
'del-port', 'br-int', 'qvo920be2f4-2b',
run_as_root=True)
]
network_info = [
{'network': {'bridge': 'br-int',
'subnets': [{'gateway': {'address': '10.11.12.1'},
'cidr': '10.11.12.0/24',
'ips': [{'address': '10.11.12.3',
'type': 'fixed', 'version': 4}]
}]},
'devname': 'tap920be2f4-2b',
'address': '00:11:22:33:44:55',
'id': iface_id,
'details': {'port_filter': True, 'ovs_hybrid_plug': True},
'type': network_model.VIF_TYPE_OVS}]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver.unplug_vifs({'name': 'fake_instance',
'uuid': 'instance_uuid'}, network_info)
ex.assert_has_calls(calls)
@mock.patch.object(docker_driver.DockerDriver,
'_find_container_by_uuid',
return_value={'id': 'fake_id'})
@mock.patch.object(docker_driver.DockerDriver,
'_find_container_pid',
return_value=1234)
def test_attach_vifs(self, mock_find_by_uuid, mock_find_pid):
calls = [
mock.call('ln', '-sf', '/proc/1234/ns/net',
'/var/run/netns/fake_id', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ip', 'link',
'set', 'lo', 'up', run_as_root=True),
mock.call('ip', 'link', 'set', 'ns920be2f4-2b', 'netns',
'fake_id', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ip', 'link',
'set', 'ns920be2f4-2b', 'address', '00:11:22:33:44:55',
run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id',
'ip', 'addr', 'add', '10.11.12.3/24', 'dev',
'ns920be2f4-2b', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id',
'ip', 'link', 'set',
'ns920be2f4-2b', 'up', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ip', 'route',
'replace', 'default', 'via', '10.11.12.1', 'dev',
'ns920be2f4-2b', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ethtool', '--offload',
'ns920be2f4-2b', 'tso', 'off', run_as_root=True)
]
network_info = [
{'network': {'bridge': 'br100',
'subnets': [{'gateway': {'address': '10.11.12.1'},
'cidr': '10.11.12.0/24',
'ips': [{'address': '10.11.12.3',
'type': 'fixed', 'version': 4}]
}]},
'address': '00:11:22:33:44:55',
'id': '920be2f4-2b98-411e-890a-69bcabb2a5a0',
'type': network_model.VIF_TYPE_BRIDGE}]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver._attach_vifs({'uuid': 'fake_uuid'}, network_info)
ex.assert_has_calls(calls)
@mock.patch.object(docker_driver.DockerDriver,
'_find_container_by_uuid',
return_value={'id': 'fake_id'})
@mock.patch.object(docker_driver.DockerDriver,
'_find_container_pid',
return_value=1234)
def test_attach_vifs_two_interfaces(self, mock_find_by_uuid,
mock_find_pid):
calls = [
mock.call('ln', '-sf', '/proc/1234/ns/net',
'/var/run/netns/fake_id', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ip', 'link',
'set', 'lo', 'up', run_as_root=True),
# interface 1
mock.call('ip', 'link', 'set', 'ns920be2f4-2b', 'netns', 'fake_id',
run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ip', 'link',
'set', 'ns920be2f4-2b', 'address', '00:11:22:33:44:55',
run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id',
'ip', 'addr', 'add', '10.11.12.3/24', 'dev',
'ns920be2f4-2b', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id',
'ip', 'link', 'set',
'ns920be2f4-2b', 'up', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ip', 'route',
'replace', 'default', 'via', '10.11.12.1', 'dev',
'ns920be2f4-2b', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ethtool', '--offload',
'ns920be2f4-2b', 'tso', 'off', run_as_root=True),
# interface 2
mock.call('ip', 'link', 'set', 'ns920be2f4-2b', 'netns', 'fake_id',
run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ip', 'link',
'set', 'ns920be2f4-2b', 'address', '00:11:22:33:44:66',
run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id',
'ip', 'addr', 'add', '10.13.12.3/24', 'dev',
'ns920be2f4-2b', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id',
'ip', 'link', 'set',
'ns920be2f4-2b', 'up', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ip', 'route',
'replace', 'default', 'via', '10.13.12.1', 'dev',
'ns920be2f4-2b', run_as_root=True),
mock.call('ip', 'netns', 'exec', 'fake_id', 'ethtool', '--offload',
'ns920be2f4-2b', 'tso', 'off', run_as_root=True)
]
network_info = [
{'network': {'bridge': 'br100',
'subnets': [{'gateway': {'address': '10.11.12.1'},
'cidr': '10.11.12.0/24',
'ips': [{'address': '10.11.12.3',
'type': 'fixed', 'version': 4}],
}]},
'address': '00:11:22:33:44:55',
'type': network_model.VIF_TYPE_BRIDGE,
'id': '920be2f4-2b98-411e-890a-69bcabb2a5a0'},
{'network': {'bridge': 'br100',
'subnets': [{'gateway': {'address': '10.13.12.1'},
'cidr': '10.13.12.0/24',
'ips': [{'address': '10.13.12.3',
'type': 'fixed', 'version': 4}]
}]},
'address': '00:11:22:33:44:66',
'type': network_model.VIF_TYPE_BRIDGE,
'id': '920be2f4-2b98-411e-890a-69bcabb2a5a0'}]
with mock.patch('nova.utils.execute') as ex:
driver = docker_driver.DockerDriver(object)
driver._attach_vifs({'uuid': 'fake_uuid'}, network_info)
ex.assert_has_calls(calls)
@mock.patch.object(docker_driver, 'os')
def test_attach_vifs_hyperv(self, mock_os):
mock_os.name = 'nt'
with mock.patch.object(docker_driver.DockerDriver,
'_get_container_id') as mock_get_container_id:
driver = docker_driver.DockerDriver(object)
driver._attach_vifs(mock.sentinel.instance,
mock.sentinel.network_info)
self.assertFalse(mock_get_container_id.called)

View File

@ -1,54 +0,0 @@
# Copyright 2014 Docker, Inc
# 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.
import mock
from nova import test
from novadocker.virt import hostutils
class HostUtilsTestCase(test.NoDBTestCase):
def _test_sys_uptime(self, is_nt_os=False):
expect_uptime = ("fake_time up 0:00:00, 0 users, "
"load average: 0, 0, 0")
fake_tick_count = 0
fake_time = 'fake_time'
with mock.patch.multiple(hostutils, os=mock.DEFAULT, time=mock.DEFAULT,
ctypes=mock.DEFAULT, utils=mock.DEFAULT,
create=True) as lib_mocks:
lib_mocks['os'].name = 'nt' if is_nt_os else ''
lib_mocks['time'].strftime.return_value = fake_time
lib_mocks['utils'].execute.return_value = (expect_uptime, None)
tick_count = lib_mocks['ctypes'].windll.kernel32.GetTickCount64
tick_count.return_value = fake_tick_count
uptime = hostutils.sys_uptime()
if is_nt_os:
tick_count.assert_called_once_with()
lib_mocks['time'].strftime.assert_called_once_with("%H:%M:%S")
else:
lib_mocks['utils'].execute.assert_called_once_with(
'env', 'LANG=C', 'uptime')
self.assertEqual(expect_uptime, uptime)
def test_sys_uptime(self):
self._test_sys_uptime()
def test_nt_sys_uptime(self):
self._test_sys_uptime(is_nt_os=True)

View File

@ -1,22 +0,0 @@
# Copyright (c) 2013 dotCloud, Inc.
# 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.
"""
:mod:`docker` -- Nova support for Docker Hypervisor to run Linux containers
===========================================================================
"""
from novadocker.virt.docker import driver
DockerDriver = driver.DockerDriver

View File

@ -1,99 +0,0 @@
# Copyright (c) 2013 dotCloud, Inc.
# Copyright 2014 IBM Corp.
# 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.
import functools
import inspect
from oslo_config import cfg
import six
from docker import client
from docker import tls
CONF = cfg.CONF
DEFAULT_TIMEOUT_SECONDS = 120
DEFAULT_DOCKER_API_VERSION = '1.19'
def filter_data(f):
"""Decorator that post-processes data returned by Docker.
This will avoid any surprises with different versions of Docker.
"""
@functools.wraps(f, assigned=[])
def wrapper(*args, **kwds):
out = f(*args, **kwds)
def _filter(obj):
if isinstance(obj, list):
new_list = []
for o in obj:
new_list.append(_filter(o))
obj = new_list
if isinstance(obj, dict):
for k, v in obj.items():
if isinstance(k, six.string_types):
obj[k.lower()] = _filter(v)
return obj
return _filter(out)
return wrapper
class DockerHTTPClient(client.Client):
def __init__(self, url='unix://var/run/docker.sock'):
if (CONF.docker.cert_file or
CONF.docker.key_file):
client_cert = (CONF.docker.cert_file, CONF.docker.key_file)
else:
client_cert = None
if (CONF.docker.ca_file or
CONF.docker.api_insecure or
client_cert):
ssl_config = tls.TLSConfig(
client_cert=client_cert,
ca_cert=CONF.docker.ca_file,
verify=CONF.docker.api_insecure)
else:
ssl_config = False
super(DockerHTTPClient, self).__init__(
base_url=url,
version=DEFAULT_DOCKER_API_VERSION,
timeout=DEFAULT_TIMEOUT_SECONDS,
tls=ssl_config
)
self._setup_decorators()
def _setup_decorators(self):
for name, member in inspect.getmembers(self, inspect.ismethod):
if not name.startswith('_'):
setattr(self, name, filter_data(member))
def pause(self, container_id):
url = self._url("/containers/{0}/pause".format(container_id))
res = self._post(url)
return res.status_code == 204
def unpause(self, container_id):
url = self._url("/containers/{0}/unpause".format(container_id))
res = self._post(url)
return res.status_code == 204
def load_repository_file(self, name, path):
with open(path, 'rb') as fh:
self.load_image(fh)
def get_container_logs(self, container_id):
return self.attach(container_id, 1, 1, 0, 1)

View File

@ -1,806 +0,0 @@
# Copyright (c) 2013 dotCloud, Inc.
# Copyright 2014 IBM Corp.
# 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.
"""
A Docker Hypervisor which allows running Linux Containers instead of VMs.
"""
import os
import shutil
import socket
import time
import uuid
from docker import errors
from docker import utils as docker_utils
import eventlet
from oslo_config import cfg
from oslo_log import log
from oslo_utils import fileutils
from oslo_utils import importutils
from oslo_utils import units
from oslo_utils import versionutils
from nova.compute import arch
from nova.compute import flavors
from nova.compute import hv_type
from nova.compute import power_state
from nova.compute import task_states
from nova.compute import vm_mode
from nova import exception
from nova.image import glance
from nova import objects
from nova import utils
from nova import utils as nova_utils
from nova.virt import driver
from nova.virt import firewall
from nova.virt import hardware
from nova.virt import images
from novadocker.i18n import _, _LI, _LE, _LW
from novadocker.virt.docker import client as docker_client
from novadocker.virt.docker import hostinfo
from novadocker.virt.docker import network
from novadocker.virt import hostutils
CONF = cfg.CONF
CONF.import_opt('my_ip', 'nova.conf.netconf')
CONF.import_opt('instances_path', 'nova.compute.manager')
docker_opts = [
cfg.StrOpt('root_directory',
default='/var/lib/docker',
help='Path to use as the root of the Docker runtime.'),
cfg.StrOpt('host_url',
default='unix:///var/run/docker.sock',
help='tcp://host:port to bind/connect to or '
'unix://path/to/socket to use'),
cfg.BoolOpt('api_insecure',
default=False,
help='If set, ignore any SSL validation issues'),
cfg.StrOpt('ca_file',
help='Location of CA certificates file for '
'securing docker api requests (tlscacert).'),
cfg.StrOpt('cert_file',
help='Location of TLS certificate file for '
'securing docker api requests (tlscert).'),
cfg.StrOpt('key_file',
help='Location of TLS private key file for '
'securing docker api requests (tlskey).'),
cfg.StrOpt('vif_driver',
default='novadocker.virt.docker.vifs.DockerGenericVIFDriver'),
cfg.StrOpt('snapshots_directory',
default='$instances_path/snapshots',
help='Location where docker driver will temporarily store '
'snapshots.'),
cfg.BoolOpt('inject_key',
default=False,
help='Inject the ssh public key at boot time'),
cfg.StrOpt('shared_directory',
default=None,
help='Shared directory where glance images located. If '
'specified, docker will try to load the image from '
'the shared directory by image ID.'),
cfg.BoolOpt('privileged',
default=False,
help='Set true can own all root privileges in a container.'),
]
CONF.register_opts(docker_opts, 'docker')
LOG = log.getLogger(__name__)
class DockerDriver(driver.ComputeDriver):
"""Docker hypervisor driver."""
def __init__(self, virtapi):
super(DockerDriver, self).__init__(virtapi)
self._docker = None
vif_class = importutils.import_class(CONF.docker.vif_driver)
self.vif_driver = vif_class()
self.firewall_driver = firewall.load_driver(
default='nova.virt.firewall.NoopFirewallDriver')
# NOTE(zhangguoqing): For passing the nova unit tests
self.active_migrations = {}
@property
def docker(self):
if self._docker is None:
self._docker = docker_client.DockerHTTPClient(CONF.docker.host_url)
return self._docker
def init_host(self, host):
if self._is_daemon_running() is False:
raise exception.NovaException(
_('Docker daemon is not running or is not reachable'
' (check the rights on /var/run/docker.sock)'))
def _is_daemon_running(self):
return self.docker.ping()
def _start_firewall(self, instance, network_info):
self.firewall_driver.setup_basic_filtering(instance, network_info)
self.firewall_driver.prepare_instance_filter(instance, network_info)
self.firewall_driver.apply_instance_filter(instance, network_info)
def _stop_firewall(self, instance, network_info):
self.firewall_driver.unfilter_instance(instance, network_info)
def refresh_security_group_rules(self, security_group_id):
"""Refresh security group rules from data store.
Invoked when security group rules are updated.
:param security_group_id: The security group id.
"""
self.firewall_driver.refresh_security_group_rules(security_group_id)
def refresh_security_group_members(self, security_group_id):
"""Refresh security group members from data store.
Invoked when instances are added/removed to a security group.
:param security_group_id: The security group id.
"""
self.firewall_driver.refresh_security_group_members(security_group_id)
def refresh_provider_fw_rules(self):
"""Triggers a firewall update based on database changes."""
self.firewall_driver.refresh_provider_fw_rules()
def refresh_instance_security_rules(self, instance):
"""Refresh security group rules from data store.
Gets called when an instance gets added to or removed from
the security group the instance is a member of or if the
group gains or loses a rule.
:param instance: The instance object.
"""
self.firewall_driver.refresh_instance_security_rules(instance)
def ensure_filtering_rules_for_instance(self, instance, network_info):
"""Set up filtering rules.
:param instance: The instance object.
:param network_info: Instance network information.
"""
self.firewall_driver.setup_basic_filtering(instance, network_info)
self.firewall_driver.prepare_instance_filter(instance, network_info)
def unfilter_instance(self, instance, network_info):
"""Stop filtering instance.
:param instance: The instance object.
:param network_info: Instance network information.
"""
self.firewall_driver.unfilter_instance(instance, network_info)
def list_instances(self, inspect=False):
res = []
for container in self.docker.containers(all=True):
info = self.docker.inspect_container(container['id'])
if not info:
continue
if inspect:
res.append(info)
else:
res.append(info['Config'].get('Hostname'))
return res
def attach_interface(self, instance, image_meta, vif):
"""Attach an interface to the container."""
self.vif_driver.plug(instance, vif)
container_id = self._find_container_by_uuid(instance['uuid']).get('id')
self.vif_driver.attach(instance, vif, container_id)
def detach_interface(self, instance, vif):
"""Detach an interface from the container."""
self.vif_driver.unplug(instance, vif)
def plug_vifs(self, instance, network_info):
"""Plug VIFs into networks."""
for vif in network_info:
self.vif_driver.plug(instance, vif)
self._start_firewall(instance, network_info)
def _attach_vifs(self, instance, network_info):
"""Plug VIFs into container."""
if not network_info:
return
if os.name == 'nt':
return
container_id = self._get_container_id(instance)
if not container_id:
return
netns_path = '/var/run/netns'
if not os.path.exists(netns_path):
utils.execute(
'mkdir', '-p', netns_path, run_as_root=True)
nspid = self._find_container_pid(container_id)
if not nspid:
msg = _('Cannot find any PID under container "{0}"')
raise RuntimeError(msg.format(container_id))
netns_path = os.path.join(netns_path, container_id)
utils.execute(
'ln', '-sf', '/proc/{0}/ns/net'.format(nspid),
'/var/run/netns/{0}'.format(container_id),
run_as_root=True)
utils.execute('ip', 'netns', 'exec', container_id, 'ip', 'link',
'set', 'lo', 'up', run_as_root=True)
for vif in network_info:
self.vif_driver.attach(instance, vif, container_id)
def unplug_vifs(self, instance, network_info):
"""Unplug VIFs from networks."""
for vif in network_info:
self.vif_driver.unplug(instance, vif)
self._stop_firewall(instance, network_info)
def _encode_utf8(self, value):
return unicode(value).encode('utf-8')
def _find_container_by_uuid(self, uuid):
try:
name = "nova-" + uuid
containers = self.docker.containers(all=True,
filters={'name': name})
if containers:
# NOTE(dims): We expect only one item in the containers list
return self.docker.inspect_container(containers[0]['id'])
except errors.APIError as e:
if e.response.status_code != 404:
raise
return {}
def _get_container_id(self, instance):
return self._find_container_by_uuid(instance['uuid']).get('id')
def get_info(self, instance):
container = self._find_container_by_uuid(instance['uuid'])
if not container:
raise exception.InstanceNotFound(instance_id=instance['name'])
running = container['State'].get('Running')
mem = container['Config'].get('Memory', 0)
# NOTE(ewindisch): cgroups/lxc defaults to 1024 multiplier.
# see: _get_cpu_shares for further explaination
num_cpu = container['Config'].get('CpuShares', 0) / 1024
# FIXME(ewindisch): Improve use of statistics:
# For 'mem', we should expose memory.stat.rss, and
# for cpu_time we should expose cpuacct.stat.system,
# but these aren't yet exposed by Docker.
#
# Also see:
# docker/docs/sources/articles/runmetrics.md
info = hardware.InstanceInfo(
max_mem_kb=mem,
mem_kb=mem,
num_cpu=num_cpu,
cpu_time_ns=0,
state=(power_state.RUNNING if running
else power_state.SHUTDOWN)
)
return info
def get_host_stats(self, refresh=False):
hostname = socket.gethostname()
stats = self.get_available_resource(hostname)
stats['host_hostname'] = stats['hypervisor_hostname']
stats['host_name_label'] = stats['hypervisor_hostname']
return stats
def get_available_nodes(self, refresh=False):
hostname = socket.gethostname()
return [hostname]
def get_available_resource(self, nodename):
if not hasattr(self, '_nodename'):
self._nodename = nodename
if nodename != self._nodename:
LOG.error(_('Hostname has changed from %(old)s to %(new)s. '
'A restart is required to take effect.'
), {'old': self._nodename,
'new': nodename})
memory = hostinfo.get_memory_usage()
disk = hostinfo.get_disk_usage()
stats = {
'vcpus': hostinfo.get_total_vcpus(),
'vcpus_used': hostinfo.get_vcpus_used(self.list_instances(True)),
'memory_mb': memory['total'] / units.Mi,
'memory_mb_used': memory['used'] / units.Mi,
'local_gb': disk['total'] / units.Gi,
'local_gb_used': disk['used'] / units.Gi,
'disk_available_least': disk['available'] / units.Gi,
'hypervisor_type': 'docker',
'hypervisor_version': versionutils.convert_version_to_int('1.0'),
'hypervisor_hostname': self._nodename,
'cpu_info': '?',
'numa_topology': None,
'supported_instances': [
(arch.I686, hv_type.DOCKER, vm_mode.EXE),
(arch.X86_64, hv_type.DOCKER, vm_mode.EXE)
]
}
return stats
def _find_container_pid(self, container_id):
n = 0
while True:
# NOTE(samalba): We wait for the process to be spawned inside the
# container in order to get the the "container pid". This is
# usually really fast. To avoid race conditions on a slow
# machine, we allow 10 seconds as a hard limit.
if n > 20:
return
info = self.docker.inspect_container(container_id)
if info:
pid = info['State']['Pid']
# Pid is equal to zero if it isn't assigned yet
if pid:
return pid
time.sleep(0.5)
n += 1
def _get_memory_limit_bytes(self, instance):
if isinstance(instance, objects.Instance):
return instance.get_flavor().memory_mb * units.Mi
else:
system_meta = utils.instance_sys_meta(instance)
return int(system_meta.get(
'instance_type_memory_mb', 0)) * units.Mi
def _get_image_name(self, context, instance, image):
fmt = image.container_format
if fmt != 'docker':
msg = _('Image container format not supported ({0})')
raise exception.InstanceDeployFailure(msg.format(fmt),
instance_id=instance['name'])
return image.name
def _pull_missing_image(self, context, image_meta, instance):
msg = 'Image name "%s" does not exist, fetching it...'
LOG.debug(msg, image_meta.name)
shared_directory = CONF.docker.shared_directory
if (shared_directory and
os.path.exists(os.path.join(shared_directory,
image_meta.id))):
LOG.debug('Found %s in shared_directory', image_meta.id)
try:
LOG.debug('Loading repository file into docker %s',
self._encode_utf8(image_meta.name))
self.docker.load_repository_file(
self._encode_utf8(image_meta.name),
os.path.join(shared_directory, image_meta.id))
return self.docker.inspect_image(
self._encode_utf8(image_meta.name))
except Exception as e:
# If failed to load image from shared_directory, continue
# to download the image from glance then load.
LOG.warning(_('Cannot load repository file from shared '
'directory: %s'),
e, instance=instance, exc_info=True)
# TODO(imain): It would be nice to do this with file like object
# passing but that seems a bit complex right now.
snapshot_directory = CONF.docker.snapshots_directory
fileutils.ensure_tree(snapshot_directory)
with utils.tempdir(dir=snapshot_directory) as tmpdir:
try:
out_path = os.path.join(tmpdir, uuid.uuid4().hex)
LOG.debug('Fetching image with id %s from glance',
image_meta.id)
images.fetch(context, image_meta.id, out_path,
instance['user_id'], instance['project_id'])
LOG.debug('Loading repository file into docker %s',
self._encode_utf8(image_meta.name))
self.docker.load_repository_file(
self._encode_utf8(image_meta.name),
out_path
)
return self.docker.inspect_image(
self._encode_utf8(image_meta.name))
except Exception as e:
LOG.warning(_('Cannot load repository file: %s'),
e, instance=instance, exc_info=True)
msg = _('Cannot load repository file: {0}')
raise exception.NovaException(msg.format(e),
instance_id=image_meta.name)
def _extract_dns_entries(self, network_info):
dns = []
if network_info:
for net in network_info:
subnets = net['network'].get('subnets', [])
for subnet in subnets:
dns_entries = subnet.get('dns', [])
for dns_entry in dns_entries:
if 'address' in dns_entry:
dns.append(dns_entry['address'])
return dns if dns else None
def _get_key_binds(self, container_id, instance):
binds = None
# Handles the key injection.
if CONF.docker.inject_key and instance.get('key_data'):
key = str(instance['key_data'])
mount_origin = self._inject_key(container_id, key)
binds = {mount_origin: {'bind': '/root/.ssh', 'ro': True}}
return binds
def _neutron_failed_callback(self, event_name, instance):
LOG.error(_LE('Neutron Reported failure on event '
'%(event)s for instance %(uuid)s'),
{'event': event_name, 'uuid': instance.uuid},
instance=instance)
if CONF.vif_plugging_is_fatal:
raise exception.VirtualInterfaceCreateException()
def _get_neutron_events(self, network_info):
# NOTE(danms): We need to collect any VIFs that are currently
# down that we expect a down->up event for. Anything that is
# already up will not undergo that transition, and for
# anything that might be stale (cache-wise) assume it's
# already up so we don't block on it.
return [('network-vif-plugged', vif['id'])
for vif in network_info if vif.get('active', True) is False]
def _start_container(self, container_id, instance, network_info=None):
binds = self._get_key_binds(container_id, instance)
dns = self._extract_dns_entries(network_info)
self.docker.start(container_id, binds=binds, dns=dns,
privileged=CONF.docker.privileged)
if not network_info:
return
timeout = CONF.vif_plugging_timeout
if (utils.is_neutron() and timeout):
events = self._get_neutron_events(network_info)
else:
events = []
try:
with self.virtapi.wait_for_instance_event(
instance, events, deadline=timeout,
error_callback=self._neutron_failed_callback):
self.plug_vifs(instance, network_info)
self._attach_vifs(instance, network_info)
except eventlet.timeout.Timeout:
LOG.warn(_LW('Timeout waiting for vif plugging callback for '
'instance %(uuid)s'), {'uuid': instance['name']})
if CONF.vif_plugging_is_fatal:
self.docker.kill(container_id)
self.docker.remove_container(container_id, force=True)
raise exception.InstanceDeployFailure(
'Timeout waiting for vif plugging',
instance_id=instance['name'])
except (Exception) as e:
LOG.warning(_('Cannot setup network: %s'),
e, instance=instance, exc_info=True)
msg = _('Cannot setup network: {0}')
self.docker.kill(container_id)
self.docker.remove_container(container_id, force=True)
raise exception.InstanceDeployFailure(msg.format(e),
instance_id=instance['name'])
def spawn(self, context, instance, image_meta, injected_files,
admin_password, network_info=None, block_device_info=None,
flavor=None):
image_name = self._get_image_name(context, instance, image_meta)
args = {
'hostname': instance['name'],
'mem_limit': self._get_memory_limit_bytes(instance),
'cpu_shares': self._get_cpu_shares(instance),
'network_disabled': True,
}
try:
image = self.docker.inspect_image(self._encode_utf8(image_name))
except errors.APIError:
image = None
if not image:
image = self._pull_missing_image(context, image_meta, instance)
# Glance command-line overrides any set in the Docker image
if (image_meta is not None and
image_meta.properties.get("os_command_line") is not None):
args['command'] = image_meta.properties.get("os_command_line")
if 'metadata' in instance:
args['environment'] = nova_utils.instance_meta(instance)
container_id = self._create_container(instance, image_name, args)
if not container_id:
raise exception.InstanceDeployFailure(
_('Cannot create container'),
instance_id=instance['name'])
self._start_container(container_id, instance, network_info)
def _inject_key(self, id, key):
if isinstance(id, dict):
id = id.get('id')
sshdir = os.path.join(CONF.instances_path, id, '.ssh')
key_data = ''.join([
'\n',
'# The following ssh key was injected by Nova',
'\n',
key.strip(),
'\n',
])
fileutils.ensure_tree(sshdir)
keys_file = os.path.join(sshdir, 'authorized_keys')
with open(keys_file, 'a') as f:
f.write(key_data)
os.chmod(sshdir, 0o700)
os.chmod(keys_file, 0o600)
return sshdir
def _cleanup_key(self, instance, id):
if isinstance(id, dict):
id = id.get('id')
dir = os.path.join(CONF.instances_path, id)
if os.path.exists(dir):
LOG.info(_LI('Deleting instance files %s'), dir,
instance=instance)
try:
shutil.rmtree(dir)
except OSError as e:
LOG.error(_LE('Failed to cleanup directory %(target)s: '
'%(e)s'), {'target': dir, 'e': e},
instance=instance)
def restore(self, instance):
container_id = self._get_container_id(instance)
if not container_id:
return
self._start_container(container_id, instance)
def _stop(self, container_id, instance, timeout=5):
try:
self.docker.stop(container_id, max(timeout, 5))
except errors.APIError as e:
if 'Unpause the container before stopping' not in e.explanation:
LOG.warning(_('Cannot stop container: %s'),
e, instance=instance, exc_info=True)
raise
self.docker.unpause(container_id)
self.docker.stop(container_id, timeout)
def soft_delete(self, instance):
container_id = self._get_container_id(instance)
if not container_id:
return
self._stop(container_id, instance)
def destroy(self, context, instance, network_info, block_device_info=None,
destroy_disks=True, migrate_data=None):
self.soft_delete(instance)
self.cleanup(context, instance, network_info,
block_device_info, destroy_disks)
def cleanup(self, context, instance, network_info, block_device_info=None,
destroy_disks=True, migrate_data=None, destroy_vifs=True):
"""Cleanup after instance being destroyed by Hypervisor."""
container_id = self._get_container_id(instance)
if not container_id:
self.unplug_vifs(instance, network_info)
return
self.docker.remove_container(container_id, force=True)
network.teardown_network(container_id)
self.unplug_vifs(instance, network_info)
if CONF.docker.inject_key:
self._cleanup_key(instance, container_id)
def reboot(self, context, instance, network_info, reboot_type,
block_device_info=None, bad_volumes_callback=None):
container_id = self._get_container_id(instance)
if not container_id:
return
self._stop(container_id, instance)
try:
network.teardown_network(container_id)
if network_info:
self.unplug_vifs(instance, network_info)
except Exception as e:
LOG.warning(_('Cannot destroy the container network'
' during reboot {0}').format(e),
exc_info=True)
return
binds = self._get_key_binds(container_id, instance)
dns = self._extract_dns_entries(network_info)
self.docker.start(container_id, binds=binds, dns=dns)
try:
if network_info:
self.plug_vifs(instance, network_info)
self._attach_vifs(instance, network_info)
except Exception as e:
LOG.warning(_('Cannot setup network on reboot: {0}'), e,
exc_info=True)
return
def power_on(self, context, instance, network_info,
block_device_info=None):
container_id = self._get_container_id(instance)
if not container_id:
return
binds = self._get_key_binds(container_id, instance)
dns = self._extract_dns_entries(network_info)
self.docker.start(container_id, binds=binds, dns=dns)
if not network_info:
return
try:
self.plug_vifs(instance, network_info)
self._attach_vifs(instance, network_info)
except Exception as e:
LOG.debug(_('Cannot setup network: %s'),
e, instance=instance, exc_info=True)
msg = _('Cannot setup network: {0}')
self.docker.kill(container_id)
self.docker.remove_container(container_id, force=True)
raise exception.InstanceDeployFailure(msg.format(e),
instance_id=instance['name'])
def power_off(self, instance, timeout=0, retry_interval=0):
container_id = self._get_container_id(instance)
if not container_id:
return
self._stop(container_id, instance, timeout)
def pause(self, instance):
"""Pause the specified instance.
:param instance: nova.objects.instance.Instance
"""
try:
cont_id = self._get_container_id(instance)
if not self.docker.pause(cont_id):
raise exception.NovaException
except Exception as e:
LOG.debug(_('Error pause container: %s'),
e, instance=instance, exc_info=True)
msg = _('Cannot pause container: {0}')
raise exception.NovaException(msg.format(e),
instance_id=instance['name'])
def unpause(self, instance):
"""Unpause paused VM instance.
:param instance: nova.objects.instance.Instance
"""
try:
cont_id = self._get_container_id(instance)
if not self.docker.unpause(cont_id):
raise exception.NovaException
except Exception as e:
LOG.debug(_('Error unpause container: %s'),
e, instance=instance, exc_info=True)
msg = _('Cannot unpause container: {0}')
raise exception.NovaException(msg.format(e),
instance_id=instance['name'])
def get_console_output(self, context, instance):
container_id = self._get_container_id(instance)
if not container_id:
return ''
return self.docker.get_container_logs(container_id)
def snapshot(self, context, instance, image_href, update_task_state):
container_id = self._get_container_id(instance)
if not container_id:
raise exception.InstanceNotRunning(instance_id=instance['uuid'])
update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD)
(image_service, image_id) = glance.get_remote_image_service(
context, image_href)
image = image_service.show(context, image_id)
if ':' not in image['name']:
commit_name = self._encode_utf8(image['name'])
tag = 'latest'
else:
parts = self._encode_utf8(image['name']).rsplit(':', 1)
commit_name = parts[0]
tag = parts[1]
self.docker.commit(container_id, repository=commit_name, tag=tag)
update_task_state(task_state=task_states.IMAGE_UPLOADING,
expected_state=task_states.IMAGE_PENDING_UPLOAD)
metadata = {
'is_public': False,
'status': 'active',
'disk_format': 'raw',
'container_format': 'docker',
'name': image['name'],
'properties': {
'image_location': 'snapshot',
'image_state': 'available',
'status': 'available',
'owner_id': instance['project_id'],
'ramdisk_id': instance['ramdisk_id']
}
}
if instance['os_type']:
metadata['properties']['os_type'] = instance['os_type']
try:
raw = self.docker.get_image(commit_name)
# Patch the seek/tell as urllib3 throws UnsupportedOperation
raw.seek = lambda x=None, y=None: None
raw.tell = lambda: None
image_service.update(context, image_href, metadata, raw)
except Exception as e:
LOG.debug(_('Error saving image: %s'),
e, instance=instance, exc_info=True)
msg = _('Error saving image: {0}')
raise exception.NovaException(msg.format(e),
instance_id=instance['name'])
def _get_cpu_shares(self, instance):
"""Get allocated CPUs from configured flavor.
Docker/lxc supports relative CPU allocation.
cgroups specifies following:
/sys/fs/cgroup/lxc/cpu.shares = 1024
/sys/fs/cgroup/cpu.shares = 1024
For that reason we use 1024 as multiplier.
This multiplier allows to divide the CPU
resources fair with containers started by
the user (e.g. docker registry) which has
the default CpuShares value of zero.
"""
if isinstance(instance, objects.Instance):
flavor = instance.get_flavor()
else:
flavor = flavors.extract_flavor(instance)
return int(flavor['vcpus']) * 1024
def _create_container(self, instance, image_name, args):
name = "nova-" + instance['uuid']
hostname = args.pop('hostname', None)
cpu_shares = args.pop('cpu_shares', None)
network_disabled = args.pop('network_disabled', False)
environment = args.pop('environment', None)
command = args.pop('command', None)
host_config = docker_utils.create_host_config(**args)
return self.docker.create_container(image_name,
name=self._encode_utf8(name),
hostname=hostname,
cpu_shares=cpu_shares,
network_disabled=network_disabled,
environment=environment,
command=command,
host_config=host_config)
def get_host_uptime(self):
return hostutils.sys_uptime()

View File

@ -1,74 +0,0 @@
# Copyright (c) 2013 dotCloud, Inc.
# 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.
import multiprocessing
import os
from oslo_config import cfg
import psutil
CONF = cfg.CONF
def statvfs():
docker_path = CONF.docker.root_directory
if not os.path.exists(docker_path):
docker_path = '/'
return psutil.disk_usage(docker_path)
def get_disk_usage():
# This is the location where Docker stores its containers. It's currently
# hardcoded in Docker so it's not configurable yet.
st = statvfs()
return {
'total': st.total,
'available': st.free,
'used': st.used
}
def get_total_vcpus():
return multiprocessing.cpu_count()
def get_vcpus_used(containers):
total_vcpus_used = 0
for container in containers:
if isinstance(container, dict):
total_vcpus_used += container.get('Config', {}).get(
'CpuShares', 0) / 1024
return total_vcpus_used
def get_memory_usage():
vmem = psutil.virtual_memory()
return {
'total': vmem.total,
'used': vmem.used
}
def get_mounts():
with open('/proc/mounts') as f:
return f.readlines()
def get_cgroup_devices_path():
for ln in get_mounts():
fields = ln.split(' ')
if fields[2] == 'cgroup' and 'devices' in fields[3].split(','):
return fields[1]

View File

@ -1,65 +0,0 @@
# Copyright 2014 OpenStack Foundation
# 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.
import os
from oslo_concurrency import processutils
from oslo_log import log
from nova import exception
from nova import utils
from novadocker.i18n import _
LOG = log.getLogger(__name__)
def teardown_network(container_id):
if os.name == 'nt':
return
try:
output, err = utils.execute('ip', '-o', 'netns', 'list')
for line in output.split('\n'):
if container_id == line.strip():
utils.execute('ip', 'netns', 'delete', container_id,
run_as_root=True)
break
except processutils.ProcessExecutionError:
LOG.warning(_('Cannot remove network namespace, netns id: %s'),
container_id)
def find_fixed_ip(instance, network_info):
for subnet in network_info['subnets']:
netmask = subnet['cidr'].split('/')[1]
for ip in subnet['ips']:
if ip['type'] == 'fixed' and ip['address']:
return ip['address'] + "/" + netmask
raise exception.InstanceDeployFailure(_('Cannot find fixed ip'),
instance_id=instance['uuid'])
def find_gateway(instance, network_info):
for subnet in network_info['subnets']:
return subnet['gateway']['address']
raise exception.InstanceDeployFailure(_('Cannot find gateway'),
instance_id=instance['uuid'])
# NOTE(arosen) - this method should be removed after it's moved into the
# linux_net code in nova.
def get_ovs_interfaceid(vif):
return vif.get('ovs_interfaceid') or vif['id']

View File

@ -1,172 +0,0 @@
# Copyright (C) 2014 Juniper Networks, Inc
# 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.
import eventlet
from contrail_vrouter_api.vrouter_api import ContrailVRouterApi
from nova.network import linux_net
from nova import utils
from oslo_log import log as logging
from oslo_service import loopingcall
from novadocker.i18n import _
LOG = logging.getLogger(__name__)
class OpenContrailVIFDriver(object):
def __init__(self):
self._vrouter_semaphore = eventlet.semaphore.Semaphore()
self._vrouter_client = ContrailVRouterApi(
doconnect=True, semaphore=self._vrouter_semaphore)
timer = loopingcall.FixedIntervalLoopingCall(self._keep_alive)
timer.start(interval=2)
def _keep_alive(self):
self._vrouter_client.periodic_connection_check()
def plug(self, instance, vif):
vif_type = vif['type']
LOG.debug('Plug vif_type=%(vif_type)s instance=%(instance)s '
'vif=%(vif)s',
{'vif_type': vif_type, 'instance': instance,
'vif': vif})
if_local_name = 'veth%s' % vif['id'][:8]
if_remote_name = 'ns%s' % vif['id'][:8]
# Device already exists so return.
if linux_net.device_exists(if_local_name):
return
undo_mgr = utils.UndoManager()
try:
utils.execute('ip', 'link', 'add', if_local_name, 'type', 'veth',
'peer', 'name', if_remote_name, run_as_root=True)
undo_mgr.undo_with(lambda: utils.execute(
'ip', 'link', 'delete', if_local_name, run_as_root=True))
utils.execute('ip', 'link', 'set', if_remote_name, 'address',
vif['address'], run_as_root=True)
except Exception:
LOG.exception("Failed to configure network")
msg = _('Failed to setup the network, rolling back')
undo_mgr.rollback_and_reraise(msg=msg, instance=instance)
def attach(self, instance, vif, container_id):
vif_type = vif['type']
LOG.debug('Attach vif_type=%(vif_type)s instance=%(instance)s '
'vif=%(vif)s',
{'vif_type': vif_type, 'instance': instance,
'vif': vif})
if_local_name = 'veth%s' % vif['id'][:8]
if_remote_name = 'ns%s' % vif['id'][:8]
undo_mgr = utils.UndoManager()
undo_mgr.undo_with(lambda: utils.execute(
'ip', 'link', 'delete', if_local_name, run_as_root=True))
ipv4_address = '0.0.0.0'
ipv6_address = None
if 'subnets' in vif['network']:
subnets = vif['network']['subnets']
for subnet in subnets:
ips = subnet['ips'][0]
if (ips['version'] == 4):
if ips['address'] is not None:
ipv4_address = ips['address']
ipv4_netmask = subnet['cidr'].split('/')[1]
ipv4_gateway = subnet['gateway']['address']
if (ips['version'] == 6):
if ips['address'] is not None:
ipv6_address = ips['address']
ipv6_netmask = subnet['cidr'].split('/')[1]
ipv6_gateway = subnet['gateway']['address']
params = {
'ip_address': ipv4_address,
'vn_id': vif['network']['id'],
'display_name': instance['display_name'],
'hostname': instance['hostname'],
'host': instance['host'],
'vm_project_id': instance['project_id'],
'port_type': 'NovaVMPort',
'ip6_address': ipv6_address,
}
try:
utils.execute('ip', 'link', 'set', if_remote_name, 'netns',
container_id, run_as_root=True)
result = self._vrouter_client.add_port(
instance['uuid'], vif['id'],
if_local_name, vif['address'], **params)
if not result:
# follow the exception path
raise RuntimeError('add_port returned %s' % str(result))
utils.execute('ip', 'link', 'set', if_local_name, 'up',
run_as_root=True)
except Exception:
LOG.exception("Failed to attach the network")
msg = _('Failed to attach the network, rolling back')
undo_mgr.rollback_and_reraise(msg=msg, instance=instance)
try:
utils.execute('ip', 'netns', 'exec', container_id, 'ip', 'link',
'set', if_remote_name, 'address', vif['address'],
run_as_root=True)
if ipv6_address:
ip = ipv6_address + "/" + ipv6_netmask
gateway = ipv6_gateway
utils.execute('ip', 'netns', 'exec', container_id, 'ifconfig',
if_remote_name, 'inet6', 'add', ip,
run_as_root=True)
utils.execute('ip', 'netns', 'exec', container_id, 'ip', '-6',
'route', 'replace', 'default', 'via', gateway,
'dev', if_remote_name, run_as_root=True)
if ipv4_address != '0.0.0.0':
ip = ipv4_address + "/" + ipv4_netmask
gateway = ipv4_gateway
utils.execute('ip', 'netns', 'exec', container_id, 'ifconfig',
if_remote_name, ip, run_as_root=True)
utils.execute('ip', 'netns', 'exec', container_id, 'ip',
'route', 'replace', 'default', 'via', gateway,
'dev', if_remote_name, run_as_root=True)
utils.execute('ip', 'netns', 'exec', container_id, 'ip', 'link',
'set', if_remote_name, 'up', run_as_root=True)
except Exception:
LOG.exception(_("Failed to attach vif"), instance=instance)
def unplug(self, instance, vif):
vif_type = vif['type']
if_local_name = 'veth%s' % vif['id'][:8]
LOG.debug('Unplug vif_type=%(vif_type)s instance=%(instance)s '
'vif=%(vif)s',
{'vif_type': vif_type, 'instance': instance,
'vif': vif})
try:
self._vrouter_client.delete_port(vif['id'])
if linux_net.device_exists(if_local_name):
utils.execute('ip', 'link', 'delete', if_local_name,
run_as_root=True)
except Exception:
LOG.exception(_("Delete port failed"), instance=instance)

View File

@ -1,491 +0,0 @@
# Copyright (C) 2013 VMware, Inc
# Copyright 2011 OpenStack Foundation
# 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.
from oslo_concurrency import processutils
from oslo_log import log as logging
from nova import exception
from nova.network import linux_net
from nova.network import manager
from nova.network import model as network_model
from nova import utils
from novadocker.i18n import _
from novadocker.virt.docker import network
from oslo_config import cfg
import random
# We need config opts from manager, but pep8 complains, this silences it.
assert manager
CONF = cfg.CONF
CONF.import_opt('my_ip', 'nova.conf.netconf')
CONF.import_opt('vlan_interface', 'nova.manager')
CONF.import_opt('flat_interface', 'nova.manager')
CONF.import_opt('network_device_mtu', 'nova.objects.network')
LOG = logging.getLogger(__name__)
class DockerGenericVIFDriver(object):
def plug(self, instance, vif):
vif_type = vif['type']
LOG.debug('plug vif_type=%(vif_type)s instance=%(instance)s '
'vif=%(vif)s',
{'vif_type': vif_type, 'instance': instance,
'vif': vif})
if vif_type is None:
raise exception.NovaException(
_("vif_type parameter must be present "
"for this vif_driver implementation"))
if vif_type == network_model.VIF_TYPE_BRIDGE:
self.plug_bridge(instance, vif)
elif vif_type == network_model.VIF_TYPE_OVS:
if self.ovs_hybrid_required(vif):
self.plug_ovs_hybrid(instance, vif)
else:
self.plug_ovs(instance, vif)
elif vif_type == network_model.VIF_TYPE_MIDONET:
self.plug_midonet(instance, vif)
elif vif_type == network_model.VIF_TYPE_IOVISOR:
self.plug_iovisor(instance, vif)
elif vif_type == 'hyperv':
self.plug_windows(instance, vif)
else:
raise exception.NovaException(
_("Unexpected vif_type=%s") % vif_type)
def plug_windows(self, instance, vif):
pass
def plug_iovisor(self, instance, vif):
"""Plug docker vif into IOvisor
Creates a port on IOvisor and onboards the interface
"""
if_local_name = 'tap%s' % vif['id'][:11]
if_remote_name = 'ns%s' % vif['id'][:11]
iface_id = vif['id']
net_id = vif['network']['id']
tenant_id = instance['project_id']
# Device already exists so return.
if linux_net.device_exists(if_local_name):
return
undo_mgr = utils.UndoManager()
try:
utils.execute('ip', 'link', 'add', 'name', if_local_name, 'type',
'veth', 'peer', 'name', if_remote_name,
run_as_root=True)
utils.execute('ifc_ctl', 'gateway', 'add_port', if_local_name,
run_as_root=True)
utils.execute('ifc_ctl', 'gateway', 'ifup', if_local_name,
'access_vm',
vif['network']['label'] + "_" + iface_id,
vif['address'], 'pgtag2=%s' % net_id,
'pgtag1=%s' % tenant_id, run_as_root=True)
utils.execute('ip', 'link', 'set', if_local_name, 'up',
run_as_root=True)
except Exception:
LOG.exception("Failed to configure network on IOvisor")
msg = _('Failed to setup the network, rolling back')
undo_mgr.rollback_and_reraise(msg=msg, instance=instance)
def plug_ovs(self, instance, vif):
if_local_name = 'tap%s' % vif['id'][:11]
if_remote_name = 'ns%s' % vif['id'][:11]
bridge = vif['network']['bridge']
# Device already exists so return.
if linux_net.device_exists(if_local_name):
return
undo_mgr = utils.UndoManager()
try:
utils.execute('ip', 'link', 'add', 'name', if_local_name, 'type',
'veth', 'peer', 'name', if_remote_name,
run_as_root=True)
linux_net.create_ovs_vif_port(bridge, if_local_name,
network.get_ovs_interfaceid(vif),
vif['address'],
instance['uuid'])
utils.execute('ip', 'link', 'set', if_local_name, 'up',
run_as_root=True)
except Exception:
LOG.exception("Failed to configure network")
msg = _('Failed to setup the network, rolling back')
undo_mgr.rollback_and_reraise(msg=msg, instance=instance)
def plug_midonet(self, instance, vif):
"""Plug into MidoNet's network port
This accomplishes binding of the vif to a MidoNet virtual port
"""
if_local_name = 'tap%s' % vif['id'][:11]
if_remote_name = 'ns%s' % vif['id'][:11]
port_id = network.get_ovs_interfaceid(vif)
# Device already exists so return.
if linux_net.device_exists(if_local_name):
return
undo_mgr = utils.UndoManager()
try:
utils.execute('ip', 'link', 'add', 'name', if_local_name, 'type',
'veth', 'peer', 'name', if_remote_name,
run_as_root=True)
undo_mgr.undo_with(lambda: utils.execute(
'ip', 'link', 'delete', if_local_name, run_as_root=True))
utils.execute('ip', 'link', 'set', if_local_name, 'up',
run_as_root=True)
utils.execute('mm-ctl', '--bind-port', port_id, if_local_name,
run_as_root=True)
except Exception:
LOG.exception("Failed to configure network")
msg = _('Failed to setup the network, rolling back')
undo_mgr.rollback_and_reraise(msg=msg, instance=instance)
def plug_ovs_hybrid(self, instance, vif):
"""Plug using hybrid strategy
Create a per-VIF linux bridge, then link that bridge to the OVS
integration bridge via a veth device, setting up the other end
of the veth device just like a normal OVS port. Then boot the
VIF on the linux bridge. and connect the tap port to linux bridge
"""
if_local_name = 'tap%s' % vif['id'][:11]
if_remote_name = 'ns%s' % vif['id'][:11]
iface_id = self.get_ovs_interfaceid(vif)
br_name = self.get_br_name(vif['id'])
v1_name, v2_name = self.get_veth_pair_names(vif['id'])
# Device already exists so return.
if linux_net.device_exists(if_local_name):
return
undo_mgr = utils.UndoManager()
try:
if not linux_net.device_exists(br_name):
utils.execute('brctl', 'addbr', br_name, run_as_root=True)
# Incase of failure undo the Steps
# Deleting/Undoing the interface will delete all
# associated resources
undo_mgr.undo_with(lambda: utils.execute(
'brctl', 'delbr', br_name, run_as_root=True))
# LOG.exception('Throw Test exception with bridgename %s'
# % br_name)
utils.execute('brctl', 'setfd', br_name, 0, run_as_root=True)
utils.execute('brctl', 'stp', br_name, 'off', run_as_root=True)
utils.execute('tee',
('/sys/class/net/%s/bridge/multicast_snooping' %
br_name),
process_input='0',
run_as_root=True,
check_exit_code=[0, 1])
if not linux_net.device_exists(v2_name):
linux_net._create_veth_pair(v1_name, v2_name)
undo_mgr.undo_with(lambda: utils.execute(
'ip', 'link', 'delete', v1_name, run_as_root=True))
utils.execute('ip', 'link', 'set', br_name, 'up',
run_as_root=True)
undo_mgr.undo_with(lambda: utils.execute('ip', 'link', 'set',
br_name, 'down',
run_as_root=True))
# Deleting/Undoing the interface will delete all
# associated resources (remove from the bridge, its
# pair, etc...)
utils.execute('brctl', 'addif', br_name, v1_name,
run_as_root=True)
linux_net.create_ovs_vif_port(self.get_bridge_name(vif),
v2_name,
iface_id, vif['address'],
instance['uuid'])
undo_mgr.undo_with(
lambda: utils.execute('ovs-vsctl', 'del-port',
self.get_bridge_name(vif),
v2_name, run_as_root=True))
utils.execute('ip', 'link', 'add', 'name', if_local_name, 'type',
'veth', 'peer', 'name', if_remote_name,
run_as_root=True)
undo_mgr.undo_with(
lambda: utils.execute('ip', 'link', 'delete', if_local_name,
run_as_root=True))
# Deleting/Undoing the interface will delete all
# associated resources (remove from the bridge, its pair, etc...)
utils.execute('brctl', 'addif', br_name, if_local_name,
run_as_root=True)
utils.execute('ip', 'link', 'set', if_local_name, 'up',
run_as_root=True)
except Exception:
msg = "Failed to configure Network." \
" Rolling back the network interfaces %s %s %s %s " % (
br_name, if_local_name, v1_name, v2_name)
undo_mgr.rollback_and_reraise(msg=msg, instance=instance)
# We are creating our own mac's now because the linux bridge interface
# takes on the lowest mac that is assigned to it. By using FE range
# mac's we prevent the interruption and possible loss of networking
# from changing mac addresses.
def _fe_random_mac(self):
mac = [0xfe, 0xed,
random.randint(0x00, 0xff),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff)]
return ':'.join(map(lambda x: "%02x" % x, mac))
def plug_bridge(self, instance, vif):
if_local_name = 'tap%s' % vif['id'][:11]
if_remote_name = 'ns%s' % vif['id'][:11]
bridge = vif['network']['bridge']
gateway = network.find_gateway(instance, vif['network'])
net = vif['network']
if net.get_meta('should_create_vlan', False):
vlan = net.get_meta('vlan'),
iface = (CONF.vlan_interface or
vif['network'].get_meta('bridge_interface'))
linux_net.LinuxBridgeInterfaceDriver.ensure_vlan_bridge(
vlan,
bridge,
iface,
net_attrs=vif,
mtu=vif.get('mtu'))
iface = 'vlan%s' % vlan
else:
iface = (CONF.flat_interface or
vif['network'].get_meta('bridge_interface'))
LOG.debug('Ensuring bridge for %s - %s' % (iface, bridge))
linux_net.LinuxBridgeInterfaceDriver.ensure_bridge(
bridge,
iface,
net_attrs=vif,
gateway=gateway)
# Device already exists so return.
if linux_net.device_exists(if_local_name):
return
undo_mgr = utils.UndoManager()
try:
utils.execute('ip', 'link', 'add', 'name', if_local_name, 'type',
'veth', 'peer', 'name', if_remote_name,
run_as_root=True)
undo_mgr.undo_with(lambda: utils.execute(
'ip', 'link', 'delete', if_local_name, run_as_root=True))
# NOTE(samalba): Deleting the interface will delete all
# associated resources (remove from the bridge, its pair, etc...)
utils.execute('ip', 'link', 'set', if_local_name, 'address',
self._fe_random_mac(), run_as_root=True)
utils.execute('brctl', 'addif', bridge, if_local_name,
run_as_root=True)
utils.execute('ip', 'link', 'set', if_local_name, 'up',
run_as_root=True)
except Exception:
LOG.exception("Failed to configure network")
msg = _('Failed to setup the network, rolling back')
undo_mgr.rollback_and_reraise(msg=msg, instance=instance)
def unplug(self, instance, vif):
vif_type = vif['type']
LOG.debug('vif_type=%(vif_type)s instance=%(instance)s '
'vif=%(vif)s',
{'vif_type': vif_type, 'instance': instance,
'vif': vif})
if vif_type is None:
raise exception.NovaException(
_("vif_type parameter must be present "
"for this vif_driver implementation"))
if vif_type == network_model.VIF_TYPE_BRIDGE:
self.unplug_bridge(instance, vif)
elif vif_type == network_model.VIF_TYPE_OVS:
if self.ovs_hybrid_required(vif):
self.unplug_ovs_hybrid(instance, vif)
else:
self.unplug_ovs(instance, vif)
elif vif_type == network_model.VIF_TYPE_MIDONET:
self.unplug_midonet(instance, vif)
elif vif_type == network_model.VIF_TYPE_IOVISOR:
self.unplug_iovisor(instance, vif)
elif vif_type == 'hyperv':
self.unplug_windows(instance, vif)
else:
raise exception.NovaException(
_("Unexpected vif_type=%s") % vif_type)
def unplug_windows(self, instance, vif):
pass
def unplug_iovisor(self, instance, vif):
"""Unplug vif from IOvisor
Offboard an interface and deletes port from IOvisor
"""
if_local_name = 'tap%s' % vif['id'][:11]
iface_id = vif['id']
try:
utils.execute('ifc_ctl', 'gateway', 'ifdown',
if_local_name, 'access_vm',
vif['network']['label'] + "_" + iface_id,
vif['address'], run_as_root=True)
utils.execute('ifc_ctl', 'gateway', 'del_port', if_local_name,
run_as_root=True)
linux_net.delete_net_dev(if_local_name)
except processutils.ProcessExecutionError:
LOG.exception(_("Failed while unplugging vif"), instance=instance)
def unplug_ovs(self, instance, vif):
"""Unplug the VIF by deleting the port from the bridge."""
try:
linux_net.delete_ovs_vif_port(vif['network']['bridge'],
vif['devname'])
except processutils.ProcessExecutionError:
LOG.exception(_("Failed while unplugging vif"), instance=instance)
def unplug_midonet(self, instance, vif):
"""Unplug into MidoNet's network port
This accomplishes unbinding of the vif from its MidoNet virtual port
"""
try:
utils.execute('mm-ctl', '--unbind-port',
network.get_ovs_interfaceid(vif), run_as_root=True)
except processutils.ProcessExecutionError:
LOG.exception(_("Failed while unplugging vif"), instance=instance)
def unplug_ovs_hybrid(self, instance, vif):
"""UnPlug using hybrid strategy
Unhook port from OVS, unhook port from bridge, delete
bridge, and delete both veth devices.
"""
try:
br_name = self.get_br_name(vif['id'])
v1_name, v2_name = self.get_veth_pair_names(vif['id'])
if linux_net.device_exists(br_name):
utils.execute('brctl', 'delif', br_name, v1_name,
run_as_root=True)
utils.execute('ip', 'link', 'set', br_name, 'down',
run_as_root=True)
utils.execute('brctl', 'delbr', br_name,
run_as_root=True)
linux_net.delete_ovs_vif_port(self.get_bridge_name(vif),
v2_name)
except processutils.ProcessExecutionError:
LOG.exception(_("Failed while unplugging vif"), instance=instance)
def unplug_bridge(self, instance, vif):
# NOTE(arosen): nothing has to be done in the linuxbridge case
# as when the veth is deleted it automatically is removed from
# the bridge.
pass
def attach(self, instance, vif, container_id):
vif_type = vif['type']
if_remote_name = 'ns%s' % vif['id'][:11]
gateway = network.find_gateway(instance, vif['network'])
ip = network.find_fixed_ip(instance, vif['network'])
LOG.debug('attach vif_type=%(vif_type)s instance=%(instance)s '
'vif=%(vif)s',
{'vif_type': vif_type, 'instance': instance,
'vif': vif})
try:
utils.execute('ip', 'link', 'set', if_remote_name, 'netns',
container_id, run_as_root=True)
utils.execute('ip', 'netns', 'exec', container_id, 'ip', 'link',
'set', if_remote_name, 'address', vif['address'],
run_as_root=True)
utils.execute('ip', 'netns', 'exec', container_id, 'ip', 'addr',
'add', ip, 'dev', if_remote_name, run_as_root=True)
utils.execute('ip', 'netns', 'exec', container_id, 'ip', 'link',
'set', if_remote_name, 'up', run_as_root=True)
# Setup MTU on if_remote_name is required if it is a non
# default value
mtu = CONF.network_device_mtu
if vif.get('mtu') is not None:
mtu = vif.get('mtu')
if mtu is not None:
utils.execute('ip', 'netns', 'exec', container_id, 'ip',
'link', 'set', if_remote_name, 'mtu', mtu,
run_as_root=True)
if gateway is not None:
utils.execute('ip', 'netns', 'exec', container_id,
'ip', 'route', 'replace', 'default', 'via',
gateway, 'dev', if_remote_name, run_as_root=True)
# Disable TSO, for now no config option
utils.execute('ip', 'netns', 'exec', container_id, 'ethtool',
'--offload', if_remote_name, 'tso', 'off',
run_as_root=True)
except Exception:
LOG.exception("Failed to attach vif")
def get_bridge_name(self, vif):
return vif['network']['bridge']
def get_ovs_interfaceid(self, vif):
return vif.get('ovs_interfaceid') or vif['id']
def get_br_name(self, iface_id):
return ("qbr" + iface_id)[:network_model.NIC_NAME_LEN]
def get_veth_pair_names(self, iface_id):
return (("qvb%s" % iface_id)[:network_model.NIC_NAME_LEN],
("qvo%s" % iface_id)[:network_model.NIC_NAME_LEN])
def ovs_hybrid_required(self, vif):
ovs_hybrid_required = self.get_firewall_required(vif) or \
self.get_hybrid_plug_enabled(vif)
return ovs_hybrid_required
def get_firewall_required(self, vif):
if vif.get('details'):
enabled = vif['details'].get('port_filter', False)
if enabled:
return False
if CONF.firewall_driver != "nova.virt.firewall.NoopFirewallDriver":
return True
return False
def get_hybrid_plug_enabled(self, vif):
if vif.get('details'):
return vif['details'].get('ovs_hybrid_plug', False)
return False

View File

@ -1,35 +0,0 @@
# Copyright (c) 2014 Docker, Inc.
# 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.
import ctypes
import datetime
import os
import time
from nova import utils
def sys_uptime():
"""Returns the host uptime."""
if os.name == 'nt':
tick_count64 = ctypes.windll.kernel32.GetTickCount64()
return ("%s up %s, 0 users, load average: 0, 0, 0" %
(str(time.strftime("%H:%M:%S")),
str(datetime.timedelta(milliseconds=long(tick_count64)))))
else:
out, err = utils.execute('env', 'LANG=C', 'uptime')
return out

View File

@ -1,12 +0,0 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
pbr>=1.6 # Apache-2.0
Babel!=2.3.0,!=2.3.1,!=2.3.2,!=2.3.3,>=1.3 # BSD
six>=1.9.0 # MIT
oslo.serialization>=1.10.0 # Apache-2.0
oslo.utils>=3.5.0 # Apache-2.0
oslo.config>=3.9.0 # Apache-2.0
oslo.concurrency>=3.5.0 # Apache-2.0
oslo.i18n>=2.1.0 # Apache-2.0
docker-py<1.8.0,>=1.6.0 # Apache-2.0

View File

@ -1,252 +0,0 @@
#!/bin/bash
set -eu
function usage {
echo "Usage: $0 [OPTION]..."
echo "Run Nova's test suite(s)"
echo ""
echo " -V, --virtual-env Always use virtualenv. Install automatically if not present"
echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment"
echo " -s, --no-site-packages Isolate the virtualenv from the global Python environment"
echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added."
echo " -u, --update Update the virtual environment with any newer package versions"
echo " -p, --pep8 Just run PEP8 and HACKING compliance check"
echo " -8, --pep8-only-changed Just run PEP8 and HACKING compliance check on files changed since HEAD~1"
echo " -P, --no-pep8 Don't run static code checks"
echo " -c, --coverage Generate coverage report"
echo " -d, --debug Run tests with testtools instead of testr. This allows you to use the debugger."
echo " -h, --help Print this usage message"
echo " --hide-elapsed Don't print the elapsed time for each test along with slow test list"
echo " --virtual-env-path <path> Location of the virtualenv directory"
echo " Default: \$(pwd)"
echo " --virtual-env-name <name> Name of the virtualenv directory"
echo " Default: .venv"
echo " --tools-path <dir> Location of the tools directory"
echo " Default: \$(pwd)"
echo " --concurrency <concurrency> How many processes to use when running the tests. A value of 0 autodetects concurrency from your CPU count"
echo " Default: 0"
echo ""
echo "Note: with no options specified, the script will try to run the tests in a virtual environment,"
echo " If no virtualenv is found, the script will ask if you would like to create one. If you "
echo " prefer to run tests NOT in a virtual environment, simply pass the -N option."
exit
}
function process_options {
i=1
while [ $i -le $# ]; do
case "${!i}" in
-h|--help) usage;;
-V|--virtual-env) always_venv=1; never_venv=0;;
-N|--no-virtual-env) always_venv=0; never_venv=1;;
-s|--no-site-packages) no_site_packages=1;;
-f|--force) force=1;;
-u|--update) update=1;;
-p|--pep8) just_pep8=1;;
-8|--pep8-only-changed) just_pep8_changed=1;;
-P|--no-pep8) no_pep8=1;;
-c|--coverage) coverage=1;;
-d|--debug) debug=1;;
--virtual-env-path)
(( i++ ))
venv_path=${!i}
;;
--virtual-env-name)
(( i++ ))
venv_dir=${!i}
;;
--tools-path)
(( i++ ))
tools_path=${!i}
;;
--concurrency)
(( i++ ))
concurrency=${!i}
;;
-*) testropts="$testropts ${!i}";;
*) testrargs="$testrargs ${!i}"
esac
(( i++ ))
done
}
tool_path=${tools_path:-$(pwd)}
venv_path=${venv_path:-$(pwd)}
venv_dir=${venv_name:-.venv}
with_venv=tools/with_venv.sh
always_venv=0
never_venv=0
force=0
no_site_packages=0
installvenvopts=
testrargs=
testropts=
wrapper=""
just_pep8=0
just_pep8_changed=0
no_pep8=0
coverage=0
debug=0
update=0
concurrency=0
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_ALL=C
process_options $@
# Make our paths available to other scripts we call
export venv_path
export venv_dir
export venv_name
export tools_dir
export venv=${venv_path}/${venv_dir}
if [ $no_site_packages -eq 1 ]; then
installvenvopts="--no-site-packages"
fi
function run_tests {
# Cleanup *pyc
${wrapper} find . -type f -name "*.pyc" -delete
if [ $debug -eq 1 ]; then
if [ "$testropts" = "" ] && [ "$testrargs" = "" ]; then
# Default to running all tests if specific test is not
# provided.
testrargs="discover ./nova/tests"
fi
${wrapper} python -m testtools.run $testropts $testrargs
# Short circuit because all of the testr and coverage stuff
# below does not make sense when running testtools.run for
# debugging purposes.
return $?
fi
if [ $coverage -eq 1 ]; then
TESTRTESTS="$TESTRTESTS --coverage"
else
TESTRTESTS="$TESTRTESTS"
fi
# Just run the test suites in current environment
set +e
testrargs=`echo "$testrargs" | sed -e's/^\s*\(.*\)\s*$/\1/'`
TESTRTESTS="$TESTRTESTS --testr-args='--subunit --concurrency $concurrency $testropts $testrargs'"
if [ setup.cfg -nt nova.egg-info/entry_points.txt ]
then
${wrapper} python setup.py egg_info
fi
echo "Running \`${wrapper} $TESTRTESTS\`"
if ${wrapper} which subunit-2to1 2>&1 > /dev/null
then
# subunit-2to1 is present, testr subunit stream should be in version 2
# format. Convert to version one before colorizing.
bash -c "${wrapper} $TESTRTESTS | ${wrapper} subunit-2to1 | ${wrapper} tools/colorizer.py"
else
bash -c "${wrapper} $TESTRTESTS | ${wrapper} tools/colorizer.py"
fi
RESULT=$?
set -e
copy_subunit_log
if [ $coverage -eq 1 ]; then
echo "Generating coverage report in covhtml/"
# Don't compute coverage for common code, which is tested elsewhere
${wrapper} coverage combine
${wrapper} coverage html --include='nova/*' --omit='nova/openstack/common/*' -d covhtml -i
fi
return $RESULT
}
function copy_subunit_log {
LOGNAME=`cat .testrepository/next-stream`
LOGNAME=$(($LOGNAME - 1))
LOGNAME=".testrepository/${LOGNAME}"
cp $LOGNAME subunit.log
}
function warn_on_flake8_without_venv {
if [ $never_venv -eq 1 ]; then
echo "**WARNING**:"
echo "Running flake8 without virtual env may miss OpenStack HACKING detection"
fi
}
function run_pep8 {
echo "Running flake8 ..."
warn_on_flake8_without_venv
bash -c "${wrapper} flake8"
}
TESTRTESTS="python setup.py testr"
if [ $never_venv -eq 0 ]
then
# Remove the virtual environment if --force used
if [ $force -eq 1 ]; then
echo "Cleaning virtualenv..."
rm -rf ${venv}
fi
if [ $update -eq 1 ]; then
echo "Updating virtualenv..."
python tools/install_venv.py $installvenvopts
fi
if [ -e ${venv} ]; then
wrapper="${with_venv}"
else
if [ $always_venv -eq 1 ]; then
# Automatically install the virtualenv
python tools/install_venv.py $installvenvopts
wrapper="${with_venv}"
else
echo -e "No virtual environment found...create one? (Y/n) \c"
read use_ve
if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then
# Install the virtualenv and run the test suite in it
python tools/install_venv.py $installvenvopts
wrapper=${with_venv}
fi
fi
fi
fi
# Delete old coverage data from previous runs
if [ $coverage -eq 1 ]; then
${wrapper} coverage erase
fi
if [ $just_pep8 -eq 1 ]; then
run_pep8
exit
fi
if [ $just_pep8_changed -eq 1 ]; then
# NOTE(gilliard) We want use flake8 to check the entirety of every file that has
# a change in it. Unfortunately the --filenames argument to flake8 only accepts
# file *names* and there are no files named (eg) "nova/compute/manager.py". The
# --diff argument behaves surprisingly as well, because although you feed it a
# diff, it actually checks the file on disk anyway.
files=$(git diff --name-only HEAD~1 | tr '\n' ' ')
echo "Running flake8 on ${files}"
warn_on_flake8_without_venv
bash -c "diff -u --from-file /dev/null ${files} | ${wrapper} flake8 --diff"
exit
fi
run_tests
# NOTE(sirp): we only want to run pep8 when we're running the full-test suite,
# not when we're running tests individually. To handle this, we need to
# distinguish between options (testropts), which begin with a '-', and
# arguments (testrargs).
if [ -z "$testrargs" ]; then
if [ $no_pep8 -eq 0 ]; then
run_pep8
fi
fi

View File

@ -1,45 +0,0 @@
[metadata]
name = nova-docker
summary = Docker driver for OpenStack Nova.
description-file =
README.rst
author = OpenStack
author-email = openstack-dev@lists.openstack.org
home-page = http://www.openstack.org/
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.3
[files]
packages =
novadocker
[build_sphinx]
source-dir = doc/source
build-dir = doc/build
all_files = 1
[upload_sphinx]
upload-dir = doc/build/html
[compile_catalog]
directory = novadocker/locale
domain = nova-docker
[update_catalog]
domain = nova-docker
output_dir = novadocker/locale
input_file = novadocker/locale/nova-docker.pot
[extract_messages]
keywords = _ gettext ngettext l_ lazy_gettext
mapping_file = babel.cfg
output_file = novadocker/locale/nova-docker.pot

View File

@ -1,29 +0,0 @@
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
# 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.
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
# In python < 2.7.4, a lazy loading of package `pbr` will break
# setuptools if some other modules registered functions in `atexit`.
# solution from: http://bugs.python.org/issue15881#msg170215
try:
import multiprocessing # noqa
except ImportError:
pass
setuptools.setup(
setup_requires=['pbr>=1.8'],
pbr=True)

View File

@ -1,17 +0,0 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking<0.11,>=0.10.0
coverage>=3.6 # Apache-2.0
discover # BSD
fixtures<2.0,>=1.3.1 # Apache-2.0/BSD
python-subunit>=0.0.18 # Apache-2.0/BSD
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
mock>=1.2 # BSD
mox3>=0.7.0 # Apache-2.0

View File

@ -1,333 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2013, Nebula, Inc.
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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.
#
# Colorizer Code is borrowed from Twisted:
# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""Display a subunit stream through a colorized unittest test runner."""
import heapq
import subunit
import sys
import unittest
import testtools
class _AnsiColorizer(object):
"""
A colorizer is an object that loosely wraps around a stream, allowing
callers to write text to the stream in a particular color.
Colorizer classes must implement C{supported()} and C{write(text, color)}.
"""
_colors = dict(black=30, red=31, green=32, yellow=33,
blue=34, magenta=35, cyan=36, white=37)
def __init__(self, stream):
self.stream = stream
def supported(cls, stream=sys.stdout):
"""
A class method that returns True if the current platform supports
coloring terminal output using this method. Returns False otherwise.
"""
if not stream.isatty():
return False # auto color only on TTYs
try:
import curses
except ImportError:
return False
else:
try:
try:
return curses.tigetnum("colors") > 2
except curses.error:
curses.setupterm()
return curses.tigetnum("colors") > 2
except Exception:
# guess false in case of error
return False
supported = classmethod(supported)
def write(self, text, color):
"""
Write the given text to the stream in the given color.
@param text: Text to be written to the stream.
@param color: A string label for a color. e.g. 'red', 'white'.
"""
color = self._colors[color]
self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text))
class _Win32Colorizer(object):
"""
See _AnsiColorizer docstring.
"""
def __init__(self, stream):
import win32console
red, green, blue, bold = (win32console.FOREGROUND_RED,
win32console.FOREGROUND_GREEN,
win32console.FOREGROUND_BLUE,
win32console.FOREGROUND_INTENSITY)
self.stream = stream
self.screenBuffer = win32console.GetStdHandle(
win32console.STD_OUT_HANDLE)
self._colors = {
'normal': red | green | blue,
'red': red | bold,
'green': green | bold,
'blue': blue | bold,
'yellow': red | green | bold,
'magenta': red | blue | bold,
'cyan': green | blue | bold,
'white': red | green | blue | bold
}
def supported(cls, stream=sys.stdout):
try:
import win32console
screenBuffer = win32console.GetStdHandle(
win32console.STD_OUT_HANDLE)
except ImportError:
return False
import pywintypes
try:
screenBuffer.SetConsoleTextAttribute(
win32console.FOREGROUND_RED |
win32console.FOREGROUND_GREEN |
win32console.FOREGROUND_BLUE)
except pywintypes.error:
return False
else:
return True
supported = classmethod(supported)
def write(self, text, color):
color = self._colors[color]
self.screenBuffer.SetConsoleTextAttribute(color)
self.stream.write(text)
self.screenBuffer.SetConsoleTextAttribute(self._colors['normal'])
class _NullColorizer(object):
"""
See _AnsiColorizer docstring.
"""
def __init__(self, stream):
self.stream = stream
def supported(cls, stream=sys.stdout):
return True
supported = classmethod(supported)
def write(self, text, color):
self.stream.write(text)
def get_elapsed_time_color(elapsed_time):
if elapsed_time > 1.0:
return 'red'
elif elapsed_time > 0.25:
return 'yellow'
else:
return 'green'
class NovaTestResult(testtools.TestResult):
def __init__(self, stream, descriptions, verbosity):
super(NovaTestResult, self).__init__()
self.stream = stream
self.showAll = verbosity > 1
self.num_slow_tests = 10
self.slow_tests = [] # this is a fixed-sized heap
self.colorizer = None
# NOTE(vish): reset stdout for the terminal check
stdout = sys.stdout
sys.stdout = sys.__stdout__
for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]:
if colorizer.supported():
self.colorizer = colorizer(self.stream)
break
sys.stdout = stdout
self.start_time = None
self.last_time = {}
self.results = {}
self.last_written = None
def _writeElapsedTime(self, elapsed):
color = get_elapsed_time_color(elapsed)
self.colorizer.write(" %.2f" % elapsed, color)
def _addResult(self, test, *args):
try:
name = test.id()
except AttributeError:
name = 'Unknown.unknown'
test_class, test_name = name.rsplit('.', 1)
elapsed = (self._now() - self.start_time).total_seconds()
item = (elapsed, test_class, test_name)
if len(self.slow_tests) >= self.num_slow_tests:
heapq.heappushpop(self.slow_tests, item)
else:
heapq.heappush(self.slow_tests, item)
self.results.setdefault(test_class, [])
self.results[test_class].append((test_name, elapsed) + args)
self.last_time[test_class] = self._now()
self.writeTests()
def _writeResult(self, test_name, elapsed, long_result, color,
short_result, success):
if self.showAll:
self.stream.write(' %s' % str(test_name).ljust(66))
self.colorizer.write(long_result, color)
if success:
self._writeElapsedTime(elapsed)
self.stream.writeln()
else:
self.colorizer.write(short_result, color)
def addSuccess(self, test):
super(NovaTestResult, self).addSuccess(test)
self._addResult(test, 'OK', 'green', '.', True)
def addFailure(self, test, err):
if test.id() == 'process-returncode':
return
super(NovaTestResult, self).addFailure(test, err)
self._addResult(test, 'FAIL', 'red', 'F', False)
def addError(self, test, err):
super(NovaTestResult, self).addFailure(test, err)
self._addResult(test, 'ERROR', 'red', 'E', False)
def addSkip(self, test, reason=None, details=None):
super(NovaTestResult, self).addSkip(test, reason, details)
self._addResult(test, 'SKIP', 'blue', 'S', True)
def startTest(self, test):
self.start_time = self._now()
super(NovaTestResult, self).startTest(test)
def writeTestCase(self, cls):
if not self.results.get(cls):
return
if cls != self.last_written:
self.colorizer.write(cls, 'white')
self.stream.writeln()
for result in self.results[cls]:
self._writeResult(*result)
del self.results[cls]
self.stream.flush()
self.last_written = cls
def writeTests(self):
time = self.last_time.get(self.last_written, self._now())
if not self.last_written or (self._now() - time).total_seconds() > 2.0:
diff = 3.0
while diff > 2.0:
classes = self.results.keys()
oldest = min(classes, key=lambda x: self.last_time[x])
diff = (self._now() - self.last_time[oldest]).total_seconds()
self.writeTestCase(oldest)
else:
self.writeTestCase(self.last_written)
def done(self):
self.stopTestRun()
def stopTestRun(self):
for cls in list(self.results.iterkeys()):
self.writeTestCase(cls)
self.stream.writeln()
self.writeSlowTests()
def writeSlowTests(self):
# Pare out 'fast' tests
slow_tests = [item for item in self.slow_tests
if get_elapsed_time_color(item[0]) != 'green']
if slow_tests:
slow_total_time = sum(item[0] for item in slow_tests)
slow = ("Slowest %i tests took %.2f secs:"
% (len(slow_tests), slow_total_time))
self.colorizer.write(slow, 'yellow')
self.stream.writeln()
last_cls = None
# sort by name
for elapsed, cls, name in sorted(slow_tests,
key=lambda x: x[1] + x[2]):
if cls != last_cls:
self.colorizer.write(cls, 'white')
self.stream.writeln()
last_cls = cls
self.stream.write(' %s' % str(name).ljust(68))
self._writeElapsedTime(elapsed)
self.stream.writeln()
def printErrors(self):
if self.showAll:
self.stream.writeln()
self.printErrorList('ERROR', self.errors)
self.printErrorList('FAIL', self.failures)
def printErrorList(self, flavor, errors):
for test, err in errors:
self.colorizer.write("=" * 70, 'red')
self.stream.writeln()
self.colorizer.write(flavor, 'red')
self.stream.writeln(": %s" % test.id())
self.colorizer.write("-" * 70, 'red')
self.stream.writeln()
self.stream.writeln("%s" % err)
test = subunit.ProtocolTestCase(sys.stdin, passthrough=None)
if sys.version_info[0:2] <= (2, 6):
runner = unittest.TextTestRunner(verbosity=2)
else:
runner = unittest.TextTestRunner(verbosity=2, resultclass=NovaTestResult)
if runner.run(test).wasSuccessful():
exit_code = 0
else:
exit_code = 1
sys.exit(exit_code)

39
tox.ini
View File

@ -1,39 +0,0 @@
[tox]
minversion = 1.6
envlist = py27,py34,pypy,pep8
skipsdist = True
[testenv]
usedevelop = True
install_command = pip install -U {opts} {packages}
setenv =
VIRTUAL_ENV={envdir}
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
-egit+https://github.com/openstack/nova#egg=nova
commands = python setup.py testr --slowest --testr-args='{posargs}'
[testenv:pep8]
commands = flake8
[testenv:venv]
commands = {posargs}
[testenv:docs]
commands = python setup.py build_sphinx
[testenv:cover]
commands = python setup.py testr --coverage --testr-args='{posargs}'
[flake8]
# E712 is ignored on purpose, since it is normal to use 'column == true'
# in sqlalchemy.
# H803 skipped on purpose per list discussion.
# E125 is deliberately excluded. See https://github.com/jcrocholl/pep8/issues/126
# The rest of the ignores are TODOs
ignore = E125,E712,F811,H305,H307,H803
exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,tools
[hacking]
import_exceptions = novadocker.i18n