cleaned client with fixed tests. no quotas functionality implemented

This commit is contained in:
vik 2013-09-10 03:26:11 -04:00
parent 9a3e8e15af
commit 041bfa455c
4580 changed files with 1039600 additions and 3006 deletions

1
.testrepository/format Normal file
View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1 @@
0

Binary file not shown.

253
.tox/log/tox-0.log Normal file
View File

@ -0,0 +1,253 @@
actionid=tox
msg=packaging
cmdargs=['/usr/bin/python', local('/opt/stack/python-manilaclient/setup.py'), 'sdist', '--formats=zip', '--dist-dir', local('/opt/stack/python-manilaclient/.tox/dist')]
env=None
running sdist
running egg_info
writing requirements to python_manilaclient.egg-info/requires.txt
writing python_manilaclient.egg-info/PKG-INFO
writing top-level names to python_manilaclient.egg-info/top_level.txt
writing dependency_links to python_manilaclient.egg-info/dependency_links.txt
writing entry points to python_manilaclient.egg-info/entry_points.txt
reading manifest template 'MANIFEST.in'
warning: no previously-included files found matching '.gitreview'
writing manifest file 'python_manilaclient.egg-info/SOURCES.txt'
warning: LocalSDist: standard file not found: should have one of README, README.txt
creating python-manilaclient-9a3e8e1
creating python-manilaclient-9a3e8e1/doc
creating python-manilaclient-9a3e8e1/doc/source
creating python-manilaclient-9a3e8e1/manilaclient
creating python-manilaclient-9a3e8e1/manilaclient/openstack
creating python-manilaclient-9a3e8e1/manilaclient/openstack/common
creating python-manilaclient-9a3e8e1/manilaclient/v1
creating python-manilaclient-9a3e8e1/manilaclient/v1/contrib
creating python-manilaclient-9a3e8e1/manilaclient/v2
creating python-manilaclient-9a3e8e1/manilaclient/v2/contrib
creating python-manilaclient-9a3e8e1/python_manilaclient.egg-info
creating python-manilaclient-9a3e8e1/tests
creating python-manilaclient-9a3e8e1/tests/v1
creating python-manilaclient-9a3e8e1/tests/v1/contrib
creating python-manilaclient-9a3e8e1/tests/v1/shares
creating python-manilaclient-9a3e8e1/tests/v2
creating python-manilaclient-9a3e8e1/tests/v2/contrib
creating python-manilaclient-9a3e8e1/tests/v2/shares
creating python-manilaclient-9a3e8e1/tools
making hard links in python-manilaclient-9a3e8e1...
hard linking AUTHORS -> python-manilaclient-9a3e8e1
hard linking ChangeLog -> python-manilaclient-9a3e8e1
hard linking HACKING -> python-manilaclient-9a3e8e1
hard linking LICENSE -> python-manilaclient-9a3e8e1
hard linking MANIFEST.in -> python-manilaclient-9a3e8e1
hard linking README.rst -> python-manilaclient-9a3e8e1
hard linking openstack-common.conf -> python-manilaclient-9a3e8e1
hard linking run_tests.sh -> python-manilaclient-9a3e8e1
hard linking setup.cfg -> python-manilaclient-9a3e8e1
hard linking setup.py -> python-manilaclient-9a3e8e1
hard linking tox.ini -> python-manilaclient-9a3e8e1
hard linking doc/.gitignore -> python-manilaclient-9a3e8e1/doc
hard linking doc/Makefile -> python-manilaclient-9a3e8e1/doc
hard linking doc/source/conf.py -> python-manilaclient-9a3e8e1/doc/source
hard linking doc/source/index.rst -> python-manilaclient-9a3e8e1/doc/source
hard linking doc/source/shell.rst -> python-manilaclient-9a3e8e1/doc/source
hard linking manilaclient/__init__.py -> python-manilaclient-9a3e8e1/manilaclient
hard linking manilaclient/base.py -> python-manilaclient-9a3e8e1/manilaclient
hard linking manilaclient/client.py -> python-manilaclient-9a3e8e1/manilaclient
hard linking manilaclient/exceptions.py -> python-manilaclient-9a3e8e1/manilaclient
hard linking manilaclient/extension.py -> python-manilaclient-9a3e8e1/manilaclient
hard linking manilaclient/service_catalog.py -> python-manilaclient-9a3e8e1/manilaclient
hard linking manilaclient/shell.py -> python-manilaclient-9a3e8e1/manilaclient
hard linking manilaclient/utils.py -> python-manilaclient-9a3e8e1/manilaclient
hard linking manilaclient/openstack/__init__.py -> python-manilaclient-9a3e8e1/manilaclient/openstack
hard linking manilaclient/openstack/common/__init__.py -> python-manilaclient-9a3e8e1/manilaclient/openstack/common
hard linking manilaclient/openstack/common/setup.py -> python-manilaclient-9a3e8e1/manilaclient/openstack/common
hard linking manilaclient/openstack/common/strutils.py -> python-manilaclient-9a3e8e1/manilaclient/openstack/common
hard linking manilaclient/openstack/common/version.py -> python-manilaclient-9a3e8e1/manilaclient/openstack/common
hard linking manilaclient/v1/__init__.py -> python-manilaclient-9a3e8e1/manilaclient/v1
hard linking manilaclient/v1/client.py -> python-manilaclient-9a3e8e1/manilaclient/v1
hard linking manilaclient/v1/limits.py -> python-manilaclient-9a3e8e1/manilaclient/v1
hard linking manilaclient/v1/quota_classes.py -> python-manilaclient-9a3e8e1/manilaclient/v1
hard linking manilaclient/v1/quotas.py -> python-manilaclient-9a3e8e1/manilaclient/v1
hard linking manilaclient/v1/share_snapshots.py -> python-manilaclient-9a3e8e1/manilaclient/v1
hard linking manilaclient/v1/shares.py -> python-manilaclient-9a3e8e1/manilaclient/v1
hard linking manilaclient/v1/shell.py -> python-manilaclient-9a3e8e1/manilaclient/v1
hard linking manilaclient/v1/contrib/__init__.py -> python-manilaclient-9a3e8e1/manilaclient/v1/contrib
hard linking manilaclient/v1/contrib/list_extensions.py -> python-manilaclient-9a3e8e1/manilaclient/v1/contrib
hard linking manilaclient/v2/__init__.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/client.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/limits.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/quota_classes.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/quotas.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/share_snapshots.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/shares.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/shell.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/volume_backups.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/volume_backups_restore.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/volume_snapshots.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/volume_types.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/volumes.py -> python-manilaclient-9a3e8e1/manilaclient/v2
hard linking manilaclient/v2/contrib/__init__.py -> python-manilaclient-9a3e8e1/manilaclient/v2/contrib
hard linking manilaclient/v2/contrib/list_extensions.py -> python-manilaclient-9a3e8e1/manilaclient/v2/contrib
hard linking python_manilaclient.egg-info/PKG-INFO -> python-manilaclient-9a3e8e1/python_manilaclient.egg-info
hard linking python_manilaclient.egg-info/SOURCES.txt -> python-manilaclient-9a3e8e1/python_manilaclient.egg-info
hard linking python_manilaclient.egg-info/dependency_links.txt -> python-manilaclient-9a3e8e1/python_manilaclient.egg-info
hard linking python_manilaclient.egg-info/entry_points.txt -> python-manilaclient-9a3e8e1/python_manilaclient.egg-info
hard linking python_manilaclient.egg-info/requires.txt -> python-manilaclient-9a3e8e1/python_manilaclient.egg-info
hard linking python_manilaclient.egg-info/top_level.txt -> python-manilaclient-9a3e8e1/python_manilaclient.egg-info
hard linking tests/__init__.py -> python-manilaclient-9a3e8e1/tests
hard linking tests/fakes.py -> python-manilaclient-9a3e8e1/tests
hard linking tests/test_base.py -> python-manilaclient-9a3e8e1/tests
hard linking tests/test_client.py -> python-manilaclient-9a3e8e1/tests
hard linking tests/test_http.py -> python-manilaclient-9a3e8e1/tests
hard linking tests/test_service_catalog.py -> python-manilaclient-9a3e8e1/tests
hard linking tests/test_shell.py -> python-manilaclient-9a3e8e1/tests
hard linking tests/test_utils.py -> python-manilaclient-9a3e8e1/tests
hard linking tests/utils.py -> python-manilaclient-9a3e8e1/tests
hard linking tests/v1/__init__.py -> python-manilaclient-9a3e8e1/tests/v1
hard linking tests/v1/fakes.py -> python-manilaclient-9a3e8e1/tests/v1
hard linking tests/v1/test_auth.py -> python-manilaclient-9a3e8e1/tests/v1
hard linking tests/v1/test_quota_classes.py -> python-manilaclient-9a3e8e1/tests/v1
hard linking tests/v1/test_quotas.py -> python-manilaclient-9a3e8e1/tests/v1
hard linking tests/v1/test_shell.py -> python-manilaclient-9a3e8e1/tests/v1
hard linking tests/v1/test_types.py -> python-manilaclient-9a3e8e1/tests/v1
hard linking tests/v1/test_volume_backups.py -> python-manilaclient-9a3e8e1/tests/v1
hard linking tests/v1/test_volumes.py -> python-manilaclient-9a3e8e1/tests/v1
hard linking tests/v1/testfile.txt -> python-manilaclient-9a3e8e1/tests/v1
hard linking tests/v1/contrib/__init__.py -> python-manilaclient-9a3e8e1/tests/v1/contrib
hard linking tests/v1/contrib/test_list_extensions.py -> python-manilaclient-9a3e8e1/tests/v1/contrib
hard linking tests/v1/shares/__init__.py -> python-manilaclient-9a3e8e1/tests/v1/shares
hard linking tests/v1/shares/fakes.py -> python-manilaclient-9a3e8e1/tests/v1/shares
hard linking tests/v1/shares/test_share_snapshots.py -> python-manilaclient-9a3e8e1/tests/v1/shares
hard linking tests/v1/shares/test_shares.py -> python-manilaclient-9a3e8e1/tests/v1/shares
hard linking tests/v2/__init__.py -> python-manilaclient-9a3e8e1/tests/v2
hard linking tests/v2/fakes.py -> python-manilaclient-9a3e8e1/tests/v2
hard linking tests/v2/test_auth.py -> python-manilaclient-9a3e8e1/tests/v2
hard linking tests/v2/test_quota_classes.py -> python-manilaclient-9a3e8e1/tests/v2
hard linking tests/v2/test_quotas.py -> python-manilaclient-9a3e8e1/tests/v2
hard linking tests/v2/test_shell.py -> python-manilaclient-9a3e8e1/tests/v2
hard linking tests/v2/test_types.py -> python-manilaclient-9a3e8e1/tests/v2
hard linking tests/v2/test_volume_backups.py -> python-manilaclient-9a3e8e1/tests/v2
hard linking tests/v2/test_volumes.py -> python-manilaclient-9a3e8e1/tests/v2
hard linking tests/v2/contrib/__init__.py -> python-manilaclient-9a3e8e1/tests/v2/contrib
hard linking tests/v2/contrib/test_list_extensions.py -> python-manilaclient-9a3e8e1/tests/v2/contrib
hard linking tests/v2/shares/__init__.py -> python-manilaclient-9a3e8e1/tests/v2/shares
hard linking tests/v2/shares/fakes.py -> python-manilaclient-9a3e8e1/tests/v2/shares
hard linking tests/v2/shares/test_share_snapshots.py -> python-manilaclient-9a3e8e1/tests/v2/shares
hard linking tests/v2/shares/test_shares.py -> python-manilaclient-9a3e8e1/tests/v2/shares
hard linking tools/cinder.bash_completion -> python-manilaclient-9a3e8e1/tools
hard linking tools/generate_authors.sh -> python-manilaclient-9a3e8e1/tools
hard linking tools/install_venv.py -> python-manilaclient-9a3e8e1/tools
hard linking tools/pip-requires -> python-manilaclient-9a3e8e1/tools
hard linking tools/test-requires -> python-manilaclient-9a3e8e1/tools
hard linking tools/with_venv.sh -> python-manilaclient-9a3e8e1/tools
copying setup.cfg -> python-manilaclient-9a3e8e1
Writing python-manilaclient-9a3e8e1/setup.cfg
creating '.tox/dist/python-manilaclient-9a3e8e1.zip' and adding 'python-manilaclient-9a3e8e1' to it
adding 'python-manilaclient-9a3e8e1/README.rst'
adding 'python-manilaclient-9a3e8e1/tox.ini'
adding 'python-manilaclient-9a3e8e1/openstack-common.conf'
adding 'python-manilaclient-9a3e8e1/setup.py'
adding 'python-manilaclient-9a3e8e1/run_tests.sh'
adding 'python-manilaclient-9a3e8e1/AUTHORS'
adding 'python-manilaclient-9a3e8e1/setup.cfg'
adding 'python-manilaclient-9a3e8e1/LICENSE'
adding 'python-manilaclient-9a3e8e1/PKG-INFO'
adding 'python-manilaclient-9a3e8e1/ChangeLog'
adding 'python-manilaclient-9a3e8e1/MANIFEST.in'
adding 'python-manilaclient-9a3e8e1/HACKING'
adding 'python-manilaclient-9a3e8e1/manilaclient/exceptions.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/shell.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/client.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/service_catalog.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/base.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/__init__.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/utils.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/extension.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/quota_classes.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/volume_snapshots.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/shell.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/client.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/volume_backups.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/quotas.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/limits.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/__init__.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/volume_backups_restore.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/shares.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/volumes.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/share_snapshots.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/volume_types.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/contrib/list_extensions.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v2/contrib/__init__.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/openstack/__init__.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/openstack/common/setup.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/openstack/common/version.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/openstack/common/__init__.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/openstack/common/strutils.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v1/quota_classes.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v1/shell.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v1/client.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v1/quotas.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v1/limits.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v1/__init__.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v1/shares.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v1/share_snapshots.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v1/contrib/list_extensions.py'
adding 'python-manilaclient-9a3e8e1/manilaclient/v1/contrib/__init__.py'
adding 'python-manilaclient-9a3e8e1/tools/generate_authors.sh'
adding 'python-manilaclient-9a3e8e1/tools/with_venv.sh'
adding 'python-manilaclient-9a3e8e1/tools/test-requires'
adding 'python-manilaclient-9a3e8e1/tools/pip-requires'
adding 'python-manilaclient-9a3e8e1/tools/install_venv.py'
adding 'python-manilaclient-9a3e8e1/tools/cinder.bash_completion'
adding 'python-manilaclient-9a3e8e1/doc/Makefile'
adding 'python-manilaclient-9a3e8e1/doc/.gitignore'
adding 'python-manilaclient-9a3e8e1/doc/source/shell.rst'
adding 'python-manilaclient-9a3e8e1/doc/source/conf.py'
adding 'python-manilaclient-9a3e8e1/doc/source/index.rst'
adding 'python-manilaclient-9a3e8e1/python_manilaclient.egg-info/top_level.txt'
adding 'python-manilaclient-9a3e8e1/python_manilaclient.egg-info/SOURCES.txt'
adding 'python-manilaclient-9a3e8e1/python_manilaclient.egg-info/dependency_links.txt'
adding 'python-manilaclient-9a3e8e1/python_manilaclient.egg-info/PKG-INFO'
adding 'python-manilaclient-9a3e8e1/python_manilaclient.egg-info/requires.txt'
adding 'python-manilaclient-9a3e8e1/python_manilaclient.egg-info/entry_points.txt'
adding 'python-manilaclient-9a3e8e1/tests/test_shell.py'
adding 'python-manilaclient-9a3e8e1/tests/test_http.py'
adding 'python-manilaclient-9a3e8e1/tests/test_client.py'
adding 'python-manilaclient-9a3e8e1/tests/test_base.py'
adding 'python-manilaclient-9a3e8e1/tests/__init__.py'
adding 'python-manilaclient-9a3e8e1/tests/utils.py'
adding 'python-manilaclient-9a3e8e1/tests/test_utils.py'
adding 'python-manilaclient-9a3e8e1/tests/test_service_catalog.py'
adding 'python-manilaclient-9a3e8e1/tests/fakes.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/test_quota_classes.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/test_shell.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/test_auth.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/test_volumes.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/test_volume_backups.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/test_types.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/test_quotas.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/__init__.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/fakes.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/contrib/__init__.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/contrib/test_list_extensions.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/shares/test_shares.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/shares/test_share_snapshots.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/shares/__init__.py'
adding 'python-manilaclient-9a3e8e1/tests/v2/shares/fakes.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/test_quota_classes.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/test_shell.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/test_auth.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/test_volumes.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/test_volume_backups.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/test_types.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/test_quotas.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/__init__.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/testfile.txt'
adding 'python-manilaclient-9a3e8e1/tests/v1/fakes.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/contrib/__init__.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/contrib/test_list_extensions.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/shares/test_shares.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/shares/test_share_snapshots.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/shares/__init__.py'
adding 'python-manilaclient-9a3e8e1/tests/v1/shares/fakes.py'
removing 'python-manilaclient-9a3e8e1' (and everything under it)

3
.tox/pep8/.tox-config1 Normal file
View File

@ -0,0 +1,3 @@
00000000000000000000000000000000 /usr/bin/python
1.6.1 0 0 0
00000000000000000000000000000000 pep8

80
.tox/pep8/bin/activate Normal file
View File

@ -0,0 +1,80 @@
# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly
deactivate () {
unset pydoc
# reset old environment variables
if [ -n "$_OLD_VIRTUAL_PATH" ] ; then
PATH="$_OLD_VIRTUAL_PATH"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "$_OLD_VIRTUAL_PYTHONHOME" ] ; then
PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
hash -r 2>/dev/null
fi
if [ -n "$_OLD_VIRTUAL_PS1" ] ; then
PS1="$_OLD_VIRTUAL_PS1"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
if [ ! "$1" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}
# unset irrelevant variables
deactivate nondestructive
VIRTUAL_ENV="/opt/stack/python-manilaclient/.tox/pep8"
export VIRTUAL_ENV
_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/bin:$PATH"
export PATH
# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "$PYTHONHOME" ] ; then
_OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME"
unset PYTHONHOME
fi
if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then
_OLD_VIRTUAL_PS1="$PS1"
if [ "x" != x ] ; then
PS1="$PS1"
else
if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then
# special case for Aspen magic directories
# see http://www.zetadev.com/software/aspen/
PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1"
else
PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1"
fi
fi
export PS1
fi
alias pydoc="python -m pydoc"
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
hash -r 2>/dev/null
fi

View File

@ -0,0 +1,42 @@
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
# Created by Davide Di Blasi <davidedb@gmail.com>.
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc'
# Unset irrelevant variables.
deactivate nondestructive
setenv VIRTUAL_ENV "/opt/stack/python-manilaclient/.tox/pep8"
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
if ("" != "") then
set env_name = ""
else
if (`basename "$VIRTUAL_ENV"` == "__") then
# special case for Aspen magic directories
# see http://www.zetadev.com/software/aspen/
set env_name = `basename \`dirname "$VIRTUAL_ENV"\``
else
set env_name = `basename "$VIRTUAL_ENV"`
endif
endif
# Could be in a non-interactive environment,
# in which case, $prompt is undefined and we wouldn't
# care about the prompt anyway.
if ( $?prompt ) then
set _OLD_VIRTUAL_PROMPT="$prompt"
set prompt = "[$env_name] $prompt"
endif
unset env_name
alias pydoc python -m pydoc
rehash

View File

@ -0,0 +1,74 @@
# This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org)
# you cannot run it directly
function deactivate -d "Exit virtualenv and return to normal shell environment"
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
set -e _OLD_VIRTUAL_PATH
end
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
set -e _OLD_VIRTUAL_PYTHONHOME
end
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
functions -e fish_prompt
set -e _OLD_FISH_PROMPT_OVERRIDE
. ( begin
printf "function fish_prompt\n\t#"
functions _old_fish_prompt
end | psub )
functions -e _old_fish_prompt
end
set -e VIRTUAL_ENV
if test "$argv[1]" != "nondestructive"
# Self destruct!
functions -e deactivate
end
end
# unset irrelevant variables
deactivate nondestructive
set -gx VIRTUAL_ENV "/opt/stack/python-manilaclient/.tox/pep8"
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
# unset PYTHONHOME if set
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
set -e PYTHONHOME
end
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
# fish uses a function instead of an env var to generate the prompt.
# save the current fish_prompt function as the function _old_fish_prompt
. ( begin
printf "function _old_fish_prompt\n\t#"
functions fish_prompt
end | psub )
# with the original prompt function renamed, we can override with our own.
function fish_prompt
# Prompt override?
if test -n ""
printf "%s%s%s" "" (set_color normal) (_old_fish_prompt)
return
end
# ...Otherwise, prepend env
set -l _checkbase (basename "$VIRTUAL_ENV")
if test $_checkbase = "__"
# special case for Aspen magic directories
# see http://www.zetadev.com/software/aspen/
printf "%s[%s]%s %s" (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) (_old_fish_prompt)
else
printf "%s(%s)%s%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) (_old_fish_prompt)
end
end
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
end

View File

@ -0,0 +1,34 @@
"""By using execfile(this_file, dict(__file__=this_file)) you will
activate this virtualenv environment.
This can be used when you must use an existing Python interpreter, not
the virtualenv bin/python
"""
try:
__file__
except NameError:
raise AssertionError(
"You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))")
import sys
import os
old_os_path = os.environ['PATH']
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path
base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if sys.platform == 'win32':
site_packages = os.path.join(base, 'Lib', 'site-packages')
else:
site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages')
prev_sys_path = list(sys.path)
import site
site.addsitedir(site_packages)
sys.real_prefix = sys.prefix
sys.prefix = base
# Move the added items to the front of the path:
new_sys_path = []
for item in list(sys.path):
if item not in prev_sys_path:
new_sys_path.append(item)
sys.path.remove(item)
sys.path[:0] = new_sys_path

10
.tox/pep8/bin/easy_install Executable file
View File

@ -0,0 +1,10 @@
#!/opt/stack/python-manilaclient/.tox/pep8/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==0.9.8','console_scripts','easy_install'
__requires__ = 'setuptools==0.9.8'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('setuptools==0.9.8', 'console_scripts', 'easy_install')()
)

10
.tox/pep8/bin/easy_install-2.7 Executable file
View File

@ -0,0 +1,10 @@
#!/opt/stack/python-manilaclient/.tox/pep8/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==0.9.8','console_scripts','easy_install-2.7'
__requires__ = 'setuptools==0.9.8'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('setuptools==0.9.8', 'console_scripts', 'easy_install-2.7')()
)

10
.tox/pep8/bin/manila Executable file
View File

@ -0,0 +1,10 @@
#!/opt/stack/python-manilaclient/.tox/pep8/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'python-manilaclient==9a3e8e1','console_scripts','manila'
__requires__ = 'python-manilaclient==9a3e8e1'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('python-manilaclient==9a3e8e1', 'console_scripts', 'manila')()
)

10
.tox/pep8/bin/pep8 Executable file
View File

@ -0,0 +1,10 @@
#!/opt/stack/python-manilaclient/.tox/pep8/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'pep8==1.4.6','console_scripts','pep8'
__requires__ = 'pep8==1.4.6'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('pep8==1.4.6', 'console_scripts', 'pep8')()
)

10
.tox/pep8/bin/pip Executable file
View File

@ -0,0 +1,10 @@
#!/opt/stack/python-manilaclient/.tox/pep8/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'pip==1.4.1','console_scripts','pip'
__requires__ = 'pip==1.4.1'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('pip==1.4.1', 'console_scripts', 'pip')()
)

10
.tox/pep8/bin/pip-2.7 Executable file
View File

@ -0,0 +1,10 @@
#!/opt/stack/python-manilaclient/.tox/pep8/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'pip==1.4.1','console_scripts','pip-2.7'
__requires__ = 'pip==1.4.1'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('pip==1.4.1', 'console_scripts', 'pip-2.7')()
)

BIN
.tox/pep8/bin/python Executable file

Binary file not shown.

1
.tox/pep8/bin/python2 Symbolic link
View File

@ -0,0 +1 @@
python

1
.tox/pep8/bin/python2.7 Symbolic link
View File

@ -0,0 +1 @@
python

1
.tox/pep8/include/python2.7 Symbolic link
View File

@ -0,0 +1 @@
/usr/include/python2.7

View File

@ -0,0 +1 @@
/usr/lib/python2.7/UserDict.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/_abcoll.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/_weakrefset.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/abc.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/codecs.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/config

View File

@ -0,0 +1 @@
/usr/lib/python2.7/copy_reg.py

View File

@ -0,0 +1,101 @@
import os
import sys
import warnings
import imp
import opcode # opcode is not a virtualenv module, so we can use it to find the stdlib
# Important! To work on pypy, this must be a module that resides in the
# lib-python/modified-x.y.z directory
dirname = os.path.dirname
distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils')
if os.path.normpath(distutils_path) == os.path.dirname(os.path.normpath(__file__)):
warnings.warn(
"The virtualenv distutils package at %s appears to be in the same location as the system distutils?")
else:
__path__.insert(0, distutils_path)
real_distutils = imp.load_module("_virtualenv_distutils", None, distutils_path, ('', '', imp.PKG_DIRECTORY))
# Copy the relevant attributes
try:
__revision__ = real_distutils.__revision__
except AttributeError:
pass
__version__ = real_distutils.__version__
from distutils import dist, sysconfig
try:
basestring
except NameError:
basestring = str
## patch build_ext (distutils doesn't know how to get the libs directory
## path on windows - it hardcodes the paths around the patched sys.prefix)
if sys.platform == 'win32':
from distutils.command.build_ext import build_ext as old_build_ext
class build_ext(old_build_ext):
def finalize_options (self):
if self.library_dirs is None:
self.library_dirs = []
elif isinstance(self.library_dirs, basestring):
self.library_dirs = self.library_dirs.split(os.pathsep)
self.library_dirs.insert(0, os.path.join(sys.real_prefix, "Libs"))
old_build_ext.finalize_options(self)
from distutils.command import build_ext as build_ext_module
build_ext_module.build_ext = build_ext
## distutils.dist patches:
old_find_config_files = dist.Distribution.find_config_files
def find_config_files(self):
found = old_find_config_files(self)
system_distutils = os.path.join(distutils_path, 'distutils.cfg')
#if os.path.exists(system_distutils):
# found.insert(0, system_distutils)
# What to call the per-user config file
if os.name == 'posix':
user_filename = ".pydistutils.cfg"
else:
user_filename = "pydistutils.cfg"
user_filename = os.path.join(sys.prefix, user_filename)
if os.path.isfile(user_filename):
for item in list(found):
if item.endswith('pydistutils.cfg'):
found.remove(item)
found.append(user_filename)
return found
dist.Distribution.find_config_files = find_config_files
## distutils.sysconfig patches:
old_get_python_inc = sysconfig.get_python_inc
def sysconfig_get_python_inc(plat_specific=0, prefix=None):
if prefix is None:
prefix = sys.real_prefix
return old_get_python_inc(plat_specific, prefix)
sysconfig_get_python_inc.__doc__ = old_get_python_inc.__doc__
sysconfig.get_python_inc = sysconfig_get_python_inc
old_get_python_lib = sysconfig.get_python_lib
def sysconfig_get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
if standard_lib and prefix is None:
prefix = sys.real_prefix
return old_get_python_lib(plat_specific, standard_lib, prefix)
sysconfig_get_python_lib.__doc__ = old_get_python_lib.__doc__
sysconfig.get_python_lib = sysconfig_get_python_lib
old_get_config_vars = sysconfig.get_config_vars
def sysconfig_get_config_vars(*args):
real_vars = old_get_config_vars(*args)
if sys.platform == 'win32':
lib_dir = os.path.join(sys.real_prefix, "libs")
if isinstance(real_vars, dict) and 'LIBDIR' not in real_vars:
real_vars['LIBDIR'] = lib_dir # asked for all
elif isinstance(real_vars, list) and 'LIBDIR' in args:
real_vars = real_vars + [lib_dir] # asked for list
return real_vars
sysconfig_get_config_vars.__doc__ = old_get_config_vars.__doc__
sysconfig.get_config_vars = sysconfig_get_config_vars

View File

@ -0,0 +1,6 @@
# This is a config file local to this virtualenv installation
# You may include options that will be used by all distutils commands,
# and by easy_install. For instance:
#
# [easy_install]
# find_links = http://mylocalsite

View File

@ -0,0 +1 @@
/usr/lib/python2.7/encodings

View File

@ -0,0 +1 @@
/usr/lib/python2.7/fnmatch.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/genericpath.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/lib-dynload

View File

@ -0,0 +1 @@
/usr/lib/python2.7/linecache.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/locale.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/ntpath.py

View File

@ -0,0 +1 @@
/usr

View File

@ -0,0 +1 @@
/usr/lib/python2.7/os.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/posixpath.py

View File

@ -0,0 +1 @@
/usr/lib/python2.7/re.py

View File

@ -0,0 +1,16 @@
try:
import ast
from _markerlib.markers import default_environment, compile, interpret
except ImportError:
if 'ast' in globals():
raise
def default_environment():
return {}
def compile(marker):
def marker_fn(environment=None, override=None):
# 'empty markers are True' heuristic won't install extra deps.
return not marker.strip()
marker_fn.__doc__ = marker
return marker_fn
def interpret(marker, environment=None, override=None):
return compile(marker)()

View File

@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-
"""Interpret PEP 345 environment markers.
EXPR [in|==|!=|not in] EXPR [or|and] ...
where EXPR belongs to any of those:
python_version = '%s.%s' % (sys.version_info[0], sys.version_info[1])
python_full_version = sys.version.split()[0]
os.name = os.name
sys.platform = sys.platform
platform.version = platform.version()
platform.machine = platform.machine()
platform.python_implementation = platform.python_implementation()
a free string, like '2.6', or 'win32'
"""
__all__ = ['default_environment', 'compile', 'interpret']
import ast
import os
import platform
import sys
import weakref
_builtin_compile = compile
try:
from platform import python_implementation
except ImportError:
if os.name == "java":
# Jython 2.5 has ast module, but not platform.python_implementation() function.
def python_implementation():
return "Jython"
else:
raise
# restricted set of variables
_VARS = {'sys.platform': sys.platform,
'python_version': '%s.%s' % sys.version_info[:2],
# FIXME parsing sys.platform is not reliable, but there is no other
# way to get e.g. 2.7.2+, and the PEP is defined with sys.version
'python_full_version': sys.version.split(' ', 1)[0],
'os.name': os.name,
'platform.version': platform.version(),
'platform.machine': platform.machine(),
'platform.python_implementation': python_implementation(),
'extra': None # wheel extension
}
for var in list(_VARS.keys()):
if '.' in var:
_VARS[var.replace('.', '_')] = _VARS[var]
def default_environment():
"""Return copy of default PEP 385 globals dictionary."""
return dict(_VARS)
class ASTWhitelist(ast.NodeTransformer):
def __init__(self, statement):
self.statement = statement # for error messages
ALLOWED = (ast.Compare, ast.BoolOp, ast.Attribute, ast.Name, ast.Load, ast.Str)
# Bool operations
ALLOWED += (ast.And, ast.Or)
# Comparison operations
ALLOWED += (ast.Eq, ast.Gt, ast.GtE, ast.In, ast.Is, ast.IsNot, ast.Lt, ast.LtE, ast.NotEq, ast.NotIn)
def visit(self, node):
"""Ensure statement only contains allowed nodes."""
if not isinstance(node, self.ALLOWED):
raise SyntaxError('Not allowed in environment markers.\n%s\n%s' %
(self.statement,
(' ' * node.col_offset) + '^'))
return ast.NodeTransformer.visit(self, node)
def visit_Attribute(self, node):
"""Flatten one level of attribute access."""
new_node = ast.Name("%s.%s" % (node.value.id, node.attr), node.ctx)
return ast.copy_location(new_node, node)
def parse_marker(marker):
tree = ast.parse(marker, mode='eval')
new_tree = ASTWhitelist(marker).generic_visit(tree)
return new_tree
def compile_marker(parsed_marker):
return _builtin_compile(parsed_marker, '<environment marker>', 'eval',
dont_inherit=True)
_cache = weakref.WeakValueDictionary()
def compile(marker):
"""Return compiled marker as a function accepting an environment dict."""
try:
return _cache[marker]
except KeyError:
pass
if not marker.strip():
def marker_fn(environment=None, override=None):
""""""
return True
else:
compiled_marker = compile_marker(parse_marker(marker))
def marker_fn(environment=None, override=None):
"""override updates environment"""
if override is None:
override = {}
if environment is None:
environment = default_environment()
environment.update(override)
return eval(compiled_marker, environment)
marker_fn.__doc__ = marker
_cache[marker] = marker_fn
return _cache[marker]
def interpret(marker, environment=None):
return compile(marker)(environment)

View File

@ -0,0 +1,5 @@
"""Run the EasyInstall command"""
if __name__ == '__main__':
from setuptools.command.easy_install import main
main()

View File

@ -0,0 +1,25 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC
#
# 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 manilaclient.openstack.common import version
version_info = version.VersionInfo('python-manilaclient')
# We have a circular import problem when we first run python setup.py sdist
# It's harmless, so deflect it.
try:
__version__ = version_info.version_string()
except AttributeError:
__version__ = None

View File

@ -0,0 +1,293 @@
# Copyright 2010 Jacob Kaplan-Moss
# Copyright 2011 OpenStack LLC.
# 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.
"""
Base utilities to build API operation managers and objects on top of.
"""
import contextlib
import hashlib
import os
from manilaclient import exceptions
from manilaclient import utils
# Python 2.4 compat
try:
all
except NameError:
def all(iterable):
return True not in (not x for x in iterable)
def getid(obj):
"""
Abstracts the common pattern of allowing both an object or an object's ID
as a parameter when dealing with relationships.
"""
try:
return obj.id
except AttributeError:
return obj
class Manager(utils.HookableMixin):
"""
Managers interact with a particular type of API (servers, flavors, images,
etc.) and provide CRUD operations for them.
"""
resource_class = None
def __init__(self, api):
self.api = api
def _list(self, url, response_key, obj_class=None, body=None):
resp = None
if body:
resp, body = self.api.client.post(url, body=body)
else:
resp, body = self.api.client.get(url)
if obj_class is None:
obj_class = self.resource_class
data = body[response_key]
# NOTE(ja): keystone returns values as list as {'values': [ ... ]}
# unlike other services which just return the list...
if isinstance(data, dict):
try:
data = data['values']
except KeyError:
pass
with self.completion_cache('human_id', obj_class, mode="w"):
with self.completion_cache('uuid', obj_class, mode="w"):
return [obj_class(self, res, loaded=True)
for res in data if res]
@contextlib.contextmanager
def completion_cache(self, cache_type, obj_class, mode):
"""
The completion cache store items that can be used for bash
autocompletion, like UUIDs or human-friendly IDs.
A resource listing will clear and repopulate the cache.
A resource create will append to the cache.
Delete is not handled because listings are assumed to be performed
often enough to keep the cache reasonably up-to-date.
"""
base_dir = utils.env('manilaclient_UUID_CACHE_DIR',
default="~/.manilaclient")
# NOTE(sirp): Keep separate UUID caches for each username + endpoint
# pair
username = utils.env('OS_USERNAME', 'MANILA_USERNAME')
url = utils.env('OS_URL', 'MANILA_URL')
uniqifier = hashlib.md5(username + url).hexdigest()
cache_dir = os.path.expanduser(os.path.join(base_dir, uniqifier))
try:
os.makedirs(cache_dir, 0755)
except OSError:
# NOTE(kiall): This is typicaly either permission denied while
# attempting to create the directory, or the directory
# already exists. Either way, don't fail.
pass
resource = obj_class.__name__.lower()
filename = "%s-%s-cache" % (resource, cache_type.replace('_', '-'))
path = os.path.join(cache_dir, filename)
cache_attr = "_%s_cache" % cache_type
try:
setattr(self, cache_attr, open(path, mode))
except IOError:
# NOTE(kiall): This is typicaly a permission denied while
# attempting to write the cache file.
pass
try:
yield
finally:
cache = getattr(self, cache_attr, None)
if cache:
cache.close()
delattr(self, cache_attr)
def write_to_completion_cache(self, cache_type, val):
cache = getattr(self, "_%s_cache" % cache_type, None)
if cache:
cache.write("%s\n" % val)
def _get(self, url, response_key=None):
resp, body = self.api.client.get(url)
if response_key:
return self.resource_class(self, body[response_key], loaded=True)
else:
return self.resource_class(self, body, loaded=True)
def _create(self, url, body, response_key, return_raw=False, **kwargs):
self.run_hooks('modify_body_for_create', body, **kwargs)
resp, body = self.api.client.post(url, body=body)
if return_raw:
return body[response_key]
with self.completion_cache('human_id', self.resource_class, mode="a"):
with self.completion_cache('uuid', self.resource_class, mode="a"):
return self.resource_class(self, body[response_key])
def _delete(self, url):
resp, body = self.api.client.delete(url)
def _update(self, url, body, **kwargs):
self.run_hooks('modify_body_for_update', body, **kwargs)
resp, body = self.api.client.put(url, body=body)
return body
class ManagerWithFind(Manager):
"""
Like a `Manager`, but with additional `find()`/`findall()` methods.
"""
def find(self, **kwargs):
"""
Find a single item with attributes matching ``**kwargs``.
This isn't very efficient: it loads the entire list then filters on
the Python side.
"""
matches = self.findall(**kwargs)
num_matches = len(matches)
if num_matches == 0:
msg = "No %s matching %s." % (self.resource_class.__name__, kwargs)
raise exceptions.NotFound(404, msg)
elif num_matches > 1:
raise exceptions.NoUniqueMatch
else:
return matches[0]
def findall(self, **kwargs):
"""
Find all items with attributes matching ``**kwargs``.
This isn't very efficient: it loads the entire list then filters on
the Python side.
"""
found = []
searches = kwargs.items()
for obj in self.list():
try:
if all(getattr(obj, attr) == value
for (attr, value) in searches):
found.append(obj)
except AttributeError:
continue
return found
def list(self):
raise NotImplementedError
class Resource(object):
"""
A resource represents a particular instance of an object (server, flavor,
etc). This is pretty much just a bag for attributes.
:param manager: Manager object
:param info: dictionary representing resource attributes
:param loaded: prevent lazy-loading if set to True
"""
HUMAN_ID = False
def __init__(self, manager, info, loaded=False):
self.manager = manager
self._info = info
self._add_details(info)
self._loaded = loaded
# NOTE(sirp): ensure `id` is already present because if it isn't we'll
# enter an infinite loop of __getattr__ -> get -> __init__ ->
# __getattr__ -> ...
if 'id' in self.__dict__ and len(str(self.id)) == 36:
self.manager.write_to_completion_cache('uuid', self.id)
human_id = self.human_id
if human_id:
self.manager.write_to_completion_cache('human_id', human_id)
@property
def human_id(self):
"""Subclasses may override this provide a pretty ID which can be used
for bash completion.
"""
if 'name' in self.__dict__ and self.HUMAN_ID:
return utils.slugify(self.name)
return None
def _add_details(self, info):
for (k, v) in info.iteritems():
try:
setattr(self, k, v)
except AttributeError:
# In this case we already defined the attribute on the class
pass
def __getattr__(self, k):
if k not in self.__dict__:
#NOTE(bcwaldon): disallow lazy-loading if already loaded once
if not self.is_loaded():
self.get()
return self.__getattr__(k)
raise AttributeError(k)
else:
return self.__dict__[k]
def __repr__(self):
reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and
k != 'manager')
info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
return "<%s %s>" % (self.__class__.__name__, info)
def get(self):
# set_loaded() first ... so if we have to bail, we know we tried.
self.set_loaded(True)
if not hasattr(self.manager, 'get'):
return
new = self.manager.get(self.id)
if new:
self._add_details(new._info)
def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
if hasattr(self, 'id') and hasattr(other, 'id'):
return self.id == other.id
return self._info == other._info
def is_loaded(self):
return self._loaded
def set_loaded(self, val):
self._loaded = val

View File

@ -0,0 +1,378 @@
# Copyright 2010 Jacob Kaplan-Moss
# Copyright 2011 OpenStack LLC.
# Copyright 2011 Piston Cloud Computing, Inc.
# All Rights Reserved.
"""
OpenStack Client interface. Handles the REST calls and responses.
"""
import logging
import os
import urlparse
try:
from eventlet import sleep
except ImportError:
from time import sleep
try:
import json
except ImportError:
import simplejson as json
# Python 2.5 compat fix
if not hasattr(urlparse, 'parse_qsl'):
import cgi
urlparse.parse_qsl = cgi.parse_qsl
import requests
from manilaclient import exceptions
from manilaclient import service_catalog
from manilaclient import utils
class HTTPClient(object):
USER_AGENT = 'python-manilaclient'
def __init__(self, user, password, projectid, auth_url, insecure=False,
timeout=None, tenant_id=None, proxy_tenant_id=None,
proxy_token=None, region_name=None,
endpoint_type='publicURL', service_type=None,
service_name=None, share_service_name=None, retries=None,
http_log_debug=False, cacert=None):
self.user = user
self.password = password
self.projectid = projectid
self.tenant_id = tenant_id
self.auth_url = auth_url.rstrip('/')
self.version = 'v1'
self.region_name = region_name
self.endpoint_type = endpoint_type
self.service_type = service_type
self.service_name = service_name
self.share_service_name = share_service_name
self.retries = int(retries or 0)
self.http_log_debug = http_log_debug
self.management_url = None
self.auth_token = None
self.proxy_token = proxy_token
self.proxy_tenant_id = proxy_tenant_id
if insecure:
self.verify_cert = False
else:
if cacert:
self.verify_cert = cacert
else:
self.verify_cert = True
self._logger = logging.getLogger(__name__)
if self.http_log_debug:
ch = logging.StreamHandler()
self._logger.setLevel(logging.DEBUG)
self._logger.addHandler(ch)
if hasattr(requests, 'logging'):
requests.logging.getLogger(requests.__name__).addHandler(ch)
def http_log_req(self, args, kwargs):
if not self.http_log_debug:
return
string_parts = ['curl -i']
for element in args:
if element in ('GET', 'POST', 'DELETE', 'PUT'):
string_parts.append(' -X %s' % element)
else:
string_parts.append(' %s' % element)
for element in kwargs['headers']:
header = ' -H "%s: %s"' % (element, kwargs['headers'][element])
string_parts.append(header)
if 'data' in kwargs:
string_parts.append(" -d '%s'" % (kwargs['data']))
self._logger.debug("\nREQ: %s\n" % "".join(string_parts))
def http_log_resp(self, resp):
if not self.http_log_debug:
return
self._logger.debug(
"RESP: [%s] %s\nRESP BODY: %s\n",
resp.status_code,
resp.headers,
resp.text)
def request(self, url, method, **kwargs):
kwargs.setdefault('headers', kwargs.get('headers', {}))
kwargs['headers']['User-Agent'] = self.USER_AGENT
kwargs['headers']['Accept'] = 'application/json'
if 'body' in kwargs:
kwargs['headers']['Content-Type'] = 'application/json'
kwargs['data'] = json.dumps(kwargs['body'])
del kwargs['body']
self.http_log_req((url, method,), kwargs)
resp = requests.request(
method,
url,
verify=self.verify_cert,
**kwargs)
self.http_log_resp(resp)
if resp.text:
try:
body = json.loads(resp.text)
except ValueError:
pass
body = None
else:
body = None
if resp.status_code >= 400:
raise exceptions.from_response(resp, body)
return resp, body
def _cs_request(self, url, method, **kwargs):
auth_attempts = 0
attempts = 0
backoff = 1
while True:
attempts += 1
if not self.management_url or not self.auth_token:
self.authenticate()
kwargs.setdefault('headers', {})['X-Auth-Token'] = self.auth_token
if self.projectid:
kwargs['headers']['X-Auth-Project-Id'] = self.projectid
try:
resp, body = self.request(self.management_url + url, method,
**kwargs)
return resp, body
except exceptions.BadRequest as e:
if attempts > self.retries:
raise
except exceptions.Unauthorized:
if auth_attempts > 0:
raise
self._logger.debug("Unauthorized, reauthenticating.")
self.management_url = self.auth_token = None
# First reauth. Discount this attempt.
attempts -= 1
auth_attempts += 1
continue
except exceptions.ClientException as e:
if attempts > self.retries:
raise
if 500 <= e.code <= 599:
pass
else:
raise
except requests.exceptions.ConnectionError as e:
# Catch a connection refused from requests.request
self._logger.debug("Connection refused: %s" % e)
raise
self._logger.debug(
"Failed attempt(%s of %s), retrying in %s seconds" %
(attempts, self.retries, backoff))
sleep(backoff)
backoff *= 2
def get(self, url, **kwargs):
return self._cs_request(url, 'GET', **kwargs)
def post(self, url, **kwargs):
return self._cs_request(url, 'POST', **kwargs)
def put(self, url, **kwargs):
return self._cs_request(url, 'PUT', **kwargs)
def delete(self, url, **kwargs):
return self._cs_request(url, 'DELETE', **kwargs)
def _extract_service_catalog(self, url, resp, body, extract_token=True):
"""See what the auth service told us and process the response.
We may get redirected to another site, fail or actually get
back a service catalog with a token and our endpoints."""
if resp.status_code == 200: # content must always present
try:
self.auth_url = url
self.service_catalog = \
service_catalog.ServiceCatalog(body)
if extract_token:
self.auth_token = self.service_catalog.get_token()
management_url = self.service_catalog.url_for(
attr='region',
filter_value=self.region_name,
endpoint_type=self.endpoint_type,
service_type=self.service_type,
service_name=self.service_name,
share_service_name=self.share_service_name)
self.management_url = management_url.rstrip('/')
return None
except exceptions.AmbiguousEndpoints:
print "Found more than one valid endpoint. Use a more " \
"restrictive filter"
raise
except KeyError:
raise exceptions.AuthorizationFailure()
except exceptions.EndpointNotFound:
print "Could not find any suitable endpoint. Correct region?"
raise
elif resp.status_code == 305:
return resp['location']
else:
raise exceptions.from_response(resp, body)
def _fetch_endpoints_from_auth(self, url):
"""We have a token, but don't know the final endpoint for
the region. We have to go back to the auth service and
ask again. This request requires an admin-level token
to work. The proxy token supplied could be from a low-level enduser.
We can't get this from the keystone service endpoint, we have to use
the admin endpoint.
This will overwrite our admin token with the user token.
"""
# GET ...:5001/v2.0/tokens/#####/endpoints
url = '/'.join([url, 'tokens', '%s?belongsTo=%s'
% (self.proxy_token, self.proxy_tenant_id)])
self._logger.debug("Using Endpoint URL: %s" % url)
resp, body = self.request(url, "GET",
headers={'X-Auth-Token': self.auth_token})
return self._extract_service_catalog(url, resp, body,
extract_token=False)
def authenticate(self):
magic_tuple = urlparse.urlsplit(self.auth_url)
scheme, netloc, path, query, frag = magic_tuple
port = magic_tuple.port
if port is None:
port = 80
path_parts = path.split('/')
for part in path_parts:
if len(part) > 0 and part[0] == 'v':
self.version = part
break
# TODO(sandy): Assume admin endpoint is 35357 for now.
# Ideally this is going to have to be provided by the service catalog.
new_netloc = netloc.replace(':%d' % port, ':%d' % (35357,))
admin_url = urlparse.urlunsplit((scheme, new_netloc,
path, query, frag))
auth_url = self.auth_url
if self.version == "v2.0":
while auth_url:
if "MANILA_RAX_AUTH" in os.environ:
auth_url = self._rax_auth(auth_url)
else:
auth_url = self._v2_auth(auth_url)
# Are we acting on behalf of another user via an
# existing token? If so, our actual endpoints may
# be different than that of the admin token.
if self.proxy_token:
self._fetch_endpoints_from_auth(admin_url)
# Since keystone no longer returns the user token
# with the endpoints any more, we need to replace
# our service account token with the user token.
self.auth_token = self.proxy_token
else:
try:
while auth_url:
auth_url = self._v1_auth(auth_url)
# In some configurations manila makes redirection to
# v2.0 keystone endpoint. Also, new location does not contain
# real endpoint, only hostname and port.
except exceptions.AuthorizationFailure:
if auth_url.find('v2.0') < 0:
auth_url = auth_url + '/v2.0'
self._v2_auth(auth_url)
def _v1_auth(self, url):
if self.proxy_token:
raise exceptions.NoTokenLookupException()
headers = {'X-Auth-User': self.user,
'X-Auth-Key': self.password}
if self.projectid:
headers['X-Auth-Project-Id'] = self.projectid
resp, body = self.request(url, 'GET', headers=headers)
if resp.status_code in (200, 204): # in some cases we get No Content
try:
mgmt_header = 'x-server-management-url'
self.management_url = resp.headers[mgmt_header].rstrip('/')
self.auth_token = resp.headers['x-auth-token']
self.auth_url = url
except (KeyError, TypeError):
raise exceptions.AuthorizationFailure()
elif resp.status_code == 305:
return resp.headers['location']
else:
raise exceptions.from_response(resp, body)
def _v2_auth(self, url):
"""Authenticate against a v2.0 auth service."""
body = {"auth": {
"passwordCredentials": {"username": self.user,
"password": self.password}}}
if self.projectid:
body['auth']['tenantName'] = self.projectid
elif self.tenant_id:
body['auth']['tenantId'] = self.tenant_id
self._authenticate(url, body)
def _rax_auth(self, url):
"""Authenticate against the Rackspace auth service."""
body = {"auth": {
"RAX-KSKEY:apiKeyCredentials": {
"username": self.user,
"apiKey": self.password,
"tenantName": self.projectid}}}
self._authenticate(url, body)
def _authenticate(self, url, body):
"""Authenticate and extract the service catalog."""
token_url = url + "/tokens"
# Make sure we follow redirects when trying to reach Keystone
resp, body = self.request(
token_url,
"POST",
body=body,
allow_redirects=True)
return self._extract_service_catalog(url, resp, body)
def get_client_class(version):
version_map = {
'1': 'manilaclient.v1.client.Client',
'2': 'manilaclient.v2.client.Client',
}
try:
client_path = version_map[str(version)]
except (KeyError, ValueError):
msg = "Invalid client version '%s'. must be one of: %s" % (
(version, ', '.join(version_map.keys())))
raise exceptions.UnsupportedVersion(msg)
return utils.import_class(client_path)
def Client(version, *args, **kwargs):
client_class = get_client_class(version)
return client_class(*args, **kwargs)

View File

@ -0,0 +1,150 @@
# Copyright 2010 Jacob Kaplan-Moss
"""
Exception definitions.
"""
class UnsupportedVersion(Exception):
"""Indicates that the user is trying to use an unsupported
version of the API"""
pass
class CommandError(Exception):
pass
class AuthorizationFailure(Exception):
pass
class NoUniqueMatch(Exception):
pass
class NoTokenLookupException(Exception):
"""This form of authentication does not support looking up
endpoints from an existing token."""
pass
class EndpointNotFound(Exception):
"""Could not find Service or Region in Service Catalog."""
pass
class AmbiguousEndpoints(Exception):
"""Found more than one matching endpoint in Service Catalog."""
def __init__(self, endpoints=None):
self.endpoints = endpoints
def __str__(self):
return "AmbiguousEndpoints: %s" % repr(self.endpoints)
class ClientException(Exception):
"""
The base exception class for all exceptions this library raises.
"""
def __init__(self, code, message=None, details=None, request_id=None):
self.code = code
self.message = message or self.__class__.message
self.details = details
self.request_id = request_id
def __str__(self):
formatted_string = "%s (HTTP %s)" % (self.message, self.code)
if self.request_id:
formatted_string += " (Request-ID: %s)" % self.request_id
return formatted_string
class BadRequest(ClientException):
"""
HTTP 400 - Bad request: you sent some malformed data.
"""
http_status = 400
message = "Bad request"
class Unauthorized(ClientException):
"""
HTTP 401 - Unauthorized: bad credentials.
"""
http_status = 401
message = "Unauthorized"
class Forbidden(ClientException):
"""
HTTP 403 - Forbidden: your credentials don't give you access to this
resource.
"""
http_status = 403
message = "Forbidden"
class NotFound(ClientException):
"""
HTTP 404 - Not found
"""
http_status = 404
message = "Not found"
class OverLimit(ClientException):
"""
HTTP 413 - Over limit: you're over the API limits for this time period.
"""
http_status = 413
message = "Over limit"
# NotImplemented is a python keyword.
class HTTPNotImplemented(ClientException):
"""
HTTP 501 - Not Implemented: the server does not support this operation.
"""
http_status = 501
message = "Not Implemented"
# In Python 2.4 Exception is old-style and thus doesn't have a __subclasses__()
# so we can do this:
# _code_map = dict((c.http_status, c)
# for c in ClientException.__subclasses__())
#
# Instead, we have to hardcode it:
_code_map = dict((c.http_status, c) for c in [BadRequest, Unauthorized,
Forbidden, NotFound,
OverLimit, HTTPNotImplemented])
def from_response(response, body):
"""
Return an instance of an ClientException or subclass
based on an requests response.
Usage::
resp, body = requests.request(...)
if resp.status_code != 200:
raise exception_from_response(resp, rest.text)
"""
cls = _code_map.get(response.status_code, ClientException)
if response.headers:
request_id = response.headers.get('x-compute-request-id')
else:
request_id = None
if body:
message = "n/a"
details = "n/a"
if hasattr(body, 'keys'):
error = body[body.keys()[0]]
message = error.get('message', None)
details = error.get('details', None)
return cls(code=response.status_code, message=message, details=details,
request_id=request_id)
else:
return cls(code=response.status_code, request_id=request_id)

View File

@ -0,0 +1,39 @@
# Copyright 2011 OpenStack LLC.
# 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 manilaclient import base
from manilaclient import utils
class Extension(utils.HookableMixin):
"""Extension descriptor."""
SUPPORTED_HOOKS = ('__pre_parse_args__', '__post_parse_args__')
def __init__(self, name, module):
self.name = name
self.module = module
self._parse_extension_module()
def _parse_extension_module(self):
self.manager_class = None
for attr_name, attr_value in self.module.__dict__.items():
if attr_name in self.SUPPORTED_HOOKS:
self.add_hook(attr_name, attr_value)
elif utils.safe_issubclass(attr_value, base.Manager):
self.manager_class = attr_value
def __repr__(self):
return "<Extension '%s'>" % self.name

View File

@ -0,0 +1,367 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack Foundation.
# Copyright 2012-2013 Hewlett-Packard Development Company, L.P.
# 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.
"""
Utilities with minimum-depends for use in setup.py
"""
import email
import os
import re
import subprocess
import sys
from setuptools.command import sdist
def parse_mailmap(mailmap='.mailmap'):
mapping = {}
if os.path.exists(mailmap):
with open(mailmap, 'r') as fp:
for l in fp:
try:
canonical_email, alias = re.match(
r'[^#]*?(<.+>).*(<.+>).*', l).groups()
except AttributeError:
continue
mapping[alias] = canonical_email
return mapping
def _parse_git_mailmap(git_dir, mailmap='.mailmap'):
mailmap = os.path.join(os.path.dirname(git_dir), mailmap)
return parse_mailmap(mailmap)
def canonicalize_emails(changelog, mapping):
"""Takes in a string and an email alias mapping and replaces all
instances of the aliases in the string with their real email.
"""
for alias, email_address in mapping.iteritems():
changelog = changelog.replace(alias, email_address)
return changelog
# Get requirements from the first file that exists
def get_reqs_from_files(requirements_files):
for requirements_file in requirements_files:
if os.path.exists(requirements_file):
with open(requirements_file, 'r') as fil:
return fil.read().split('\n')
return []
def parse_requirements(requirements_files=['requirements.txt',
'tools/pip-requires']):
requirements = []
for line in get_reqs_from_files(requirements_files):
# For the requirements list, we need to inject only the portion
# after egg= so that distutils knows the package it's looking for
# such as:
# -e git://github.com/openstack/nova/master#egg=nova
if re.match(r'\s*-e\s+', line):
requirements.append(re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1',
line))
# such as:
# http://github.com/openstack/nova/zipball/master#egg=nova
elif re.match(r'\s*https?:', line):
requirements.append(re.sub(r'\s*https?:.*#egg=(.*)$', r'\1',
line))
# -f lines are for index locations, and don't get used here
elif re.match(r'\s*-f\s+', line):
pass
# argparse is part of the standard library starting with 2.7
# adding it to the requirements list screws distro installs
elif line == 'argparse' and sys.version_info >= (2, 7):
pass
else:
requirements.append(line)
return requirements
def parse_dependency_links(requirements_files=['requirements.txt',
'tools/pip-requires']):
dependency_links = []
# dependency_links inject alternate locations to find packages listed
# in requirements
for line in get_reqs_from_files(requirements_files):
# skip comments and blank lines
if re.match(r'(\s*#)|(\s*$)', line):
continue
# lines with -e or -f need the whole line, minus the flag
if re.match(r'\s*-[ef]\s+', line):
dependency_links.append(re.sub(r'\s*-[ef]\s+', '', line))
# lines that are only urls can go in unmolested
elif re.match(r'\s*https?:', line):
dependency_links.append(line)
return dependency_links
def _run_shell_command(cmd, throw_on_error=False):
if os.name == 'nt':
output = subprocess.Popen(["cmd.exe", "/C", cmd],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
else:
output = subprocess.Popen(["/bin/sh", "-c", cmd],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out = output.communicate()
if output.returncode and throw_on_error:
raise Exception("%s returned %d" % cmd, output.returncode)
if len(out) == 0:
return None
if len(out[0].strip()) == 0:
return None
return out[0].strip()
def _get_git_directory():
parent_dir = os.path.dirname(__file__)
while True:
git_dir = os.path.join(parent_dir, '.git')
if os.path.exists(git_dir):
return git_dir
parent_dir, child = os.path.split(parent_dir)
if not child: # reached to root dir
return None
def write_git_changelog():
"""Write a changelog based on the git changelog."""
new_changelog = 'ChangeLog'
git_dir = _get_git_directory()
if not os.getenv('SKIP_WRITE_GIT_CHANGELOG'):
if git_dir:
git_log_cmd = 'git --git-dir=%s log' % git_dir
changelog = _run_shell_command(git_log_cmd)
mailmap = _parse_git_mailmap(git_dir)
with open(new_changelog, "w") as changelog_file:
changelog_file.write(canonicalize_emails(changelog, mailmap))
else:
open(new_changelog, 'w').close()
def generate_authors():
"""Create AUTHORS file using git commits."""
jenkins_email = 'jenkins@review.(openstack|stackforge).org'
old_authors = 'AUTHORS.in'
new_authors = 'AUTHORS'
git_dir = _get_git_directory()
if not os.getenv('SKIP_GENERATE_AUTHORS'):
if git_dir:
# don't include jenkins email address in AUTHORS file
git_log_cmd = ("git --git-dir=" + git_dir +
" log --format='%aN <%aE>' | sort -u | "
"egrep -v '" + jenkins_email + "'")
changelog = _run_shell_command(git_log_cmd)
signed_cmd = ("git --git-dir=" + git_dir +
" log | grep -i Co-authored-by: | sort -u")
signed_entries = _run_shell_command(signed_cmd)
if signed_entries:
new_entries = "\n".join(
[signed.split(":", 1)[1].strip()
for signed in signed_entries.split("\n") if signed])
changelog = "\n".join((changelog, new_entries))
mailmap = _parse_git_mailmap(git_dir)
with open(new_authors, 'w') as new_authors_fh:
new_authors_fh.write(canonicalize_emails(changelog, mailmap))
if os.path.exists(old_authors):
with open(old_authors, "r") as old_authors_fh:
new_authors_fh.write('\n' + old_authors_fh.read())
else:
open(new_authors, 'w').close()
_rst_template = """%(heading)s
%(underline)s
.. automodule:: %(module)s
:members:
:undoc-members:
:show-inheritance:
"""
def get_cmdclass():
"""Return dict of commands to run from setup.py."""
cmdclass = dict()
def _find_modules(arg, dirname, files):
for filename in files:
if filename.endswith('.py') and filename != '__init__.py':
arg["%s.%s" % (dirname.replace('/', '.'),
filename[:-3])] = True
class LocalSDist(sdist.sdist):
"""Builds the ChangeLog and Authors files from VC first."""
def run(self):
write_git_changelog()
generate_authors()
# sdist.sdist is an old style class, can't use super()
sdist.sdist.run(self)
cmdclass['sdist'] = LocalSDist
# If Sphinx is installed on the box running setup.py,
# enable setup.py to build the documentation, otherwise,
# just ignore it
try:
from sphinx.setup_command import BuildDoc
class LocalBuildDoc(BuildDoc):
builders = ['html', 'man']
def generate_autoindex(self):
print "**Autodocumenting from %s" % os.path.abspath(os.curdir)
modules = {}
option_dict = self.distribution.get_option_dict('build_sphinx')
source_dir = os.path.join(option_dict['source_dir'][1], 'api')
if not os.path.exists(source_dir):
os.makedirs(source_dir)
for pkg in self.distribution.packages:
if '.' not in pkg:
os.path.walk(pkg, _find_modules, modules)
module_list = modules.keys()
module_list.sort()
autoindex_filename = os.path.join(source_dir, 'autoindex.rst')
with open(autoindex_filename, 'w') as autoindex:
autoindex.write(""".. toctree::
:maxdepth: 1
""")
for module in module_list:
output_filename = os.path.join(source_dir,
"%s.rst" % module)
heading = "The :mod:`%s` Module" % module
underline = "=" * len(heading)
values = dict(module=module, heading=heading,
underline=underline)
print "Generating %s" % output_filename
with open(output_filename, 'w') as output_file:
output_file.write(_rst_template % values)
autoindex.write(" %s.rst\n" % module)
def run(self):
if not os.getenv('SPHINX_DEBUG'):
self.generate_autoindex()
for builder in self.builders:
self.builder = builder
self.finalize_options()
self.project = self.distribution.get_name()
self.version = self.distribution.get_version()
self.release = self.distribution.get_version()
BuildDoc.run(self)
class LocalBuildLatex(LocalBuildDoc):
builders = ['latex']
cmdclass['build_sphinx'] = LocalBuildDoc
cmdclass['build_sphinx_latex'] = LocalBuildLatex
except ImportError:
pass
return cmdclass
def _get_revno(git_dir):
"""Return the number of commits since the most recent tag.
We use git-describe to find this out, but if there are no
tags then we fall back to counting commits since the beginning
of time.
"""
describe = _run_shell_command(
"git --git-dir=%s describe --always" % git_dir)
if "-" in describe:
return describe.rsplit("-", 2)[-2]
# no tags found
revlist = _run_shell_command(
"git --git-dir=%s rev-list --abbrev-commit HEAD" % git_dir)
return len(revlist.splitlines())
def _get_version_from_git(pre_version):
"""Return a version which is equal to the tag that's on the current
revision if there is one, or tag plus number of additional revisions
if the current revision has no tag."""
git_dir = _get_git_directory()
if git_dir:
if pre_version:
try:
return _run_shell_command(
"git --git-dir=" + git_dir + " describe --exact-match",
throw_on_error=True).replace('-', '.')
except Exception:
sha = _run_shell_command(
"git --git-dir=" + git_dir + " log -n1 --pretty=format:%h")
return "%s.a%s.g%s" % (pre_version, _get_revno(git_dir), sha)
else:
return _run_shell_command(
"git --git-dir=" + git_dir + " describe --always").replace(
'-', '.')
return None
def _get_version_from_pkg_info(package_name):
"""Get the version from PKG-INFO file if we can."""
try:
pkg_info_file = open('PKG-INFO', 'r')
except (IOError, OSError):
return None
try:
pkg_info = email.message_from_file(pkg_info_file)
except email.MessageError:
return None
# Check to make sure we're in our own dir
if pkg_info.get('Name', None) != package_name:
return None
return pkg_info.get('Version', None)
def get_version(package_name, pre_version=None):
"""Get the version of the project. First, try getting it from PKG-INFO, if
it exists. If it does, that means we're in a distribution tarball or that
install has happened. Otherwise, if there is no PKG-INFO file, pull the
version from git.
We do not support setup.py version sanity in git archive tarballs, nor do
we support packagers directly sucking our git repo into theirs. We expect
that a source tarball be made from our git repo - or that if someone wants
to make a source tarball from a fork of our repo with additional tags in it
that they understand and desire the results of doing that.
"""
version = os.environ.get("OSLO_PACKAGE_VERSION", None)
if version:
return version
version = _get_version_from_pkg_info(package_name)
if version:
return version
version = _get_version_from_git(pre_version)
if version:
return version
raise Exception("Versioning for this project requires either an sdist"
" tarball, or access to an upstream git repository.")

View File

@ -0,0 +1,133 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# 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.
"""
System-level utilities and helper functions.
"""
import logging
import sys
LOG = logging.getLogger(__name__)
def int_from_bool_as_string(subject):
"""
Interpret a string as a boolean and return either 1 or 0.
Any string value in:
('True', 'true', 'On', 'on', '1')
is interpreted as a boolean True.
Useful for JSON-decoded stuff and config file parsing
"""
return bool_from_string(subject) and 1 or 0
def bool_from_string(subject):
"""
Interpret a string as a boolean.
Any string value in:
('True', 'true', 'On', 'on', 'Yes', 'yes', '1')
is interpreted as a boolean True.
Useful for JSON-decoded stuff and config file parsing
"""
if isinstance(subject, bool):
return subject
if isinstance(subject, basestring):
if subject.strip().lower() in ('true', 'on', 'yes', '1'):
return True
return False
def safe_decode(text, incoming=None, errors='strict'):
"""
Decodes incoming str using `incoming` if they're
not already unicode.
:param incoming: Text's current encoding
:param errors: Errors handling policy. See here for valid
values http://docs.python.org/2/library/codecs.html
:returns: text or a unicode `incoming` encoded
representation of it.
:raises TypeError: If text is not an isntance of basestring
"""
if not isinstance(text, basestring):
raise TypeError("%s can't be decoded" % type(text))
if isinstance(text, unicode):
return text
if not incoming:
incoming = (sys.stdin.encoding or
sys.getdefaultencoding())
try:
return text.decode(incoming, errors)
except UnicodeDecodeError:
# Note(flaper87) If we get here, it means that
# sys.stdin.encoding / sys.getdefaultencoding
# didn't return a suitable encoding to decode
# text. This happens mostly when global LANG
# var is not set correctly and there's no
# default encoding. In this case, most likely
# python will use ASCII or ANSI encoders as
# default encodings but they won't be capable
# of decoding non-ASCII characters.
#
# Also, UTF-8 is being used since it's an ASCII
# extension.
return text.decode('utf-8', errors)
def safe_encode(text, incoming=None,
encoding='utf-8', errors='strict'):
"""
Encodes incoming str/unicode using `encoding`. If
incoming is not specified, text is expected to
be encoded with current python's default encoding.
(`sys.getdefaultencoding`)
:param incoming: Text's current encoding
:param encoding: Expected encoding for text (Default UTF-8)
:param errors: Errors handling policy. See here for valid
values http://docs.python.org/2/library/codecs.html
:returns: text or a bytestring `encoding` encoded
representation of it.
:raises TypeError: If text is not an isntance of basestring
"""
if not isinstance(text, basestring):
raise TypeError("%s can't be encoded" % type(text))
if not incoming:
incoming = (sys.stdin.encoding or
sys.getdefaultencoding())
if isinstance(text, unicode):
return text.encode(encoding, errors)
elif text and encoding != incoming:
# Decode text before encoding it with `encoding`
text = safe_decode(text, incoming, errors)
return text.encode(encoding, errors)
return text

View File

@ -0,0 +1,94 @@
# Copyright 2012 OpenStack Foundation
# Copyright 2012-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.
"""
Utilities for consuming the version from pkg_resources.
"""
import pkg_resources
class VersionInfo(object):
def __init__(self, package):
"""Object that understands versioning for a package
:param package: name of the python package, such as glance, or
python-glanceclient
"""
self.package = package
self.release = None
self.version = None
self._cached_version = None
def __str__(self):
"""Make the VersionInfo object behave like a string."""
return self.version_string()
def __repr__(self):
"""Include the name."""
return "VersionInfo(%s:%s)" % (self.package, self.version_string())
def _get_version_from_pkg_resources(self):
"""Get the version of the package from the pkg_resources record
associated with the package."""
try:
requirement = pkg_resources.Requirement.parse(self.package)
provider = pkg_resources.get_provider(requirement)
return provider.version
except pkg_resources.DistributionNotFound:
# The most likely cause for this is running tests in a tree
# produced from a tarball where the package itself has not been
# installed into anything. Revert to setup-time logic.
from manilaclient.openstack.common import setup
return setup.get_version(self.package)
def release_string(self):
"""Return the full version of the package including suffixes indicating
VCS status.
"""
if self.release is None:
self.release = self._get_version_from_pkg_resources()
return self.release
def version_string(self):
"""Return the short version minus any alpha/beta tags."""
if self.version is None:
parts = []
for part in self.release_string().split('.'):
if part[0].isdigit():
parts.append(part)
else:
break
self.version = ".".join(parts)
return self.version
# Compatibility functions
canonical_version_string = version_string
version_string_with_vcs = release_string
def cached_version_string(self, prefix=""):
"""Generate an object which will expand in a string context to
the results of version_string(). We do this so that don't
call into pkg_resources every time we start up a program when
passing version information into the CONF constructor, but
rather only do the calculation when and if a version is requested
"""
if not self._cached_version:
self._cached_version = "%s%s" % (prefix,
self.version_string())
return self._cached_version

View File

@ -0,0 +1,77 @@
# Copyright 2011 OpenStack LLC.
# Copyright 2011, Piston Cloud Computing, 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 manilaclient.exceptions
class ServiceCatalog(object):
"""Helper methods for dealing with a Keystone Service Catalog."""
def __init__(self, resource_dict):
self.catalog = resource_dict
def get_token(self):
return self.catalog['access']['token']['id']
def url_for(self, attr=None, filter_value=None,
service_type=None, endpoint_type='publicURL',
service_name=None, share_service_name=None):
"""Fetch the public URL from the Compute service for
a particular endpoint attribute. If none given, return
the first. See tests for sample service catalog."""
matching_endpoints = []
if 'endpoints' in self.catalog:
# We have a bastardized service catalog. Treat it special. :/
for endpoint in self.catalog['endpoints']:
if not filter_value or endpoint[attr] == filter_value:
matching_endpoints.append(endpoint)
if not matching_endpoints:
raise manilaclient.exceptions.EndpointNotFound()
# We don't always get a service catalog back ...
if not 'serviceCatalog' in self.catalog['access']:
return None
# Full catalog ...
catalog = self.catalog['access']['serviceCatalog']
for service in catalog:
if service.get("type") != service_type:
continue
if (service_name and service_type == 'compute' and
service.get('name') != service_name):
continue
if (share_service_name and service_type == 'volume' and
service.get('name') != share_service_name):
continue
endpoints = service['endpoints']
for endpoint in endpoints:
if not filter_value or endpoint.get(attr) == filter_value:
endpoint["serviceName"] = service.get("name")
matching_endpoints.append(endpoint)
if not matching_endpoints:
raise manilaclient.exceptions.EndpointNotFound()
elif len(matching_endpoints) > 1:
raise manilaclient.exceptions.AmbiguousEndpoints(
endpoints=matching_endpoints)
else:
return matching_endpoints[0][endpoint_type]

View File

@ -0,0 +1,515 @@
# Copyright 2011 OpenStack LLC.
# 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.
"""
Command-line interface to the OpenStack Manila API.
"""
import argparse
import glob
import imp
import itertools
import os
import pkgutil
import sys
import logging
from manilaclient import client
from manilaclient import exceptions as exc
import manilaclient.extension
from manilaclient.openstack.common import strutils
from manilaclient import utils
from manilaclient.v1 import shell as shell_v1
from manilaclient.v2 import shell as shell_v2
DEFAULT_OS_SHARE_API_VERSION = "1"
DEFAULT_MANILA_ENDPOINT_TYPE = 'publicURL'
DEFAULT_MANILA_SERVICE_TYPE = 'share'
logger = logging.getLogger(__name__)
class manilaclientArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super(manilaclientArgumentParser, self).__init__(*args, **kwargs)
def error(self, message):
"""error(message: string)
Prints a usage message incorporating the message to stderr and
exits.
"""
self.print_usage(sys.stderr)
#FIXME(lzyeval): if changes occur in argparse.ArgParser._check_value
choose_from = ' (choose from'
progparts = self.prog.partition(' ')
self.exit(2, "error: %(errmsg)s\nTry '%(mainp)s help %(subp)s'"
" for more information.\n" %
{'errmsg': message.split(choose_from)[0],
'mainp': progparts[0],
'subp': progparts[2]})
class OpenStackManilaShell(object):
def get_base_parser(self):
parser = manilaclientArgumentParser(
prog='manila',
description=__doc__.strip(),
epilog='See "manila help COMMAND" '
'for help on a specific command.',
add_help=False,
formatter_class=OpenStackHelpFormatter,
)
# Global arguments
parser.add_argument('-h', '--help',
action='store_true',
help=argparse.SUPPRESS)
parser.add_argument('--version',
action='version',
version=manilaclient.__version__)
parser.add_argument('--debug',
action='store_true',
default=utils.env('manilaclient_DEBUG',
default=False),
help="Print debugging output")
parser.add_argument('--os-username',
metavar='<auth-user-name>',
default=utils.env('OS_USERNAME',
'MANILA_USERNAME'),
help='Defaults to env[OS_USERNAME].')
parser.add_argument('--os_username',
help=argparse.SUPPRESS)
parser.add_argument('--os-password',
metavar='<auth-password>',
default=utils.env('OS_PASSWORD',
'MANILA_PASSWORD'),
help='Defaults to env[OS_PASSWORD].')
parser.add_argument('--os_password',
help=argparse.SUPPRESS)
parser.add_argument('--os-tenant-name',
metavar='<auth-tenant-name>',
default=utils.env('OS_TENANT_NAME',
'MANILA_PROJECT_ID'),
help='Defaults to env[OS_TENANT_NAME].')
parser.add_argument('--os_tenant_name',
help=argparse.SUPPRESS)
parser.add_argument('--os-tenant-id',
metavar='<auth-tenant-id>',
default=utils.env('OS_TENANT_ID',
'MANILA_TENANT_ID'),
help='Defaults to env[OS_TENANT_ID].')
parser.add_argument('--os_tenant_id',
help=argparse.SUPPRESS)
parser.add_argument('--os-auth-url',
metavar='<auth-url>',
default=utils.env('OS_AUTH_URL',
'MANILA_URL'),
help='Defaults to env[OS_AUTH_URL].')
parser.add_argument('--os_auth_url',
help=argparse.SUPPRESS)
parser.add_argument('--os-region-name',
metavar='<region-name>',
default=utils.env('OS_REGION_NAME',
'MANILA_REGION_NAME'),
help='Defaults to env[OS_REGION_NAME].')
parser.add_argument('--os_region_name',
help=argparse.SUPPRESS)
parser.add_argument('--service-type',
metavar='<service-type>',
help='Defaults to compute for most actions')
parser.add_argument('--service_type',
help=argparse.SUPPRESS)
parser.add_argument('--service-name',
metavar='<service-name>',
default=utils.env('MANILA_SERVICE_NAME'),
help='Defaults to env[MANILA_SERVICE_NAME]')
parser.add_argument('--service_name',
help=argparse.SUPPRESS)
parser.add_argument('--share-service-name',
metavar='<volume-service-name>',
default=utils.env('MANILA_share_service_name'),
help='Defaults to env[MANILA_share_service_name]')
parser.add_argument('--share_service_name',
help=argparse.SUPPRESS)
parser.add_argument('--endpoint-type',
metavar='<endpoint-type>',
default=utils.env('MANILA_ENDPOINT_TYPE',
default=DEFAULT_MANILA_ENDPOINT_TYPE),
help='Defaults to env[MANILA_ENDPOINT_TYPE] or '
+ DEFAULT_MANILA_ENDPOINT_TYPE + '.')
parser.add_argument('--endpoint_type',
help=argparse.SUPPRESS)
parser.add_argument('--os-volume-api-version',
metavar='<compute-api-ver>',
default=utils.env('OS_SHARE_API_VERSION',
default=DEFAULT_OS_SHARE_API_VERSION),
help='Accepts 1 or 2,defaults '
'to env[OS_SHARE_API_VERSION].')
parser.add_argument('--os_volume_api_version',
help=argparse.SUPPRESS)
parser.add_argument('--os-cacert',
metavar='<ca-certificate>',
default=utils.env('OS_CACERT', default=None),
help='Specify a CA bundle file to use in '
'verifying a TLS (https) server certificate. '
'Defaults to env[OS_CACERT]')
parser.add_argument('--insecure',
default=utils.env('manilaclient_INSECURE',
default=False),
action='store_true',
help=argparse.SUPPRESS)
parser.add_argument('--retries',
metavar='<retries>',
type=int,
default=0,
help='Number of retries.')
# FIXME(dtroyer): The args below are here for diablo compatibility,
# remove them in folsum cycle
# alias for --os-username, left in for backwards compatibility
parser.add_argument('--username',
help=argparse.SUPPRESS)
# alias for --os-region_name, left in for backwards compatibility
parser.add_argument('--region_name',
help=argparse.SUPPRESS)
# alias for --os-password, left in for backwards compatibility
parser.add_argument('--apikey', '--password', dest='apikey',
default=utils.env('MANILA_API_KEY'),
help=argparse.SUPPRESS)
# alias for --os-tenant-name, left in for backward compatibility
parser.add_argument('--projectid', '--tenant_name', dest='projectid',
default=utils.env('MANILA_PROJECT_ID'),
help=argparse.SUPPRESS)
# alias for --os-auth-url, left in for backward compatibility
parser.add_argument('--url', '--auth_url', dest='url',
default=utils.env('MANILA_URL'),
help=argparse.SUPPRESS)
return parser
def get_subcommand_parser(self, version):
parser = self.get_base_parser()
self.subcommands = {}
subparsers = parser.add_subparsers(metavar='<subcommand>')
try:
actions_module = {
'1.1': shell_v1,
'2': shell_v2,
}[version]
except KeyError:
actions_module = shell_v1
self._find_actions(subparsers, actions_module)
self._find_actions(subparsers, self)
for extension in self.extensions:
self._find_actions(subparsers, extension.module)
self._add_bash_completion_subparser(subparsers)
return parser
def _discover_extensions(self, version):
extensions = []
for name, module in itertools.chain(
self._discover_via_python_path(version),
self._discover_via_contrib_path(version)):
extension = manilaclient.extension.Extension(name, module)
extensions.append(extension)
return extensions
def _discover_via_python_path(self, version):
for (module_loader, name, ispkg) in pkgutil.iter_modules():
if name.endswith('python_manilaclient_ext'):
if not hasattr(module_loader, 'load_module'):
# Python 2.6 compat: actually get an ImpImporter obj
module_loader = module_loader.find_module(name)
module = module_loader.load_module(name)
yield name, module
def _discover_via_contrib_path(self, version):
module_path = os.path.dirname(os.path.abspath(__file__))
version_str = "v%s" % version.replace('.', '_')
ext_path = os.path.join(module_path, version_str, 'contrib')
ext_glob = os.path.join(ext_path, "*.py")
for ext_path in glob.iglob(ext_glob):
name = os.path.basename(ext_path)[:-3]
if name == "__init__":
continue
module = imp.load_source(name, ext_path)
yield name, module
def _add_bash_completion_subparser(self, subparsers):
subparser = subparsers.add_parser(
'bash_completion',
add_help=False,
formatter_class=OpenStackHelpFormatter)
self.subcommands['bash_completion'] = subparser
subparser.set_defaults(func=self.do_bash_completion)
def _find_actions(self, subparsers, actions_module):
for attr in (a for a in dir(actions_module) if a.startswith('do_')):
# I prefer to be hypen-separated instead of underscores.
command = attr[3:].replace('_', '-')
callback = getattr(actions_module, attr)
desc = callback.__doc__ or ''
help = desc.strip().split('\n')[0]
arguments = getattr(callback, 'arguments', [])
subparser = subparsers.add_parser(
command,
help=help,
description=desc,
add_help=False,
formatter_class=OpenStackHelpFormatter)
subparser.add_argument('-h', '--help',
action='help',
help=argparse.SUPPRESS,)
self.subcommands[command] = subparser
for (args, kwargs) in arguments:
subparser.add_argument(*args, **kwargs)
subparser.set_defaults(func=callback)
def setup_debugging(self, debug):
if not debug:
return
streamhandler = logging.StreamHandler()
streamformat = "%(levelname)s (%(module)s:%(lineno)d) %(message)s"
streamhandler.setFormatter(logging.Formatter(streamformat))
logger.setLevel(logging.DEBUG)
logger.addHandler(streamhandler)
def main(self, argv):
# Parse args once to find version and debug settings
parser = self.get_base_parser()
(options, args) = parser.parse_known_args(argv)
self.setup_debugging(options.debug)
# build available subcommands based on version
self.extensions = self._discover_extensions(
options.os_volume_api_version)
self._run_extension_hooks('__pre_parse_args__')
subcommand_parser = self.get_subcommand_parser(
options.os_volume_api_version)
self.parser = subcommand_parser
if options.help or not argv:
subcommand_parser.print_help()
return 0
args = subcommand_parser.parse_args(argv)
self._run_extension_hooks('__post_parse_args__', args)
# Short-circuit and deal with help right away.
if args.func == self.do_help:
self.do_help(args)
return 0
elif args.func == self.do_bash_completion:
self.do_bash_completion(args)
return 0
(os_username, os_password, os_tenant_name, os_auth_url,
os_region_name, os_tenant_id, endpoint_type, insecure,
service_type, service_name, share_service_name,
username, apikey, projectid, url, region_name, cacert) = (
args.os_username, args.os_password,
args.os_tenant_name, args.os_auth_url,
args.os_region_name, args.os_tenant_id,
args.endpoint_type, args.insecure,
args.service_type, args.service_name,
args.share_service_name, args.username,
args.apikey, args.projectid,
args.url, args.region_name, args.os_cacert)
if not endpoint_type:
endpoint_type = DEFAULT_MANILA_ENDPOINT_TYPE
if not service_type:
service_type = DEFAULT_MANILA_SERVICE_TYPE
service_type = utils.get_service_type(args.func) or service_type
#FIXME(usrleon): Here should be restrict for project id same as
# for os_username or os_password but for compatibility it is not.
if not utils.isunauthenticated(args.func):
if not os_username:
if not username:
raise exc.CommandError(
"You must provide a username "
"via either --os-username or env[OS_USERNAME]")
else:
os_username = username
if not os_password:
if not apikey:
raise exc.CommandError("You must provide a password "
"via either --os-password or via "
"env[OS_PASSWORD]")
else:
os_password = apikey
if not (os_tenant_name or os_tenant_id):
if not projectid:
raise exc.CommandError("You must provide a tenant_id "
"via either --os-tenant-id or "
"env[OS_TENANT_ID]")
else:
os_tenant_name = projectid
if not os_auth_url:
if not url:
raise exc.CommandError(
"You must provide an auth url "
"via either --os-auth-url or env[OS_AUTH_URL]")
else:
os_auth_url = url
if not os_region_name and region_name:
os_region_name = region_name
if not (os_tenant_name or os_tenant_id):
raise exc.CommandError(
"You must provide a tenant_id "
"via either --os-tenant-id or env[OS_TENANT_ID]")
if not os_auth_url:
raise exc.CommandError(
"You must provide an auth url "
"via either --os-auth-url or env[OS_AUTH_URL]")
self.cs = client.Client(options.os_volume_api_version, os_username,
os_password, os_tenant_name, os_auth_url,
insecure, region_name=os_region_name,
tenant_id=os_tenant_id,
endpoint_type=endpoint_type,
extensions=self.extensions,
service_type=service_type,
service_name=service_name,
share_service_name=share_service_name,
retries=options.retries,
http_log_debug=args.debug,
cacert=cacert)
try:
if not utils.isunauthenticated(args.func):
self.cs.authenticate()
except exc.Unauthorized:
raise exc.CommandError("Invalid OpenStack Manila credentials.")
except exc.AuthorizationFailure:
raise exc.CommandError("Unable to authorize user")
args.func(self.cs, args)
def _run_extension_hooks(self, hook_type, *args, **kwargs):
"""Run hooks for all registered extensions."""
for extension in self.extensions:
extension.run_hooks(hook_type, *args, **kwargs)
def do_bash_completion(self, args):
"""Print arguments for bash_completion.
Prints all of the commands and options to stdout so that the
manila.bash_completion script doesn't have to hard code them.
"""
commands = set()
options = set()
for sc_str, sc in self.subcommands.items():
commands.add(sc_str)
for option in sc._optionals._option_string_actions.keys():
options.add(option)
commands.remove('bash-completion')
commands.remove('bash_completion')
print ' '.join(commands | options)
@utils.arg('command', metavar='<subcommand>', nargs='?',
help='Display help for <subcommand>')
def do_help(self, args):
"""
Display help about this program or one of its subcommands.
"""
if args.command:
if args.command in self.subcommands:
self.subcommands[args.command].print_help()
else:
raise exc.CommandError("'%s' is not a valid subcommand" %
args.command)
else:
self.parser.print_help()
# I'm picky about my shell help.
class OpenStackHelpFormatter(argparse.HelpFormatter):
def start_section(self, heading):
# Title-case the headings
heading = '%s%s' % (heading[0].upper(), heading[1:])
super(OpenStackHelpFormatter, self).start_section(heading)
def main():
try:
OpenStackManilaShell().main(map(strutils.safe_decode, sys.argv[1:]))
except KeyboardInterrupt:
print >> sys.stderr, "... terminating manila client"
sys.exit(130)
except Exception, e:
logger.debug(e, exc_info=1)
message = e.message
if not isinstance(message, basestring):
message = str(message)
print >> sys.stderr, "ERROR: %s" % strutils.safe_encode(message)
sys.exit(1)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,266 @@
import os
import re
import sys
import uuid
import prettytable
from manilaclient import exceptions
from manilaclient.openstack.common import strutils
def arg(*args, **kwargs):
"""Decorator for CLI args."""
def _decorator(func):
add_arg(func, *args, **kwargs)
return func
return _decorator
def env(*vars, **kwargs):
"""
returns the first environment variable set
if none are non-empty, defaults to '' or keyword arg default
"""
for v in vars:
value = os.environ.get(v, None)
if value:
return value
return kwargs.get('default', '')
def add_arg(f, *args, **kwargs):
"""Bind CLI arguments to a shell.py `do_foo` function."""
if not hasattr(f, 'arguments'):
f.arguments = []
# NOTE(sirp): avoid dups that can occur when the module is shared across
# tests.
if (args, kwargs) not in f.arguments:
# Because of the sematics of decorator composition if we just append
# to the options list positional options will appear to be backwards.
f.arguments.insert(0, (args, kwargs))
def add_resource_manager_extra_kwargs_hook(f, hook):
"""Adds hook to bind CLI arguments to ResourceManager calls.
The `do_foo` calls in shell.py will receive CLI args and then in turn pass
them through to the ResourceManager. Before passing through the args, the
hooks registered here will be called, giving us a chance to add extra
kwargs (taken from the command-line) to what's passed to the
ResourceManager.
"""
if not hasattr(f, 'resource_manager_kwargs_hooks'):
f.resource_manager_kwargs_hooks = []
names = [h.__name__ for h in f.resource_manager_kwargs_hooks]
if hook.__name__ not in names:
f.resource_manager_kwargs_hooks.append(hook)
def get_resource_manager_extra_kwargs(f, args, allow_conflicts=False):
"""Return extra_kwargs by calling resource manager kwargs hooks."""
hooks = getattr(f, "resource_manager_kwargs_hooks", [])
extra_kwargs = {}
for hook in hooks:
hook_name = hook.__name__
hook_kwargs = hook(args)
conflicting_keys = set(hook_kwargs.keys()) & set(extra_kwargs.keys())
if conflicting_keys and not allow_conflicts:
raise Exception("Hook '%(hook_name)s' is attempting to redefine"
" attributes '%(conflicting_keys)s'" % locals())
extra_kwargs.update(hook_kwargs)
return extra_kwargs
def unauthenticated(f):
"""
Adds 'unauthenticated' attribute to decorated function.
Usage:
@unauthenticated
def mymethod(f):
...
"""
f.unauthenticated = True
return f
def isunauthenticated(f):
"""
Checks to see if the function is marked as not requiring authentication
with the @unauthenticated decorator. Returns True if decorator is
set to True, False otherwise.
"""
return getattr(f, 'unauthenticated', False)
def service_type(stype):
"""
Adds 'service_type' attribute to decorated function.
Usage:
@service_type('volume')
def mymethod(f):
...
"""
def inner(f):
f.service_type = stype
return f
return inner
def get_service_type(f):
"""
Retrieves service type from function
"""
return getattr(f, 'service_type', None)
def pretty_choice_list(l):
return ', '.join("'%s'" % i for i in l)
def print_list(objs, fields, formatters={}):
mixed_case_fields = ['serverId']
pt = prettytable.PrettyTable([f for f in fields], caching=False)
pt.aligns = ['l' for f in fields]
for o in objs:
row = []
for field in fields:
if field in formatters:
row.append(formatters[field](o))
else:
if field in mixed_case_fields:
field_name = field.replace(' ', '_')
else:
field_name = field.lower().replace(' ', '_')
data = getattr(o, field_name, '')
row.append(data)
pt.add_row(row)
if len(objs) > 0:
print strutils.safe_encode(pt.get_string(sortby=fields[0]))
def print_dict(d, property="Property"):
pt = prettytable.PrettyTable([property, 'Value'], caching=False)
pt.aligns = ['l', 'l']
[pt.add_row(list(r)) for r in d.iteritems()]
print strutils.safe_encode(pt.get_string(sortby=property))
def find_resource(manager, name_or_id):
"""Helper for the _find_* methods."""
# first try to get entity as integer id
try:
if isinstance(name_or_id, int) or name_or_id.isdigit():
return manager.get(int(name_or_id))
except exceptions.NotFound:
pass
# now try to get entity as uuid
try:
uuid.UUID(strutils.safe_decode(name_or_id))
return manager.get(name_or_id)
except (ValueError, exceptions.NotFound):
pass
try:
try:
return manager.find(human_id=name_or_id)
except exceptions.NotFound:
pass
# finally try to find entity by name
try:
return manager.find(name=name_or_id)
except exceptions.NotFound:
try:
return manager.find(display_name=name_or_id)
except (UnicodeDecodeError, exceptions.NotFound):
try:
# Volumes does not have name, but display_name
return manager.find(display_name=name_or_id)
except exceptions.NotFound:
msg = "No %s with a name or ID of '%s' exists." % \
(manager.resource_class.__name__.lower(), name_or_id)
raise exceptions.CommandError(msg)
except exceptions.NoUniqueMatch:
msg = ("Multiple %s matches found for '%s', use an ID to be more"
" specific." % (manager.resource_class.__name__.lower(),
name_or_id))
raise exceptions.CommandError(msg)
def _format_servers_list_networks(server):
output = []
for (network, addresses) in server.networks.items():
if len(addresses) == 0:
continue
addresses_csv = ', '.join(addresses)
group = "%s=%s" % (network, addresses_csv)
output.append(group)
return '; '.join(output)
class HookableMixin(object):
"""Mixin so classes can register and run hooks."""
_hooks_map = {}
@classmethod
def add_hook(cls, hook_type, hook_func):
if hook_type not in cls._hooks_map:
cls._hooks_map[hook_type] = []
cls._hooks_map[hook_type].append(hook_func)
@classmethod
def run_hooks(cls, hook_type, *args, **kwargs):
hook_funcs = cls._hooks_map.get(hook_type) or []
for hook_func in hook_funcs:
hook_func(*args, **kwargs)
def safe_issubclass(*args):
"""Like issubclass, but will just return False if not a class."""
try:
if issubclass(*args):
return True
except TypeError:
pass
return False
def import_class(import_str):
"""Returns a class from a string including module and class."""
mod_str, _sep, class_str = import_str.rpartition('.')
__import__(mod_str)
return getattr(sys.modules[mod_str], class_str)
_slugify_strip_re = re.compile(r'[^\w\s-]')
_slugify_hyphenate_re = re.compile(r'[-\s]+')
# http://code.activestate.com/recipes/
# 577257-slugify-make-a-string-usable-in-a-url-or-filename/
def slugify(value):
"""
Normalizes string, converts to lowercase, removes non-alpha characters,
and converts spaces to hyphens.
From Django's "django/template/defaultfilters.py".
"""
import unicodedata
if not isinstance(value, unicode):
value = unicode(value)
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
value = unicode(_slugify_strip_re.sub('', value).strip().lower())
return _slugify_hyphenate_re.sub('-', value)

View File

@ -0,0 +1,17 @@
# Copyright (c) 2012 OpenStack, LLC.
#
# 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 manilaclient.v1.client import Client

View File

@ -0,0 +1,79 @@
from manilaclient import client
from manilaclient.v1 import limits
from manilaclient.v1 import quota_classes
from manilaclient.v1 import quotas
from manilaclient.v1 import shares
from manilaclient.v1 import share_snapshots
class Client(object):
"""
Top-level object to access the OpenStack Volume API.
Create an instance with your creds::
>>> client = Client(USERNAME, PASSWORD, PROJECT_ID, AUTH_URL)
Then call methods on its managers::
>>> client.shares.list()
...
"""
def __init__(self, username, api_key, project_id=None, auth_url='',
insecure=False, timeout=None, tenant_id=None,
proxy_tenant_id=None, proxy_token=None, region_name=None,
endpoint_type='publicURL', extensions=None,
service_type='volume', service_name=None,
share_service_name=None, retries=None,
http_log_debug=False,
cacert=None):
# FIXME(comstud): Rename the api_key argument above when we
# know it's not being used as keyword argument
password = api_key
self.limits = limits.LimitsManager(self)
# extensions
self.quota_classes = quota_classes.QuotaClassSetManager(self)
self.quotas = quotas.QuotaSetManager(self)
self.shares = shares.ShareManager(self)
self.share_snapshots = share_snapshots.ShareSnapshotManager(self)
# Add in any extensions...
if extensions:
for extension in extensions:
if extension.manager_class:
setattr(self, extension.name,
extension.manager_class(self))
self.client = client.HTTPClient(
username,
password,
project_id,
auth_url,
insecure=insecure,
timeout=timeout,
tenant_id=tenant_id,
proxy_token=proxy_token,
proxy_tenant_id=proxy_tenant_id,
region_name=region_name,
endpoint_type=endpoint_type,
service_type=service_type,
service_name=service_name,
share_service_name=share_service_name,
retries=retries,
http_log_debug=http_log_debug,
cacert=cacert)
def authenticate(self):
"""
Authenticate against the server.
Normally this is called automatically when you first access the API,
but you can call this method to force authentication right now.
Returns on success; raises :exc:`exceptions.Unauthorized` if the
credentials are wrong.
"""
self.client.authenticate()

View File

@ -0,0 +1,47 @@
# Copyright 2011 OpenStack LLC.
# 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 manilaclient import base
from manilaclient import utils
class ListExtResource(base.Resource):
@property
def summary(self):
descr = self.description.strip()
if not descr:
return '??'
lines = descr.split("\n")
if len(lines) == 1:
return lines[0]
else:
return lines[0] + "..."
class ListExtManager(base.Manager):
resource_class = ListExtResource
def show_all(self):
return self._list("/extensions", 'extensions')
@utils.service_type('share')
def do_list_extensions(client, _args):
"""
List all the os-api extensions that are available.
"""
extensions = client.list_extensions.show_all()
fields = ["Name", "Summary", "Alias", "Updated"]
utils.print_list(extensions, fields)

View File

@ -0,0 +1,79 @@
# Copyright 2011 OpenStack LLC.
from manilaclient import base
class Limits(base.Resource):
"""A collection of RateLimit and AbsoluteLimit objects"""
def __repr__(self):
return "<Limits>"
@property
def absolute(self):
for (name, value) in self._info['absolute'].items():
yield AbsoluteLimit(name, value)
@property
def rate(self):
for group in self._info['rate']:
uri = group['uri']
regex = group['regex']
for rate in group['limit']:
yield RateLimit(rate['verb'], uri, regex, rate['value'],
rate['remaining'], rate['unit'],
rate['next-available'])
class RateLimit(object):
"""Data model that represents a flattened view of a single rate limit"""
def __init__(self, verb, uri, regex, value, remain,
unit, next_available):
self.verb = verb
self.uri = uri
self.regex = regex
self.value = value
self.remain = remain
self.unit = unit
self.next_available = next_available
def __eq__(self, other):
return self.uri == other.uri \
and self.regex == other.regex \
and self.value == other.value \
and self.verb == other.verb \
and self.remain == other.remain \
and self.unit == other.unit \
and self.next_available == other.next_available
def __repr__(self):
return "<RateLimit: method=%s uri=%s>" % (self.method, self.uri)
class AbsoluteLimit(object):
"""Data model that represents a single absolute limit"""
def __init__(self, name, value):
self.name = name
self.value = value
def __eq__(self, other):
return self.value == other.value and self.name == other.name
def __repr__(self):
return "<AbsoluteLimit: name=%s>" % (self.name)
class LimitsManager(base.Manager):
"""Manager object used to interact with limits resource"""
resource_class = Limits
def get(self):
"""
Get a specific extension.
:rtype: :class:`Limits`
"""
return self._get("/limits", "limits")

View File

@ -0,0 +1,52 @@
# Copyright 2012 OpenStack LLC.
# 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 manilaclient import base
class QuotaClassSet(base.Resource):
@property
def id(self):
"""QuotaClassSet does not have a 'id' attribute but base.Resource
needs it to self-refresh and QuotaSet is indexed by class_name"""
return self.class_name
def update(self, *args, **kwargs):
self.manager.update(self.class_name, *args, **kwargs)
class QuotaClassSetManager(base.ManagerWithFind):
resource_class = QuotaClassSet
def get(self, class_name):
return self._get("/os-quota-class-sets/%s" % (class_name),
"quota_class_set")
def update(self,
class_name,
volumes=None,
gigabytes=None):
body = {'quota_class_set': {
'class_name': class_name,
'volumes': volumes,
'gigabytes': gigabytes}}
for key in body['quota_class_set'].keys():
if body['quota_class_set'][key] is None:
body['quota_class_set'].pop(key)
self._update('/os-quota-class-sets/%s' % (class_name), body)

View File

@ -0,0 +1,55 @@
# Copyright 2011 OpenStack LLC.
# 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 manilaclient import base
class QuotaSet(base.Resource):
@property
def id(self):
"""QuotaSet does not have a 'id' attribute but base.Resource needs it
to self-refresh and QuotaSet is indexed by tenant_id"""
return self.tenant_id
def update(self, *args, **kwargs):
self.manager.update(self.tenant_id, *args, **kwargs)
class QuotaSetManager(base.ManagerWithFind):
resource_class = QuotaSet
def get(self, tenant_id):
if hasattr(tenant_id, 'tenant_id'):
tenant_id = tenant_id.tenant_id
return self._get("/os-quota-sets/%s" % (tenant_id), "quota_set")
def update(self, tenant_id, volumes=None, snapshots=None, gigabytes=None):
body = {'quota_set': {
'tenant_id': tenant_id,
'volumes': volumes,
'snapshots': snapshots,
'gigabytes': gigabytes}}
for key in body['quota_set'].keys():
if body['quota_set'][key] is None:
body['quota_set'].pop(key)
self._update('/os-quota-sets/%s' % (tenant_id), body)
def defaults(self, tenant_id):
return self._get('/os-quota-sets/%s/defaults' % tenant_id,
'quota_set')

View File

@ -0,0 +1,974 @@
# Copyright 2010 Jacob Kaplan-Moss
# Copyright 2011 OpenStack LLC.
# 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 argparse
import os
import sys
import time
from manilaclient import exceptions
from manilaclient import utils
def _poll_for_status(poll_fn, obj_id, action, final_ok_states,
poll_period=5, show_progress=True):
"""Block while an action is being performed, periodically printing
progress.
"""
def print_progress(progress):
if show_progress:
msg = ('\rInstance %(action)s... %(progress)s%% complete'
% dict(action=action, progress=progress))
else:
msg = '\rInstance %(action)s...' % dict(action=action)
sys.stdout.write(msg)
sys.stdout.flush()
print
while True:
obj = poll_fn(obj_id)
status = obj.status.lower()
progress = getattr(obj, 'progress', None) or 0
if status in final_ok_states:
print_progress(100)
print "\nFinished"
break
elif status == "error":
print "\nError %(action)s instance" % locals()
break
else:
print_progress(progress)
time.sleep(poll_period)
def _find_volume(cs, volume):
"""Get a volume by ID."""
return utils.find_resource(cs.volumes, volume)
def _find_volume_snapshot(cs, snapshot):
"""Get a volume snapshot by ID."""
return utils.find_resource(cs.volume_snapshots, snapshot)
def _find_backup(cs, backup):
"""Get a backup by ID."""
return utils.find_resource(cs.backups, backup)
def _print_volume(volume):
utils.print_dict(volume._info)
def _print_volume_snapshot(snapshot):
utils.print_dict(snapshot._info)
def _find_share(cs, share):
"""Get a share by ID."""
return utils.find_resource(cs.shares, share)
def _print_share(cs, share):
info = share._info.copy()
info.pop('links', None)
utils.print_dict(info)
def _find_share_snapshot(cs, snapshot):
"""Get a snapshot by ID."""
return utils.find_resource(cs.share_snapshots, snapshot)
def _print_share_snapshot(cs, snapshot):
info = snapshot._info.copy()
info.pop('links', None)
utils.print_dict(info)
def _translate_keys(collection, convert):
for item in collection:
keys = item.__dict__.keys()
for from_key, to_key in convert:
if from_key in keys and to_key not in keys:
setattr(item, to_key, item._info[from_key])
def _translate_volume_keys(collection):
convert = [('displayName', 'display_name'), ('volumeType', 'volume_type')]
_translate_keys(collection, convert)
def _translate_volume_snapshot_keys(collection):
convert = [('displayName', 'display_name'), ('volumeId', 'volume_id')]
_translate_keys(collection, convert)
def _extract_metadata(args):
metadata = {}
for metadatum in args.metadata:
# unset doesn't require a val, so we have the if/else
if '=' in metadatum:
(key, value) = metadatum.split('=', 1)
else:
key = metadatum
value = None
metadata[key] = value
return metadata
@utils.arg(
'--all-tenants',
dest='all_tenants',
metavar='<0|1>',
nargs='?',
type=int,
const=1,
default=0,
help='Display information from all tenants (Admin only).')
@utils.arg(
'--all_tenants',
nargs='?',
type=int,
const=1,
help=argparse.SUPPRESS)
@utils.arg(
'--display-name',
metavar='<display-name>',
default=None,
help='Filter results by display-name')
@utils.arg(
'--status',
metavar='<status>',
default=None,
help='Filter results by status')
@utils.service_type('share')
def do_list(cs, args):
"""List all the volumes."""
all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants))
search_opts = {
'all_tenants': all_tenants,
'display_name': args.display_name,
'status': args.status,
}
volumes = cs.volumes.list(search_opts=search_opts)
_translate_volume_keys(volumes)
# Create a list of servers to which the volume is attached
for vol in volumes:
servers = [s.get('server_id') for s in vol.attachments]
setattr(vol, 'attached_to', ','.join(map(str, servers)))
utils.print_list(volumes, ['ID', 'Status', 'Display Name',
'Size', 'Volume Type', 'Bootable', 'Attached to'])
@utils.arg('volume', metavar='<volume>', help='ID of the volume.')
@utils.service_type('share')
def do_show(cs, args):
"""Show details about a volume."""
volume = _find_volume(cs, args.volume)
_print_volume(volume)
@utils.arg('size',
metavar='<size>',
type=int,
help='Size of volume in GB')
@utils.arg(
'--snapshot-id',
metavar='<snapshot-id>',
default=None,
help='Create volume from snapshot id (Optional, Default=None)')
@utils.arg(
'--snapshot_id',
help=argparse.SUPPRESS)
@utils.arg(
'--source-volid',
metavar='<source-volid>',
default=None,
help='Create volume from volume id (Optional, Default=None)')
@utils.arg(
'--source_volid',
help=argparse.SUPPRESS)
@utils.arg(
'--image-id',
metavar='<image-id>',
default=None,
help='Create volume from image id (Optional, Default=None)')
@utils.arg(
'--image_id',
help=argparse.SUPPRESS)
@utils.arg(
'--display-name',
metavar='<display-name>',
default=None,
help='Volume name (Optional, Default=None)')
@utils.arg(
'--display_name',
help=argparse.SUPPRESS)
@utils.arg(
'--display-description',
metavar='<display-description>',
default=None,
help='Volume description (Optional, Default=None)')
@utils.arg(
'--display_description',
help=argparse.SUPPRESS)
@utils.arg(
'--volume-type',
metavar='<volume-type>',
default=None,
help='Volume type (Optional, Default=None)')
@utils.arg(
'--volume_type',
help=argparse.SUPPRESS)
@utils.arg(
'--availability-zone',
metavar='<availability-zone>',
default=None,
help='Availability zone for volume (Optional, Default=None)')
@utils.arg(
'--availability_zone',
help=argparse.SUPPRESS)
@utils.arg('--metadata',
type=str,
nargs='*',
metavar='<key=value>',
help='Metadata key=value pairs (Optional, Default=None)',
default=None)
@utils.service_type('share')
def do_create(cs, args):
"""Add a new volume."""
volume_metadata = None
if args.metadata is not None:
volume_metadata = _extract_metadata(args)
volume = cs.volumes.create(args.size,
args.snapshot_id,
args.source_volid,
args.display_name,
args.display_description,
args.volume_type,
availability_zone=args.availability_zone,
imageRef=args.image_id,
metadata=volume_metadata)
_print_volume(volume)
@utils.arg('volume', metavar='<volume>', help='ID of the volume to delete.')
@utils.service_type('share')
def do_delete(cs, args):
"""Remove a volume."""
volume = _find_volume(cs, args.volume)
volume.delete()
@utils.arg('volume', metavar='<volume>', help='ID of the volume to delete.')
@utils.service_type('share')
def do_force_delete(cs, args):
"""Attempt forced removal of a volume, regardless of its state."""
volume = _find_volume(cs, args.volume)
volume.force_delete()
@utils.arg('volume', metavar='<volume>', help='ID of the volume to rename.')
@utils.arg('display_name', nargs='?', metavar='<display-name>',
help='New display-name for the volume.')
@utils.arg('--display-description', metavar='<display-description>',
help='Optional volume description. (Default=None)',
default=None)
@utils.service_type('share')
def do_rename(cs, args):
"""Rename a volume."""
kwargs = {}
if args.display_name is not None:
kwargs['display_name'] = args.display_name
if args.display_description is not None:
kwargs['display_description'] = args.display_description
_find_volume(cs, args.volume).update(**kwargs)
@utils.arg('volume',
metavar='<volume>',
help='ID of the volume to update metadata on.')
@utils.arg('action',
metavar='<action>',
choices=['set', 'unset'],
help="Actions: 'set' or 'unset'")
@utils.arg('metadata',
metavar='<key=value>',
nargs='+',
default=[],
help='Metadata to set/unset (only key is necessary on unset)')
@utils.service_type('share')
def do_metadata(cs, args):
"""Set or Delete metadata on a volume."""
volume = _find_volume(cs, args.volume)
metadata = _extract_metadata(args)
if args.action == 'set':
cs.volumes.set_metadata(volume, metadata)
elif args.action == 'unset':
cs.volumes.delete_metadata(volume, metadata.keys())
@utils.arg(
'--all-tenants',
dest='all_tenants',
metavar='<0|1>',
nargs='?',
type=int,
const=1,
default=0,
help='Display information from all tenants (Admin only).')
@utils.arg(
'--all_tenants',
nargs='?',
type=int,
const=1,
help=argparse.SUPPRESS)
@utils.arg(
'--display-name',
metavar='<display-name>',
default=None,
help='Filter results by display-name')
@utils.arg(
'--status',
metavar='<status>',
default=None,
help='Filter results by status')
@utils.arg(
'--volume-id',
metavar='<volume-id>',
default=None,
help='Filter results by volume-id')
@utils.service_type('share')
def do_snapshot_list(cs, args):
"""List all the snapshots."""
all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants))
search_opts = {
'all_tenants': all_tenants,
'display_name': args.display_name,
'status': args.status,
'volume_id': args.volume_id,
}
snapshots = cs.volume_snapshots.list(search_opts=search_opts)
_translate_volume_snapshot_keys(snapshots)
utils.print_list(snapshots,
['ID', 'Volume ID', 'Status', 'Display Name', 'Size',
'Source Type'])
@utils.arg('snapshot', metavar='<snapshot>', help='ID of the snapshot.')
@utils.service_type('share')
def do_snapshot_show(cs, args):
"""Show details about a snapshot."""
snapshot = _find_volume_snapshot(cs, args.snapshot)
_print_volume_snapshot(snapshot)
@utils.arg('volume_id',
metavar='<volume-id>',
help='ID of the volume to snapshot')
@utils.arg('--force',
metavar='<True|False>',
help='Optional flag to indicate whether '
'to snapshot a volume even if it\'s '
'attached to an instance. (Default=False)',
default=False)
@utils.arg(
'--display-name',
metavar='<display-name>',
default=None,
help='Optional snapshot name. (Default=None)')
@utils.arg(
'--display_name',
help=argparse.SUPPRESS)
@utils.arg(
'--display-description',
metavar='<display-description>',
default=None,
help='Optional snapshot description. (Default=None)')
@utils.arg(
'--display_description',
help=argparse.SUPPRESS)
@utils.service_type('share')
def do_snapshot_create(cs, args):
"""Add a new snapshot."""
snapshot = cs.volume_snapshots.create(args.volume_id,
args.force,
args.display_name,
args.display_description)
_print_volume_snapshot(snapshot)
@utils.arg('snapshot_id',
metavar='<snapshot-id>',
help='ID of the snapshot to delete.')
@utils.service_type('share')
def do_snapshot_delete(cs, args):
"""Remove a snapshot."""
snapshot = _find_volume_snapshot(cs, args.snapshot_id)
snapshot.delete()
@utils.arg('snapshot', metavar='<snapshot>', help='ID of the snapshot.')
@utils.arg('display_name', nargs='?', metavar='<display-name>',
help='New display-name for the snapshot.')
@utils.arg('--display-description', metavar='<display-description>',
help='Optional snapshot description. (Default=None)',
default=None)
@utils.service_type('share')
def do_snapshot_rename(cs, args):
"""Rename a snapshot."""
kwargs = {}
if args.display_name is not None:
kwargs['display_name'] = args.display_name
if args.display_description is not None:
kwargs['display_description'] = args.display_description
_find_volume_snapshot(cs, args.snapshot).update(**kwargs)
def _print_volume_type_list(vtypes):
utils.print_list(vtypes, ['ID', 'Name'])
def _print_type_and_extra_specs_list(vtypes):
formatters = {'extra_specs': _print_type_extra_specs}
utils.print_list(vtypes, ['ID', 'Name', 'extra_specs'], formatters)
@utils.service_type('share')
def do_type_list(cs, args):
"""Print a list of available 'volume types'."""
vtypes = cs.volume_types.list()
_print_volume_type_list(vtypes)
@utils.service_type('share')
def do_extra_specs_list(cs, args):
"""Print a list of current 'volume types and extra specs' (Admin Only)."""
vtypes = cs.volume_types.list()
_print_type_and_extra_specs_list(vtypes)
@utils.arg('name',
metavar='<name>',
help="Name of the new volume type")
@utils.service_type('share')
def do_type_create(cs, args):
"""Create a new volume type."""
vtype = cs.volume_types.create(args.name)
_print_volume_type_list([vtype])
@utils.arg('id',
metavar='<id>',
help="Unique ID of the volume type to delete")
@utils.service_type('share')
def do_type_delete(cs, args):
"""Delete a specific volume type"""
cs.volume_types.delete(args.id)
@utils.arg('vtype',
metavar='<vtype>',
help="Name or ID of the volume type")
@utils.arg('action',
metavar='<action>',
choices=['set', 'unset'],
help="Actions: 'set' or 'unset'")
@utils.arg('metadata',
metavar='<key=value>',
nargs='*',
default=None,
help='Extra_specs to set/unset (only key is necessary on unset)')
@utils.service_type('share')
def do_type_key(cs, args):
"Set or unset extra_spec for a volume type."""
vtype = _find_volume_type(cs, args.vtype)
if args.metadata is not None:
keypair = _extract_metadata(args)
if args.action == 'set':
vtype.set_keys(keypair)
elif args.action == 'unset':
vtype.unset_keys(keypair.keys())
def do_endpoints(cs, args):
"""Discover endpoints that get returned from the authenticate services"""
catalog = cs.client.service_catalog.catalog
for e in catalog['access']['serviceCatalog']:
utils.print_dict(e['endpoints'][0], e['name'])
def do_credentials(cs, args):
"""Show user credentials returned from auth"""
catalog = cs.client.service_catalog.catalog
utils.print_dict(catalog['access']['user'], "User Credentials")
utils.print_dict(catalog['access']['token'], "Token")
_quota_resources = ['volumes', 'snapshots', 'gigabytes']
def _quota_show(quotas):
quota_dict = {}
for resource in _quota_resources:
quota_dict[resource] = getattr(quotas, resource, None)
utils.print_dict(quota_dict)
def _quota_update(manager, identifier, args):
updates = {}
for resource in _quota_resources:
val = getattr(args, resource, None)
if val is not None:
updates[resource] = val
if updates:
manager.update(identifier, **updates)
@utils.arg('tenant', metavar='<tenant_id>',
help='UUID of tenant to list the quotas for.')
@utils.service_type('share')
def do_quota_show(cs, args):
"""List the quotas for a tenant."""
_quota_show(cs.quotas.get(args.tenant))
@utils.arg('tenant', metavar='<tenant_id>',
help='UUID of tenant to list the default quotas for.')
@utils.service_type('share')
def do_quota_defaults(cs, args):
"""List the default quotas for a tenant."""
_quota_show(cs.quotas.defaults(args.tenant))
@utils.arg('tenant', metavar='<tenant_id>',
help='UUID of tenant to set the quotas for.')
@utils.arg('--volumes',
metavar='<volumes>',
type=int, default=None,
help='New value for the "volumes" quota.')
@utils.arg('--snapshots',
metavar='<snapshots>',
type=int, default=None,
help='New value for the "snapshots" quota.')
@utils.arg('--gigabytes',
metavar='<gigabytes>',
type=int, default=None,
help='New value for the "gigabytes" quota.')
@utils.service_type('share')
def do_quota_update(cs, args):
"""Update the quotas for a tenant."""
_quota_update(cs.quotas, args.tenant, args)
@utils.arg('class_name', metavar='<class>',
help='Name of quota class to list the quotas for.')
@utils.service_type('share')
def do_quota_class_show(cs, args):
"""List the quotas for a quota class."""
_quota_show(cs.quota_classes.get(args.class_name))
@utils.arg('class_name', metavar='<class>',
help='Name of quota class to set the quotas for.')
@utils.arg('--volumes',
metavar='<volumes>',
type=int, default=None,
help='New value for the "volumes" quota.')
@utils.arg('--snapshots',
metavar='<snapshots>',
type=int, default=None,
help='New value for the "snapshots" quota.')
@utils.arg('--gigabytes',
metavar='<gigabytes>',
type=int, default=None,
help='New value for the "gigabytes" quota.')
@utils.service_type('share')
def do_quota_class_update(cs, args):
"""Update the quotas for a quota class."""
_quota_update(cs.quota_classes, args.class_name, args)
@utils.service_type('share')
def do_absolute_limits(cs, args):
"""Print a list of absolute limits for a user"""
limits = cs.limits.get().absolute
columns = ['Name', 'Value']
utils.print_list(limits, columns)
@utils.service_type('share')
def do_rate_limits(cs, args):
"""Print a list of rate limits for a user"""
limits = cs.limits.get().rate
columns = ['Verb', 'URI', 'Value', 'Remain', 'Unit', 'Next_Available']
utils.print_list(limits, columns)
def _print_type_extra_specs(vol_type):
try:
return vol_type.get_keys()
except exceptions.NotFound:
return "N/A"
def _find_volume_type(cs, vtype):
"""Get a volume type by name or ID."""
return utils.find_resource(cs.volume_types, vtype)
@utils.arg('volume_id',
metavar='<volume-id>',
help='ID of the volume to upload to an image')
@utils.arg('--force',
metavar='<True|False>',
help='Optional flag to indicate whether '
'to upload a volume even if it\'s '
'attached to an instance. (Default=False)',
default=False)
@utils.arg('--container-format',
metavar='<container-format>',
help='Optional type for container format '
'(Default=bare)',
default='bare')
@utils.arg('--disk-format',
metavar='<disk-format>',
help='Optional type for disk format '
'(Default=raw)',
default='raw')
@utils.arg('image_name',
metavar='<image-name>',
help='Name for created image')
@utils.service_type('share')
def do_upload_to_image(cs, args):
"""Upload volume to image service as image."""
volume = _find_volume(cs, args.volume_id)
volume.upload_to_image(args.force,
args.image_name,
args.container_format,
args.disk_format)
@utils.arg('volume', metavar='<volume>',
help='ID of the volume to backup.')
@utils.arg('--container', metavar='<container>',
help='Optional Backup container name. (Default=None)',
default=None)
@utils.arg('--display-name', metavar='<display-name>',
help='Optional backup name. (Default=None)',
default=None)
@utils.arg('--display-description', metavar='<display-description>',
help='Optional backup description. (Default=None)',
default=None)
@utils.service_type('share')
def do_backup_create(cs, args):
"""Creates a backup."""
cs.backups.create(args.volume,
args.container,
args.display_name,
args.display_description)
@utils.arg('backup', metavar='<backup>', help='ID of the backup.')
@utils.service_type('share')
def do_backup_show(cs, args):
"""Show details about a backup."""
backup = _find_backup(cs, args.backup)
info = dict()
info.update(backup._info)
if 'links' in info:
info.pop('links')
utils.print_dict(info)
@utils.service_type('share')
def do_backup_list(cs, args):
"""List all the backups."""
backups = cs.backups.list()
columns = ['ID', 'Volume ID', 'Status', 'Name', 'Size', 'Object Count',
'Container']
utils.print_list(backups, columns)
@utils.arg('backup', metavar='<backup>',
help='ID of the backup to delete.')
@utils.service_type('share')
def do_backup_delete(cs, args):
"""Remove a backup."""
backup = _find_backup(cs, args.backup)
backup.delete()
@utils.arg('backup', metavar='<backup>',
help='ID of the backup to restore.')
@utils.arg('--volume-id', metavar='<volume-id>',
help='Optional ID of the volume to restore to.',
default=None)
@utils.service_type('share')
def do_backup_restore(cs, args):
"""Restore a backup."""
cs.restores.restore(args.backup,
args.volume_id)
@utils.arg(
'share_protocol',
metavar='<share_protocol>',
type=str,
help='Share type (NFS or CIFS)')
@utils.arg(
'size',
metavar='<size>',
type=int,
help='Share size in GB')
@utils.arg(
'--snapshot-id',
metavar='<snapshot-id>',
help='Optional snapshot id to create the share from. (Default=None)',
default=None)
@utils.arg(
'--display-name',
metavar='<display-name>',
help='Optional share name. (Default=None)',
default=None)
@utils.arg(
'--display_name',
help=argparse.SUPPRESS)
@utils.arg(
'--display-description',
metavar='<display-description>',
help='Optional share description. (Default=None)',
default=None)
@utils.arg(
'--display_description',
help=argparse.SUPPRESS)
@utils.service_type('share')
def do_share_create(cs, args):
"""Creates new NAS storage (NFS or CIFS)."""
share = cs.shares.create(args.share_protocol, args.size, args.snapshot_id,
args.display_name, args.display_description)
_print_share(cs, share)
@utils.arg(
'share',
metavar='<share>',
help='ID of the NAS to delete.')
@utils.service_type('share')
def do_share_delete(cs, args):
"""Deletes NAS storage."""
cs.shares.delete(args.share)
@utils.arg(
'share',
metavar='<share>',
help='ID of the NAS share.')
@utils.service_type('share')
def do_share_show(cs, args):
"""Show details about a NAS share."""
share = _find_share(cs, args.share)
_print_share(cs, share)
@utils.arg(
'share',
metavar='<share>',
help='ID of the NAS share to modify.')
@utils.arg(
'access_type',
metavar='<access_type>',
help='access rule type (only "ip" is supported).')
@utils.arg(
'access_to',
metavar='<access_to>',
help='Value that defines access')
@utils.service_type('share')
def do_share_allow(cs, args):
"""Allow access to the share."""
share = _find_share(cs, args.share)
share.allow(args.access_type, args.access_to)
@utils.arg(
'share',
metavar='<share>',
help='ID of the NAS share to modify.')
@utils.arg(
'id',
metavar='<id>',
help='id of the access rule to be deleted.')
@utils.service_type('share')
def do_share_deny(cs, args):
"""Deny access to a share."""
share = _find_share(cs, args.share)
share.deny(args.id)
@utils.arg(
'share',
metavar='<share>',
help='ID of the share.')
@utils.service_type('share')
def do_share_access_list(cs, args):
"""Show access list for share."""
share = _find_share(cs, args.share)
access_list = share.access_list()
utils.print_list(access_list, ['id', 'access type', 'access to', 'state'])
@utils.arg(
'--all-tenants',
dest='all_tenants',
metavar='<0|1>',
nargs='?',
type=int,
const=1,
default=0,
help='Display information from all tenants (Admin only).')
@utils.arg(
'--display-name',
metavar='<display-name>',
default=None,
help='Filter results by name')
@utils.arg(
'--status',
metavar='<status>',
default=None,
help='Filter results by status')
@utils.service_type('share')
def do_share_list(cs, args):
"""List all NAS shares."""
all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants))
search_opts = {
'all_tenants': all_tenants,
'display_name': args.display_name,
'status': args.status,
}
shares = cs.shares.list(search_opts=search_opts)
utils.print_list(shares,
['ID', 'Display Name', 'Size', 'Share Proto', 'Status',
'Export location'])
@utils.arg(
'--all-tenants',
dest='all_tenants',
metavar='<0|1>',
nargs='?',
type=int,
const=1,
default=0,
help='Display information from all tenants (Admin only).')
@utils.arg(
'--display-name',
metavar='<display-name>',
default=None,
help='Filter results by name')
@utils.arg(
'--status',
metavar='<status>',
default=None,
help='Filter results by status')
@utils.arg(
'--share-id',
metavar='<share-id>',
default=None,
help='Filter results by share-id')
@utils.service_type('share')
def do_share_snapshot_list(cs, args):
"""List all the snapshots."""
all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants))
search_opts = {
'all_tenants': all_tenants,
'display_name': args.display_name,
'status': args.status,
'share_id': args.share_id,
}
snapshots = cs.share_snapshots.list(search_opts=search_opts)
utils.print_list(snapshots,
['ID', 'Share ID', 'Status', 'Display Name',
'Share Size'])
@utils.arg(
'snapshot',
metavar='<snapshot>',
help='ID of the snapshot.')
@utils.service_type('share')
def do_share_snapshot_show(cs, args):
"""Show details about a snapshot."""
snapshot = _find_share_snapshot(cs, args.snapshot)
_print_share_snapshot(cs, snapshot)
@utils.arg(
'share_id',
metavar='<share-id>',
help='ID of the share to snapshot')
@utils.arg(
'--force',
metavar='<True|False>',
help='Optional flag to indicate whether '
'to snapshot a share even if it\'s busy.'
' (Default=False)',
default=False)
@utils.arg(
'--display-name',
metavar='<display-name>',
default=None,
help='Optional snapshot name. (Default=None)')
@utils.arg(
'--display-description',
metavar='<display-description>',
default=None,
help='Optional snapshot description. (Default=None)')
@utils.service_type('share')
def do_share_snapshot_create(cs, args):
"""Add a new snapshot."""
snapshot = cs.share_snapshots.create(args.share_id,
args.force,
args.display_name,
args.display_description)
_print_share_snapshot(cs, snapshot)
@utils.arg(
'snapshot_id',
metavar='<snapshot-id>',
help='ID of the snapshot to delete.')
@utils.service_type('share')
def do_share_snapshot_delete(cs, args):
"""Remove a snapshot."""
snapshot = _find_share_snapshot(cs, args.snapshot_id)
snapshot.delete()

View File

@ -29,7 +29,7 @@ class Client(object):
proxy_tenant_id=None, proxy_token=None, region_name=None,
endpoint_type='publicURL', extensions=None,
service_type='volume', service_name=None,
volume_service_name=None, retries=None,
share_service_name=None, retries=None,
http_log_debug=False,
cacert=None):
# FIXME(comstud): Rename the api_key argument above when we
@ -69,7 +69,7 @@ class Client(object):
endpoint_type=endpoint_type,
service_type=service_type,
service_name=service_name,
volume_service_name=volume_service_name,
share_service_name=share_service_name,
retries=retries,
http_log_debug=http_log_debug,
cacert=cacert)

View File

@ -0,0 +1,91 @@
# Copyright 2012 NetApp
# 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.
"""Interface for shares extention."""
import os
import urllib
from manilaclient import base
from manilaclient import utils
class ShareSnapshot(base.Resource):
"""Represent a snapshot of a share."""
def __repr__(self):
return "<ShareSnapshot: %s>" % self.id
def delete(self):
"""Delete this snapshot."""
self.manager.delete(self)
class ShareSnapshotManager(base.ManagerWithFind):
"""Manage :class:`ShareSnapshot` resources.
"""
resource_class = ShareSnapshot
def create(self, share_id, force=False, name=None, description=None):
"""Create a snapshot of the given share.
:param share_id: The ID of the share to snapshot.
:param force: If force is True, create a snapshot even if the
share is busy. Default is False.
:param name: Name of the snapshot
:param description: Description of the snapshot
:rtype: :class:`ShareSnapshot`
"""
body = {'share-snapshot': {'share_id': share_id,
'force': force,
'name': name,
'description': description}}
return self._create('/share-snapshots', body, 'share-snapshot')
def get(self, snapshot_id):
"""Get a snapshot.
:param snapshot_id: The ID of the snapshot to get.
:rtype: :class:`ShareSnapshot`
"""
return self._get('/share-snapshots/%s' % snapshot_id, 'share-snapshot')
def list(self, detailed=True, search_opts=None):
"""Get a list of all snapshots of shares.
:rtype: list of :class:`ShareSnapshot`
"""
if search_opts:
query_string = urllib.urlencode([(key, value)
for (key, value)
in search_opts.items()
if value])
if query_string:
query_string = "?%s" % (query_string,)
else:
query_string = ''
if detailed:
path = "/share-snapshots/detail%s" % (query_string,)
else:
path = "/share-snapshots%s" % (query_string,)
return self._list(path, 'share-snapshots')
def delete(self, snapshot):
"""Delete a snapshot of a share.
:param share: The :class:`ShareSnapshot` to delete.
"""
self._delete("/share-snapshots/%s" % base.getid(snapshot))

View File

@ -0,0 +1,182 @@
# Copyright 2012 NetApp
# 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.
"""Interface for shares extention."""
import collections
import os
import re
import urllib
from manilaclient import base
from manilaclient import exceptions
from manilaclient import utils
class Share(base.Resource):
"""A share is an extra block level storage to the OpenStack instances."""
def __repr__(self):
return "<Share: %s>" % self.id
def delete(self):
"""Delete this share."""
self.manager.delete(self)
def allow(self, access_type, access):
"""Allow access to a share."""
self._validate_access(access_type, access)
return self.manager.allow(self, access_type, access)
def deny(self, id):
"""Deny access from IP to a share."""
return self.manager.deny(self, id)
def access_list(self):
"""Deny access from IP to a share."""
return self.manager.access_list(self)
def _validate_access(self, access_type, access):
if access_type == 'ip':
self._validate_ip_range(access)
elif access_type == 'passwd':
self._validate_username(access)
else:
raise exceptions.CommandError(
'Only ip and passwd type are supported')
@staticmethod
def _validate_username(access):
valid_useraname_re = '\w{4,32}'
username = access
if not re.match(valid_useraname_re, username):
exc_str = _('Invalid user name. Must be alphanum 4-32 chars long')
raise exceptions.CommandError(exc_str)
@staticmethod
def _validate_ip_range(ip_range):
ip_range = ip_range.split('/')
exc_str = ('Supported ip format examples:\n'
'\t10.0.0.2, 10.0.0.*, 10.0.0.0/24')
if len(ip_range) > 2:
raise exceptions.CommandError(exc_str)
allow_asterisk = (len(ip_range) == 1)
ip_range = ip_range[0].split('.')
if len(ip_range) != 4:
raise exceptions.CommandError(exc_str)
for item in ip_range:
try:
if 0 <= int(item) <= 255:
continue
raise ValueError()
except ValueError:
if not (allow_asterisk and item == '*'):
raise exceptions.CommandError(exc_str)
class ShareManager(base.ManagerWithFind):
"""Manage :class:`Share` resources."""
resource_class = Share
def create(self, share_proto, size, snapshot_id=None, name=None,
description=None):
"""Create NAS.
:param size: Size of NAS in GB
:param snapshot_id: ID of the snapshot
:param name: Name of the NAS
:param description: Short description of a share
:param share_proto: Type of NAS (NFS or CIFS)
:rtype: :class:`Share`
"""
body = {'share': {'size': size,
'snapshot_id': snapshot_id,
'name': name,
'description': description,
'share_proto': share_proto}}
return self._create('/shares', body, 'share')
def get(self, share_id):
"""Get a share.
:param share_id: The ID of the share to delete.
:rtype: :class:`Share`
"""
return self._get("/shares/%s" % share_id, "share")
def list(self, detailed=True, search_opts=None):
"""Get a list of all shares.
:rtype: list of :class:`Share`
"""
if search_opts:
query_string = urllib.urlencode([(key, value)
for (key, value)
in search_opts.items()
if value])
if query_string:
query_string = "?%s" % (query_string,)
else:
query_string = ''
if detailed:
path = "/shares/detail%s" % (query_string,)
else:
path = "/shares%s" % (query_string,)
return self._list(path, 'shares')
def delete(self, share):
"""Delete a share.
:param share: The :class:`Share` to delete.
"""
self._delete("/shares/%s" % base.getid(share))
def allow(self, share, access_type, access):
"""Allow access from IP to a shares.
:param share: The :class:`Share` to delete.
:param access_type: string that represents access type ('ip','domain')
:param access: string that represents access ('127.0.0.1')
"""
return self._action('os-allow_access', share,
{'access_type': access_type,
'access_to': access})
def deny(self, share, id):
"""Deny access from IP to a shares.
:param share: The :class:`Share` to delete.
:param ip: string that represents ip address
"""
return self._action('os-deny_access', share, {'access_id': id})
def access_list(self, share):
"""Get access list to the share."""
access_list = self._action("os-access_list", share)[1]["access_list"]
if access_list:
t = collections.namedtuple('Access', access_list[0].keys())
return [t(*value.values()) for value in access_list]
else:
return []
def _action(self, action, share, info=None, **kwargs):
"""Perform a share 'action'."""
body = {action: info}
self.run_hooks('modify_body_for_action', body, **kwargs)
url = '/shares/%s/action' % base.getid(share)
return self.api.client.post(url, body=body)
#########################

View File

@ -0,0 +1,569 @@
Metadata-Version: 1.1
Name: pep8
Version: 1.4.6
Summary: Python style guide checker
Home-page: http://pep8.readthedocs.org/
Author: Johann C. Rocholl
Author-email: johann@rocholl.net
License: Expat license
Description: pep8 - Python style guide checker
=================================
pep8 is a tool to check your Python code against some of the style
conventions in `PEP 8`_.
.. _PEP 8: http://www.python.org/dev/peps/pep-0008/
Features
--------
* Plugin architecture: Adding new checks is easy.
* Parseable output: Jump to error location in your editor.
* Small: Just one Python file, requires only stdlib. You can use just
the pep8.py file for this purpose.
* Comes with a comprehensive test suite.
Installation
------------
You can install, upgrade, uninstall pep8.py with these commands::
$ pip install pep8
$ pip install --upgrade pep8
$ pip uninstall pep8
There's also a package for Debian/Ubuntu, but it's not always the
latest version.
Example usage and output
------------------------
::
$ pep8 --first optparse.py
optparse.py:69:11: E401 multiple imports on one line
optparse.py:77:1: E302 expected 2 blank lines, found 1
optparse.py:88:5: E301 expected 1 blank line, found 0
optparse.py:222:34: W602 deprecated form of raising exception
optparse.py:347:31: E211 whitespace before '('
optparse.py:357:17: E201 whitespace after '{'
optparse.py:472:29: E221 multiple spaces before operator
optparse.py:544:21: W601 .has_key() is deprecated, use 'in'
You can also make pep8.py show the source code for each error, and
even the relevant text from PEP 8::
$ pep8 --show-source --show-pep8 testsuite/E40.py
testsuite/E40.py:2:10: E401 multiple imports on one line
import os, sys
^
Imports should usually be on separate lines.
Okay: import os\nimport sys
E401: import sys, os
Or you can display how often each error was found::
$ pep8 --statistics -qq Python-2.5/Lib
232 E201 whitespace after '['
599 E202 whitespace before ')'
631 E203 whitespace before ','
842 E211 whitespace before '('
2531 E221 multiple spaces before operator
4473 E301 expected 1 blank line, found 0
4006 E302 expected 2 blank lines, found 1
165 E303 too many blank lines (4)
325 E401 multiple imports on one line
3615 E501 line too long (82 characters)
612 W601 .has_key() is deprecated, use 'in'
1188 W602 deprecated form of raising exception
Links
-----
.. image:: https://api.travis-ci.org/jcrocholl/pep8.png?branch=master
:target: https://travis-ci.org/jcrocholl/pep8
:alt: Build status
* `Read the documentation <http://pep8.readthedocs.org/>`_
* `Fork me on GitHub <http://github.com/jcrocholl/pep8>`_
Changelog
=========
1.4.6 (2013-07-02)
------------------
* Honor ``# noqa`` for errors E711 and E712. (Issue #180)
* When both a ``tox.ini`` and a ``setup.cfg`` are present in the project
directory, merge their contents. The ``tox.ini`` file takes
precedence (same as before). (Issue #182)
* Give priority to ``--select`` over ``--ignore``. (Issue #188)
* Compare full path when excluding a file. (Issue #186)
* Correctly report other E12 errors when E123 is ignored. (Issue #103)
* New option ``--hang-closing`` to switch to the alternative style of
closing bracket indentation for hanging indent. Add error E133 for
closing bracket which is missing indentation. (Issue #103)
* Accept both styles of closing bracket indentation for hanging indent.
Do not report error E123 in the default configuration. (Issue #103)
* Do not crash when running AST checks and the document contains null bytes.
(Issue #184)
* Fix false positive E261/E262 when the file contains a BOM. (Issue #193)
* Fix E701, E702 and E703 not detected sometimes. (Issue #196)
* Fix E122 not detected in some cases. (Issue #201 and #208)
* Fix false positive E121 with multiple brackets. (Issue #203)
1.4.5 (2013-03-06)
------------------
* When no path is specified, do not try to read from stdin. The feature
was added in 1.4.3, but it is not supported on Windows. Use ``-``
filename argument to read from stdin. This usage is supported
since 1.3.4. (Issue #170)
* Do not require ``setuptools`` in setup.py. It works around an issue
with ``pip`` and Python 3. (Issue #172)
* Add ``__pycache__`` to the ignore list.
* Change misleading message for E251. (Issue #171)
* Do not report false E302 when the source file has a coding cookie or a
comment on the first line. (Issue #174)
* Reorganize the tests and add tests for the API and for the command line
usage and options. (Issues #161 and #162)
* Ignore all checks which are not explicitly selected when ``select`` is
passed to the ``StyleGuide`` constructor.
1.4.4 (2013-02-24)
------------------
* Report E227 or E228 instead of E225 for whitespace around bitwise, shift
or modulo operators. (Issue #166)
* Change the message for E226 to make clear that it is about arithmetic
operators.
* Fix a false positive E128 for continuation line indentation with tabs.
* Fix regression with the ``--diff`` option. (Issue #169)
* Fix the ``TestReport`` class to print the unexpected warnings and
errors.
1.4.3 (2013-02-22)
------------------
* Hide the ``--doctest`` and ``--testsuite`` options when installed.
* Fix crash with AST checkers when the syntax is invalid. (Issue #160)
* Read from standard input if no path is specified.
* Initiate a graceful shutdown on ``Control+C``.
* Allow to change the ``checker_class`` for the ``StyleGuide``.
1.4.2 (2013-02-10)
------------------
* Support AST checkers provided by third-party applications.
* Register new checkers with ``register_check(func_or_cls, codes)``.
* Allow to construct a ``StyleGuide`` with a custom parser.
* Accept visual indentation without parenthesis after the ``if``
statement. (Issue #151)
* Fix UnboundLocalError when using ``# noqa`` with continued lines.
(Issue #158)
* Re-order the lines for the ``StandardReport``.
* Expand tabs when checking E12 continuation lines. (Issue #155)
* Refactor the testing class ``TestReport`` and the specific test
functions into a separate test module.
1.4.1 (2013-01-18)
------------------
* Allow sphinx.ext.autodoc syntax for comments. (Issue #110)
* Report E703 instead of E702 for the trailing semicolon. (Issue #117)
* Honor ``# noqa`` in addition to ``# nopep8``. (Issue #149)
* Expose the ``OptionParser`` factory for better extensibility.
1.4 (2012-12-22)
----------------
* Report E226 instead of E225 for optional whitespace around common
operators (``*``, ``**``, ``/``, ``+`` and ``-``). This new error
code is ignored in the default configuration because PEP 8 recommends
to "use your own judgement". (Issue #96)
* Lines with a ``# nopep8`` at the end will not issue errors on line
length E501 or continuation line indentation E12*. (Issue #27)
* Fix AssertionError when the source file contains an invalid line
ending ``"\r\r\n"``. (Issue #119)
* Read the ``[pep8]`` section of ``tox.ini`` or ``setup.cfg`` if present.
(Issue #93 and #141)
* Add the Sphinx-based documentation, and publish it
on http://pep8.readthedocs.org/. (Issue #105)
1.3.4 (2012-12-18)
------------------
* Fix false positive E124 and E128 with comments. (Issue #100)
* Fix error on stdin when running with bpython. (Issue #101)
* Fix false positive E401. (Issue #104)
* Report E231 for nested dictionary in list. (Issue #142)
* Catch E271 at the beginning of the line. (Issue #133)
* Fix false positive E126 for multi-line comments. (Issue #138)
* Fix false positive E221 when operator is preceded by a comma. (Issue #135)
* Fix ``--diff`` failing on one-line hunk. (Issue #137)
* Fix the ``--exclude`` switch for directory paths. (Issue #111)
* Use ``-`` filename to read from standard input. (Issue #128)
1.3.3 (2012-06-27)
------------------
* Fix regression with continuation line checker. (Issue #98)
1.3.2 (2012-06-26)
------------------
* Revert to the previous behaviour for ``--show-pep8``:
do not imply ``--first``. (Issue #89)
* Add E902 for IO errors. (Issue #87)
* Fix false positive for E121, and missed E124. (Issue #92)
* Set a sensible default path for config file on Windows. (Issue #95)
* Allow ``verbose`` in the configuration file. (Issue #91)
* Show the enforced ``max-line-length`` in the error message. (Issue #86)
1.3.1 (2012-06-18)
------------------
* Explain which configuration options are expected. Accept and recommend
the options names with hyphen instead of underscore. (Issue #82)
* Do not read the user configuration when used as a module
(except if ``config_file=True`` is passed to the ``StyleGuide`` constructor).
* Fix wrong or missing cases for the E12 series.
* Fix cases where E122 was missed. (Issue #81)
1.3 (2012-06-15)
----------------
.. warning::
The internal API is backwards incompatible.
* Remove global configuration and refactor the library around
a ``StyleGuide`` class; add the ability to configure various
reporters. (Issue #35 and #66)
* Read user configuration from ``~/.config/pep8``
and local configuration from ``./.pep8``. (Issue #22)
* Fix E502 for backslash embedded in multi-line string. (Issue #68)
* Fix E225 for Python 3 iterable unpacking (PEP 3132). (Issue #72)
* Enable the new checkers from the E12 series in the default
configuration.
* Suggest less error-prone alternatives for E712 errors.
* Rewrite checkers to run faster (E22, E251, E27).
* Fixed a crash when parsed code is invalid (too many
closing brackets).
* Fix E127 and E128 for continuation line indentation. (Issue #74)
* New option ``--format`` to customize the error format. (Issue #23)
* New option ``--diff`` to check only modified code. The unified
diff is read from STDIN. Example: ``hg diff | pep8 --diff``
(Issue #39)
* Correctly report the count of failures and set the exit code to 1
when the ``--doctest`` or the ``--testsuite`` fails.
* Correctly detect the encoding in Python 3. (Issue #69)
* Drop support for Python 2.3, 2.4 and 3.0. (Issue #78)
1.2 (2012-06-01)
----------------
* Add E121 through E128 for continuation line indentation. These
checks are disabled by default. If you want to force all checks,
use switch ``--select=E,W``. Patch by Sam Vilain. (Issue #64)
* Add E721 for direct type comparisons. (Issue #47)
* Add E711 and E712 for comparisons to singletons. (Issue #46)
* Fix spurious E225 and E701 for function annotations. (Issue #29)
* Add E502 for explicit line join between brackets.
* Fix E901 when printing source with ``--show-source``.
* Report all errors for each checker, instead of reporting only the
first occurence for each line.
* Option ``--show-pep8`` implies ``--first``.
1.1 (2012-05-24)
----------------
* Add E901 for syntax errors. (Issues #63 and #30)
* Add E271, E272, E273 and E274 for extraneous whitespace around
keywords. (Issue #57)
* Add ``tox.ini`` configuration file for tests. (Issue #61)
* Add ``.travis.yml`` configuration file for continuous integration.
(Issue #62)
1.0.1 (2012-04-06)
------------------
* Fix inconsistent version numbers.
1.0 (2012-04-04)
----------------
* Fix W602 ``raise`` to handle multi-char names. (Issue #53)
0.7.0 (2012-03-26)
------------------
* Now ``--first`` prints only the first occurence of each error.
The ``--repeat`` flag becomes obsolete because it is the default
behaviour. (Issue #6)
* Allow to specify ``--max-line-length``. (Issue #36)
* Make the shebang more flexible. (Issue #26)
* Add testsuite to the bundle. (Issue #25)
* Fixes for Jython. (Issue #49)
* Add PyPI classifiers. (Issue #43)
* Fix the ``--exclude`` option. (Issue #48)
* Fix W602, accept ``raise`` with 3 arguments. (Issue #34)
* Correctly select all tests if ``DEFAULT_IGNORE == ''``.
0.6.1 (2010-10-03)
------------------
* Fix inconsistent version numbers. (Issue #21)
0.6.0 (2010-09-19)
------------------
* Test suite reorganized and enhanced in order to check more failures
with fewer test files. Read the ``run_tests`` docstring for details
about the syntax.
* Fix E225: accept ``print >>sys.stderr, "..."`` syntax.
* Fix E501 for lines containing multibyte encoded characters. (Issue #7)
* Fix E221, E222, E223, E224 not detected in some cases. (Issue #16)
* Fix E211 to reject ``v = dic['a'] ['b']``. (Issue #17)
* Exit code is always 1 if any error or warning is found. (Issue #10)
* ``--ignore`` checks are now really ignored, especially in
conjunction with ``--count``. (Issue #8)
* Blank lines with spaces yield W293 instead of W291: some developers
want to ignore this warning and indent the blank lines to paste their
code easily in the Python interpreter.
* Fix E301: do not require a blank line before an indented block. (Issue #14)
* Fix E203 to accept NumPy slice notation ``a[0, :]``. (Issue #13)
* Performance improvements.
* Fix decoding and checking non-UTF8 files in Python 3.
* Fix E225: reject ``True+False`` when running on Python 3.
* Fix an exception when the line starts with an operator.
* Allow a new line before closing ``)``, ``}`` or ``]``. (Issue #5)
0.5.0 (2010-02-17)
------------------
* Changed the ``--count`` switch to print to sys.stderr and set
exit code to 1 if any error or warning is found.
* E241 and E242 are removed from the standard checks. If you want to
include these checks, use switch ``--select=E,W``. (Issue #4)
* Blank line is not mandatory before the first class method or nested
function definition, even if there's a docstring. (Issue #1)
* Add the switch ``--version``.
* Fix decoding errors with Python 3. (Issue #13 [1]_)
* Add ``--select`` option which is mirror of ``--ignore``.
* Add checks E261 and E262 for spaces before inline comments.
* New check W604 warns about deprecated usage of backticks.
* New check W603 warns about the deprecated operator ``<>``.
* Performance improvement, due to rewriting of E225.
* E225 now accepts:
- no whitespace after unary operator or similar. (Issue #9 [1]_)
- lambda function with argument unpacking or keyword defaults.
* Reserve "2 blank lines" for module-level logical blocks. (E303)
* Allow multi-line comments. (E302, issue #10 [1]_)
0.4.2 (2009-10-22)
------------------
* Decorators on classes and class methods are OK now.
0.4 (2009-10-20)
----------------
* Support for all versions of Python from 2.3 to 3.1.
* New and greatly expanded self tests.
* Added ``--count`` option to print the total number of errors and warnings.
* Further improvements to the handling of comments and blank lines.
(Issue #1 [1]_ and others changes.)
* Check all py files in directory when passed a directory (Issue
#2 [1]_). This also prevents an exception when traversing directories
with non ``*.py`` files.
* E231 should allow commas to be followed by ``)``. (Issue #3 [1]_)
* Spaces are no longer required around the equals sign for keyword
arguments or default parameter values.
.. [1] These issues refer to the `previous issue tracker`__.
.. __: http://github.com/cburroughs/pep8.py/issues
0.3.1 (2009-09-14)
------------------
* Fixes for comments: do not count them when checking for blank lines between
items.
* Added setup.py for pypi upload and easy_installability.
0.2 (2007-10-16)
----------------
* Loads of fixes and improvements.
0.1 (2006-10-01)
----------------
* First release.
Keywords: pep8
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules

View File

@ -0,0 +1,55 @@
CHANGES.txt
MANIFEST.in
README.rst
pep8.py
setup.cfg
setup.py
docs/Makefile
docs/advanced.rst
docs/api.rst
docs/conf.py
docs/developer.rst
docs/index.rst
docs/intro.rst
docs/make.bat
pep8.egg-info/PKG-INFO
pep8.egg-info/SOURCES.txt
pep8.egg-info/dependency_links.txt
pep8.egg-info/entry_points.txt
pep8.egg-info/namespace_packages.txt
pep8.egg-info/not-zip-safe
pep8.egg-info/top_level.txt
testsuite/E10.py
testsuite/E11.py
testsuite/E12.py
testsuite/E12not.py
testsuite/E20.py
testsuite/E21.py
testsuite/E22.py
testsuite/E23.py
testsuite/E24.py
testsuite/E25.py
testsuite/E26.py
testsuite/E27.py
testsuite/E30.py
testsuite/E30not.py
testsuite/E40.py
testsuite/E50.py
testsuite/E70.py
testsuite/E71.py
testsuite/E72.py
testsuite/E90.py
testsuite/W19.py
testsuite/W29.py
testsuite/W39.py
testsuite/W60.py
testsuite/__init__.py
testsuite/latin-1.py
testsuite/noqa.py
testsuite/python3.py
testsuite/support.py
testsuite/test_all.py
testsuite/test_api.py
testsuite/test_shell.py
testsuite/utf-8-bom.py
testsuite/utf-8.py

View File

@ -0,0 +1,3 @@
[console_scripts]
pep8 = pep8:_main

View File

@ -0,0 +1,11 @@
../pep8.py
../pep8.pyc
./
top_level.txt
not-zip-safe
SOURCES.txt
dependency_links.txt
PKG-INFO
namespace_packages.txt
entry_points.txt
../../../../bin/pep8

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
Metadata-Version: 1.1
Name: pip
Version: 1.4.1
Summary: A tool for installing and managing Python packages.
Home-page: http://www.pip-installer.org
Author: The pip developers
Author-email: python-virtualenv@groups.google.com
License: MIT
Description:
Project Info
============
* Project Page: https://github.com/pypa/pip
* Install howto: http://www.pip-installer.org/en/latest/installing.html
* Changelog: http://www.pip-installer.org/en/latest/news.html
* Bug Tracking: https://github.com/pypa/pip/issues
* Mailing list: http://groups.google.com/group/python-virtualenv
* Docs: http://www.pip-installer.org/
* IRC: #pip on Freenode.
Quickstart
==========
Install a package:
::
$ pip install SomePackage==1.0
[...]
Successfully installed SomePackage
Show what files were installed:
::
$ pip show --files SomePackage
Name: SomePackage
Version: 1.0
Location: /my/env/lib/pythonx.x/site-packages
Files:
../somepackage/__init__.py
[...]
List what packages are outdated:
::
$ pip list --outdated
SomePackage (Current: 1.0 Latest: 2.0)
Upgrade a package:
::
$ pip install --upgrade SomePackage
[...]
Found existing installation: SomePackage 1.0
Uninstalling SomePackage:
Successfully uninstalled SomePackage
Running setup.py install for SomePackage
Successfully installed SomePackage
Uninstall a package:
::
$ pip uninstall SomePackage
Uninstalling SomePackage:
/my/env/lib/pythonx.x/site-packages/somepackage
Proceed (y/n)? y
Successfully uninstalled SomePackage
Keywords: easy_install distutils setuptools egg virtualenv
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Software Development :: Build Tools
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.1
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3

View File

@ -0,0 +1,116 @@
AUTHORS.txt
CHANGES.txt
LICENSE.txt
MANIFEST.in
PROJECT.txt
README.rst
setup.cfg
setup.py
docs/configuration.rst
docs/cookbook.rst
docs/development.rst
docs/index.rst
docs/installing.rst
docs/logic.rst
docs/news.rst
docs/other-tools.rst
docs/quickstart.rst
docs/usage.rst
pip/__init__.py
pip/__main__.py
pip/basecommand.py
pip/baseparser.py
pip/cacert.pem
pip/cmdoptions.py
pip/download.py
pip/exceptions.py
pip/index.py
pip/locations.py
pip/log.py
pip/pep425tags.py
pip/req.py
pip/runner.py
pip/status_codes.py
pip/util.py
pip/wheel.py
pip.egg-info/PKG-INFO
pip.egg-info/SOURCES.txt
pip.egg-info/dependency_links.txt
pip.egg-info/entry_points.txt
pip.egg-info/not-zip-safe
pip.egg-info/requires.txt
pip.egg-info/top_level.txt
pip/backwardcompat/__init__.py
pip/backwardcompat/ssl_match_hostname.py
pip/commands/__init__.py
pip/commands/bundle.py
pip/commands/completion.py
pip/commands/freeze.py
pip/commands/help.py
pip/commands/install.py
pip/commands/list.py
pip/commands/search.py
pip/commands/show.py
pip/commands/uninstall.py
pip/commands/unzip.py
pip/commands/wheel.py
pip/commands/zip.py
pip/vcs/__init__.py
pip/vcs/bazaar.py
pip/vcs/git.py
pip/vcs/mercurial.py
pip/vcs/subversion.py
pip/vendor/__init__.py
pip/vendor/six.py
pip/vendor/distlib/__init__.py
pip/vendor/distlib/compat.py
pip/vendor/distlib/database.py
pip/vendor/distlib/index.py
pip/vendor/distlib/locators.py
pip/vendor/distlib/manifest.py
pip/vendor/distlib/markers.py
pip/vendor/distlib/metadata.py
pip/vendor/distlib/resources.py
pip/vendor/distlib/scripts.py
pip/vendor/distlib/util.py
pip/vendor/distlib/version.py
pip/vendor/distlib/wheel.py
pip/vendor/distlib/_backport/__init__.py
pip/vendor/distlib/_backport/misc.py
pip/vendor/distlib/_backport/shutil.py
pip/vendor/distlib/_backport/sysconfig.py
pip/vendor/distlib/_backport/tarfile.py
pip/vendor/html5lib/__init__.py
pip/vendor/html5lib/constants.py
pip/vendor/html5lib/html5parser.py
pip/vendor/html5lib/ihatexml.py
pip/vendor/html5lib/inputstream.py
pip/vendor/html5lib/sanitizer.py
pip/vendor/html5lib/tokenizer.py
pip/vendor/html5lib/utils.py
pip/vendor/html5lib/filters/__init__.py
pip/vendor/html5lib/filters/_base.py
pip/vendor/html5lib/filters/alphabeticalattributes.py
pip/vendor/html5lib/filters/inject_meta_charset.py
pip/vendor/html5lib/filters/lint.py
pip/vendor/html5lib/filters/optionaltags.py
pip/vendor/html5lib/filters/sanitizer.py
pip/vendor/html5lib/filters/whitespace.py
pip/vendor/html5lib/serializer/__init__.py
pip/vendor/html5lib/serializer/htmlserializer.py
pip/vendor/html5lib/treebuilders/__init__.py
pip/vendor/html5lib/treebuilders/_base.py
pip/vendor/html5lib/treebuilders/dom.py
pip/vendor/html5lib/treebuilders/etree.py
pip/vendor/html5lib/treebuilders/etree_lxml.py
pip/vendor/html5lib/treewalkers/__init__.py
pip/vendor/html5lib/treewalkers/_base.py
pip/vendor/html5lib/treewalkers/dom.py
pip/vendor/html5lib/treewalkers/etree.py
pip/vendor/html5lib/treewalkers/genshistream.py
pip/vendor/html5lib/treewalkers/lxmletree.py
pip/vendor/html5lib/treewalkers/pulldom.py
pip/vendor/html5lib/trie/__init__.py
pip/vendor/html5lib/trie/_base.py
pip/vendor/html5lib/trie/datrie.py
pip/vendor/html5lib/trie/py.py

View File

@ -0,0 +1,4 @@
[console_scripts]
pip = pip:main
pip-2.7 = pip:main

View File

@ -0,0 +1,7 @@
[testing]
nose>=1.3.0
virtualenv>=1.10
scripttest>=1.1.1
mock

View File

@ -0,0 +1,235 @@
#!/usr/bin/env python
import os
import optparse
import sys
import re
from pip.exceptions import InstallationError, CommandError, PipError
from pip.log import logger
from pip.util import get_installed_distributions, get_prog
from pip.vcs import git, mercurial, subversion, bazaar # noqa
from pip.baseparser import create_main_parser
from pip.commands import commands, get_similar_commands, get_summaries
# The version as used in the setup.py and the docs conf.py
__version__ = "1.4.1"
def autocomplete():
"""Command and option completion for the main option parser (and options)
and its subcommands (and options).
Enable by sourcing one of the completion shell scripts (bash or zsh).
"""
# Don't complete if user hasn't sourced bash_completion file.
if 'PIP_AUTO_COMPLETE' not in os.environ:
return
cwords = os.environ['COMP_WORDS'].split()[1:]
cword = int(os.environ['COMP_CWORD'])
try:
current = cwords[cword - 1]
except IndexError:
current = ''
subcommands = [cmd for cmd, summary in get_summaries()]
options = []
# subcommand
try:
subcommand_name = [w for w in cwords if w in subcommands][0]
except IndexError:
subcommand_name = None
parser = create_main_parser()
# subcommand options
if subcommand_name:
# special case: 'help' subcommand has no options
if subcommand_name == 'help':
sys.exit(1)
# special case: list locally installed dists for uninstall command
if subcommand_name == 'uninstall' and not current.startswith('-'):
installed = []
lc = current.lower()
for dist in get_installed_distributions(local_only=True):
if dist.key.startswith(lc) and dist.key not in cwords[1:]:
installed.append(dist.key)
# if there are no dists installed, fall back to option completion
if installed:
for dist in installed:
print(dist)
sys.exit(1)
subcommand = commands[subcommand_name](parser)
options += [(opt.get_opt_string(), opt.nargs)
for opt in subcommand.parser.option_list_all
if opt.help != optparse.SUPPRESS_HELP]
# filter out previously specified options from available options
prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]]
options = [(x, v) for (x, v) in options if x not in prev_opts]
# filter options by current input
options = [(k, v) for k, v in options if k.startswith(current)]
for option in options:
opt_label = option[0]
# append '=' to options which require args
if option[1]:
opt_label += '='
print(opt_label)
else:
# show main parser options only when necessary
if current.startswith('-') or current.startswith('--'):
opts = [i.option_list for i in parser.option_groups]
opts.append(parser.option_list)
opts = (o for it in opts for o in it)
subcommands += [i.get_opt_string() for i in opts
if i.help != optparse.SUPPRESS_HELP]
print(' '.join([x for x in subcommands if x.startswith(current)]))
sys.exit(1)
def parseopts(args):
parser = create_main_parser()
parser.main = True # so the help formatter knows
# create command listing
command_summaries = get_summaries()
description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries]
parser.description = '\n'.join(description)
options, args = parser.parse_args(args)
if options.version:
sys.stdout.write(parser.version)
sys.stdout.write(os.linesep)
sys.exit()
# pip || pip help || pip --help -> print_help()
if not args or (args[0] == 'help' and len(args) == 1):
parser.print_help()
sys.exit()
if not args:
msg = ('You must give a command '
'(use "pip --help" to see a list of commands)')
raise CommandError(msg)
command = args[0].lower()
if command not in commands:
guess = get_similar_commands(command)
msg = ['unknown command "%s"' % command]
if guess:
msg.append('maybe you meant "%s"' % guess)
raise CommandError(' - '.join(msg))
return command, options, args, parser
def main(initial_args=None):
if initial_args is None:
initial_args = sys.argv[1:]
autocomplete()
try:
cmd_name, options, args, parser = parseopts(initial_args)
except PipError:
e = sys.exc_info()[1]
sys.stderr.write("ERROR: %s" % e)
sys.stderr.write(os.linesep)
sys.exit(1)
command = commands[cmd_name](parser) # see baseparser.Command
return command.main(args[1:], options)
def bootstrap():
"""
Bootstrapping function to be called from install-pip.py script.
"""
return main(['install', '--upgrade', 'pip'] + sys.argv[1:])
############################################################
## Writing freeze files
class FrozenRequirement(object):
def __init__(self, name, req, editable, comments=()):
self.name = name
self.req = req
self.editable = editable
self.comments = comments
_rev_re = re.compile(r'-r(\d+)$')
_date_re = re.compile(r'-(20\d\d\d\d\d\d)$')
@classmethod
def from_dist(cls, dist, dependency_links, find_tags=False):
location = os.path.normcase(os.path.abspath(dist.location))
comments = []
from pip.vcs import vcs, get_src_requirement
if vcs.get_backend_name(location):
editable = True
try:
req = get_src_requirement(dist, location, find_tags)
except InstallationError:
ex = sys.exc_info()[1]
logger.warn("Error when trying to get requirement for VCS system %s, falling back to uneditable format" % ex)
req = None
if req is None:
logger.warn('Could not determine repository location of %s' % location)
comments.append('## !! Could not determine repository location')
req = dist.as_requirement()
editable = False
else:
editable = False
req = dist.as_requirement()
specs = req.specs
assert len(specs) == 1 and specs[0][0] == '=='
version = specs[0][1]
ver_match = cls._rev_re.search(version)
date_match = cls._date_re.search(version)
if ver_match or date_match:
svn_backend = vcs.get_backend('svn')
if svn_backend:
svn_location = svn_backend(
).get_location(dist, dependency_links)
if not svn_location:
logger.warn(
'Warning: cannot find svn location for %s' % req)
comments.append('## FIXME: could not find svn URL in dependency_links for this package:')
else:
comments.append('# Installing as editable to satisfy requirement %s:' % req)
if ver_match:
rev = ver_match.group(1)
else:
rev = '{%s}' % date_match.group(1)
editable = True
req = '%s@%s#egg=%s' % (svn_location, rev, cls.egg_name(dist))
return cls(dist.project_name, req, editable, comments)
@staticmethod
def egg_name(dist):
name = dist.egg_name()
match = re.search(r'-py\d\.\d$', name)
if match:
name = name[:match.start()]
return name
def __str__(self):
req = self.req
if self.editable:
req = '-e %s' % req
return '\n'.join(list(self.comments) + [str(req)]) + '\n'
if __name__ == '__main__':
exit = main()
if exit:
sys.exit(exit)

View File

@ -0,0 +1,7 @@
import sys
from .runner import run
if __name__ == '__main__':
exit = run()
if exit:
sys.exit(exit)

View File

@ -0,0 +1,125 @@
"""Stuff that differs in different Python versions"""
import os
import imp
import sys
import site
__all__ = ['WindowsError']
uses_pycache = hasattr(imp, 'cache_from_source')
class NeverUsedException(Exception):
"""this exception should never be raised"""
try:
WindowsError = WindowsError
except NameError:
WindowsError = NeverUsedException
try:
#new in Python 3.3
PermissionError = PermissionError
except NameError:
PermissionError = NeverUsedException
console_encoding = sys.__stdout__.encoding
if sys.version_info >= (3,):
from io import StringIO, BytesIO
from functools import reduce
from urllib.error import URLError, HTTPError
from queue import Queue, Empty
from urllib.request import url2pathname
from urllib.request import urlretrieve
from email import message as emailmessage
import urllib.parse as urllib
import urllib.request as urllib2
import configparser as ConfigParser
import xmlrpc.client as xmlrpclib
import urllib.parse as urlparse
import http.client as httplib
def cmp(a, b):
return (a > b) - (a < b)
def b(s):
return s.encode('utf-8')
def u(s):
return s.decode('utf-8')
def console_to_str(s):
try:
return s.decode(console_encoding)
except UnicodeDecodeError:
return s.decode('utf_8')
def fwrite(f, s):
f.buffer.write(b(s))
def get_http_message_param(http_message, param, default_value):
return http_message.get_param(param, default_value)
bytes = bytes
string_types = (str,)
raw_input = input
else:
from cStringIO import StringIO
from urllib2 import URLError, HTTPError
from Queue import Queue, Empty
from urllib import url2pathname, urlretrieve
from email import Message as emailmessage
import urllib
import urllib2
import urlparse
import ConfigParser
import xmlrpclib
import httplib
def b(s):
return s
def u(s):
return s
def console_to_str(s):
return s
def fwrite(f, s):
f.write(s)
def get_http_message_param(http_message, param, default_value):
result = http_message.getparam(param)
return result or default_value
bytes = str
string_types = (basestring,)
reduce = reduce
cmp = cmp
raw_input = raw_input
BytesIO = StringIO
from distutils.sysconfig import get_python_lib, get_python_version
#site.USER_SITE was created in py2.6
user_site = getattr(site, 'USER_SITE', None)
def product(*args, **kwds):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = list(map(tuple, args)) * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x + [y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
## only >=py32 has ssl.match_hostname and ssl.CertificateError
try:
from ssl import match_hostname, CertificateError
except ImportError:
from ssl_match_hostname import match_hostname, CertificateError

Some files were not shown because too many files have changed in this diff Show More