Swap the saharaclient and savannaclient directories

Exchange the contents of the saharaclient and savannaclient directories
so that 'savannlient' is the effective alias and 'saharaclient' contains
all of the source code.

* Change all of the imports that reference savannaclient to saharaclient
* Change paths that reference savannaclient (under doc)
* Leave variable and class names unchaned at this point
* Leave references to python_savannaclient unchanged since the top
* level dir name has not yet changed

Partial-implements: blueprint savanna-renaming-client
Change-Id: I83cb21922ae5a8cec291990b3ab67bb9e3cb2d62
This commit is contained in:
Trevor McKay 2014-03-13 13:36:48 -04:00
parent 38882f7198
commit 6b014ee365
52 changed files with 880 additions and 879 deletions

View File

@ -2,6 +2,6 @@
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
${PYTHON:-python} -m subunit.run discover savannaclient $LISTOPT $IDOPTION
${PYTHON:-python} -m subunit.run discover saharaclient $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -25,7 +25,7 @@ on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('../../savannaclient'))
sys.path.insert(0, os.path.abspath('../../saharaclient'))
sys.path.append(os.path.abspath('..'))
sys.path.append(os.path.abspath('../bin'))
@ -55,7 +55,7 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
project = u'Savanna Client'
project = u'Sahara Client'
copyright = u'2013, OpenStack Foundation'
# The version info for the project you're documenting, acts as replacement for
@ -63,10 +63,10 @@ copyright = u'2013, OpenStack Foundation'
# built documents.
#
# Version info
from savannaclient.version import version_info as savannaclient_version
release = savannaclient_version.release_string()
from saharaclient.version import version_info as saharaclient_version
release = saharaclient_version.release_string()
# The short X.Y version.
version = savannaclient_version.version_string()
version = saharaclient_version.version_string()
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -122,7 +122,7 @@ if on_rtd:
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = 'Savanna Client'
html_title = 'Sahara Client'
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
@ -189,7 +189,7 @@ html_sidebars = {
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'SavannaClientDoc'
htmlhelp_basename = 'SaharaClientDoc'
# -- Options for LaTeX output --------------------------------------------------
@ -208,7 +208,7 @@ latex_elements = {
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'savannaclientdoc.tex', u'Savanna Client',
('index', 'saharaclientdoc.tex', u'Sahara Client',
u'OpenStack Foundation', 'manual'),
]
@ -238,7 +238,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'savannaclient', u'Savanna Client',
('index', 'saharaclient', u'Sahara Client',
[u'OpenStack Foundation'], 1)
]
@ -252,8 +252,8 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'Savanna Client', u'Savanna Client',
u'OpenStack Foundation', 'Savanna Client', 'Savanna Client',
('index', 'Sahara Client', u'Sahara Client',
u'OpenStack Foundation', 'Sahara Client', 'Sahara Client',
'Miscellaneous'),
]

View File

@ -1,5 +1,5 @@
[DEFAULT]
base=savannaclient
base=saharaclient
module=apiclient.exceptions
module=importutils

View File

@ -79,7 +79,7 @@ function run_tests {
if [ "x$testrargs" = "x" ]; then
testrargs="^(?!.*test_coverage_ext).*$"
fi
export PYTHON="${wrapper} coverage run --source savannaclient --parallel-mode"
export PYTHON="${wrapper} coverage run --source saharaclient --parallel-mode"
fi
# Just run the test suites in current environment
set +e
@ -160,5 +160,5 @@ fi
if [ $coverage -eq 1 ]; then
echo "Generating coverage report in covhtml/"
${wrapper} coverage combine
${wrapper} coverage html --include='savannaclient/*' --omit='savannaclient/openstack/common/*' -d covhtml -i
${wrapper} coverage html --include='saharaclient/*' --omit='saharaclient/openstack/common/*' -d covhtml -i
fi

View File

@ -16,17 +16,17 @@
from keystoneclient.v2_0 import client as keystone_client_v2
from keystoneclient.v3 import client as keystone_client_v3
from savannaclient.api import cluster_templates
from savannaclient.api import clusters
from savannaclient.api import data_sources
from savannaclient.api import httpclient
from savannaclient.api import images
from savannaclient.api import job_binaries
from savannaclient.api import job_binary_internals
from savannaclient.api import job_executions
from savannaclient.api import jobs
from savannaclient.api import node_group_templates
from savannaclient.api import plugins
from saharaclient.api import cluster_templates
from saharaclient.api import clusters
from saharaclient.api import data_sources
from saharaclient.api import httpclient
from saharaclient.api import images
from saharaclient.api import job_binaries
from saharaclient.api import job_binary_internals
from saharaclient.api import job_executions
from saharaclient.api import jobs
from saharaclient.api import node_group_templates
from saharaclient.api import plugins
class Client(object):
@ -60,7 +60,7 @@ class Client(object):
savanna_catalog_url = endpoint
break
if not savanna_catalog_url:
raise RuntimeError("Could not find Savanna endpoint in catalog")
raise RuntimeError("Could not find Sahara endpoint in catalog")
self.client = httpclient.HTTPClient(savanna_catalog_url,
input_auth_token)

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from savannaclient.api import base
from saharaclient.api import base
class ClusterTemplate(base.Resource):

View File

@ -15,7 +15,7 @@
import six
from savannaclient.api import base
from saharaclient.api import base
class Cluster(base.Resource):

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from savannaclient.api import base
from saharaclient.api import base
class DataSources(base.Resource):

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from savannaclient.api import parameters as params
from saharaclient.api import parameters as params
class Helpers(object):

View File

@ -15,7 +15,7 @@
import json
from savannaclient.api import base
from saharaclient.api import base
class Image(base.Resource):

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from savannaclient.api import base
from saharaclient.api import base
class JobBinaries(base.Resource):

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from savannaclient.api import base
from saharaclient.api import base
class JobBinaryInternal(base.Resource):

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from savannaclient.api import base
from saharaclient.api import base
class JobExecution(base.Resource):

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from savannaclient.api import base
from saharaclient.api import base
class Job(base.Resource):

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from savannaclient.api import base
from saharaclient.api import base
class NodeGroupTemplate(base.Resource):

View File

@ -15,7 +15,7 @@
from six.moves.urllib import parse as urlparse
from savannaclient.api import base
from saharaclient.api import base
class Plugin(base.Resource):

View File

@ -17,8 +17,8 @@ import argparse
import datetime
import inspect
import json
from savannaclient.nova import utils
from savannaclient.openstack.common.apiclient import exceptions
from saharaclient.nova import utils
from saharaclient.openstack.common.apiclient import exceptions
import sys
@ -121,7 +121,7 @@ def do_plugin_list(cs, args):
metavar='<plugin>',
required=True,
help='Name of the plugin.')
# TODO(mattf) - savannaclient does not support query w/ version
# TODO(mattf) - saharaclient does not support query w/ version
#@utils.arg('--version',
# metavar='<version>',
# help='Optional version')

View File

@ -13,7 +13,33 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from savannaclient import client as savannaclient
from saharaclient.openstack.common import importutils
Client = savannaclient.Client
class UnsupportedVersion(Exception):
"""Indicates that the user is trying to use an unsupported
version of the API.
"""
pass
def get_client_class(version):
version_map = {
'1.0': 'saharaclient.api.client.Client',
'1.1': 'saharaclient.api.client.Client',
}
try:
client_path = version_map[str(version)]
except (KeyError, ValueError):
supported_versions = ''.join(version_map.keys())
msg = ("Invalid client version '%(version)s'; must be one of: "
"%(versions)s") % {'version': version,
'versions': supported_versions}
raise UnsupportedVersion(msg)
return importutils.import_class(client_path)
def Client(version, *args, **kwargs):
client_class = get_client_class(version)
return client_class(*args, **kwargs)

View File

@ -19,8 +19,8 @@ import pkg_resources
import six
from savannaclient.nova import utils
from savannaclient.openstack.common.apiclient import exceptions
from saharaclient.nova import utils
from saharaclient.openstack.common.apiclient import exceptions
logger = logging.getLogger(__name__)

View File

@ -29,9 +29,9 @@ import threading
import six
from savannaclient.nova import utils
from savannaclient.openstack.common.apiclient import exceptions
from savannaclient.openstack.common import strutils
from saharaclient.nova import utils
from saharaclient.openstack.common.apiclient import exceptions
from saharaclient.openstack.common import strutils
def getid(obj):

View File

@ -13,8 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from savannaclient.nova import base
from savannaclient.nova import utils
from saharaclient.nova import base
from saharaclient.nova import utils
class Extension(utils.HookableMixin):

View File

@ -22,8 +22,8 @@ import uuid
import prettytable
import six
from savannaclient.openstack.common.apiclient import exceptions
from savannaclient.openstack.common import strutils
from saharaclient.openstack.common.apiclient import exceptions
from saharaclient.openstack.common import strutils
def arg(*args, **kwargs):

View File

@ -24,7 +24,7 @@ import os
import six
from stevedore import extension
from savannaclient.openstack.common.apiclient import exceptions
from saharaclient.openstack.common.apiclient import exceptions
_discovered_plugins = {}
@ -41,7 +41,7 @@ def discover_auth_systems():
def add_plugin(ext):
_discovered_plugins[ext.name] = ext.plugin
ep_namespace = "savannaclient.openstack.common.apiclient.auth"
ep_namespace = "saharaclient.openstack.common.apiclient.auth"
mgr = extension.ExtensionManager(ep_namespace)
mgr.map(add_plugin)

View File

@ -29,8 +29,8 @@ import copy
import six
from six.moves.urllib import parse
from savannaclient.openstack.common.apiclient import exceptions
from savannaclient.openstack.common import strutils
from saharaclient.openstack.common.apiclient import exceptions
from saharaclient.openstack.common import strutils
def getid(obj):

View File

@ -35,8 +35,8 @@ except ImportError:
import requests
from savannaclient.openstack.common.apiclient import exceptions
from savannaclient.openstack.common import importutils
from saharaclient.openstack.common.apiclient import exceptions
from saharaclient.openstack.common import importutils
_logger = logging.getLogger(__name__)
@ -60,7 +60,7 @@ class HTTPClient(object):
into terminal and send the same request with curl.
"""
user_agent = "savannaclient.openstack.common.apiclient"
user_agent = "saharaclient.openstack.common.apiclient"
def __init__(self,
auth_plugin,

View File

@ -30,7 +30,7 @@ import requests
import six
from six.moves.urllib import parse
from savannaclient.openstack.common.apiclient import client
from saharaclient.openstack.common.apiclient import client
def assert_has_keys(dct, required=[], optional=[]):

View File

@ -28,10 +28,10 @@ import prettytable
import six
from six import moves
from savannaclient.openstack.common.apiclient import exceptions
from savannaclient.openstack.common.gettextutils import _
from savannaclient.openstack.common import strutils
from savannaclient.openstack.common import uuidutils
from saharaclient.openstack.common.apiclient import exceptions
from saharaclient.openstack.common.gettextutils import _
from saharaclient.openstack.common import strutils
from saharaclient.openstack.common import uuidutils
def validate_args(fn, *args, **kwargs):

View File

@ -19,7 +19,7 @@ gettext for openstack-common modules.
Usual usage in an openstack.common module:
from savannaclient.openstack.common.gettextutils import _
from saharaclient.openstack.common.gettextutils import _
"""
import copy
@ -33,15 +33,15 @@ import re
from babel import localedata
import six
_localedir = os.environ.get('savannaclient'.upper() + '_LOCALEDIR')
_t = gettext.translation('savannaclient', localedir=_localedir, fallback=True)
_localedir = os.environ.get('saharaclient'.upper() + '_LOCALEDIR')
_t = gettext.translation('saharaclient', localedir=_localedir, fallback=True)
# We use separate translation catalogs for each log level, so set up a
# mapping between the log level name and the translator. The domain
# for the log level is project_name + "-log-" + log_level so messages
# for each level end up in their own catalog.
_t_log_levels = dict(
(level, gettext.translation('savannaclient' + '-log-' + level,
(level, gettext.translation('saharaclient' + '-log-' + level,
localedir=_localedir,
fallback=True))
for level in ['info', 'warning', 'error', 'critical']
@ -65,7 +65,7 @@ def enable_lazy():
def _(msg):
if USE_LAZY:
return Message(msg, domain='savannaclient')
return Message(msg, domain='saharaclient')
else:
if six.PY3:
return _t.gettext(msg)
@ -76,7 +76,7 @@ def _log_translation(msg, level):
"""Build a single translation of a log message
"""
if USE_LAZY:
return Message(msg, domain='savannaclient' + '-log-' + level)
return Message(msg, domain='saharaclient' + '-log-' + level)
else:
translator = _t_log_levels[level]
if six.PY3:
@ -153,7 +153,7 @@ class Message(six.text_type):
"""
def __new__(cls, msgid, msgtext=None, params=None,
domain='savannaclient', *args):
domain='saharaclient', *args):
"""Create a new Message object.
In order for translation to work gettext requires a message ID, this

View File

@ -59,7 +59,7 @@ def import_module(import_str):
def import_versioned_module(version, submodule=None):
module = 'savannaclient.v%s' % version
module = 'saharaclient.v%s' % version
if submodule:
module = '.'.join((module, submodule))
return import_module(module)

View File

@ -24,7 +24,7 @@ import unicodedata
import six
from savannaclient.openstack.common.gettextutils import _
from saharaclient.openstack.common.gettextutils import _
UNIT_PREFIX_EXPONENT = {

765
saharaclient/shell.py Normal file
View File

@ -0,0 +1,765 @@
# Copyright 2010 Jacob Kaplan-Moss
# Copyright 2011 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
###
### This code is taken from python-novaclient. Goal is minimal modification.
###
"""
Command-line interface to the OpenStack Sahara API.
"""
from __future__ import print_function
import argparse
import getpass
import glob
import imp
import itertools
import logging
import os
import pkgutil
import sys
import pkg_resources
import six
HAS_KEYRING = False
all_errors = ValueError
try:
import keyring
HAS_KEYRING = True
try:
if isinstance(keyring.get_keyring(), keyring.backend.GnomeKeyring):
import gnomekeyring
all_errors = (ValueError,
gnomekeyring.IOError,
gnomekeyring.NoKeyringDaemonError)
except Exception:
pass
except ImportError:
pass
from saharaclient.api import client
from saharaclient.api import shell as shell_api
from saharaclient.nova import auth_plugin as nova_auth_plugin
from saharaclient.nova import extension as nova_extension
from saharaclient.openstack.common.apiclient import exceptions as exc
from saharaclient.openstack.common import cliutils
from saharaclient.openstack.common import strutils
DEFAULT_API_VERSION = 'api'
DEFAULT_ENDPOINT_TYPE = 'publicURL'
DEFAULT_SERVICE_TYPE = 'data_processing'
logger = logging.getLogger(__name__)
def positive_non_zero_float(text):
if text is None:
return None
try:
value = float(text)
except ValueError:
msg = "%s must be a float" % text
raise argparse.ArgumentTypeError(msg)
if value <= 0:
msg = "%s must be greater than 0" % text
raise argparse.ArgumentTypeError(msg)
return value
class SecretsHelper(object):
def __init__(self, args, client):
self.args = args
self.client = client
self.key = None
def _validate_string(self, text):
if text is None or len(text) == 0:
return False
return True
def _make_key(self):
if self.key is not None:
return self.key
keys = [
self.client.auth_url,
self.client.projectid,
self.client.user,
self.client.region_name,
self.client.endpoint_type,
self.client.service_type,
self.client.service_name,
self.client.volume_service_name,
]
for (index, key) in enumerate(keys):
if key is None:
keys[index] = '?'
else:
keys[index] = str(keys[index])
self.key = "/".join(keys)
return self.key
def _prompt_password(self, verify=True):
pw = None
if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
# Check for Ctl-D
try:
while True:
pw1 = getpass.getpass('OS Password: ')
if verify:
pw2 = getpass.getpass('Please verify: ')
else:
pw2 = pw1
if pw1 == pw2 and self._validate_string(pw1):
pw = pw1
break
except EOFError:
pass
return pw
def save(self, auth_token, management_url, tenant_id):
if not HAS_KEYRING or not self.args.os_cache:
return
if auth_token == self.auth_token and \
management_url == self.management_url:
# Nothing changed....
return
if not all([management_url, auth_token, tenant_id]):
raise ValueError("Unable to save empty management url/auth token")
value = "|".join([str(auth_token),
str(management_url),
str(tenant_id)])
keyring.set_password("saharaclient_auth", self._make_key(), value)
@property
def password(self):
if self._validate_string(self.args.os_password):
return self.args.os_password
verify_pass = \
strutils.bool_from_string(cliutils.env("OS_VERIFY_PASSWORD"))
return self._prompt_password(verify_pass)
@property
def management_url(self):
if not HAS_KEYRING or not self.args.os_cache:
return None
management_url = None
try:
block = keyring.get_password('saharaclient_auth',
self._make_key())
if block:
_token, management_url, _tenant_id = block.split('|', 2)
except all_errors:
pass
return management_url
@property
def auth_token(self):
# Now is where it gets complicated since we
# want to look into the keyring module, if it
# exists and see if anything was provided in that
# file that we can use.
if not HAS_KEYRING or not self.args.os_cache:
return None
token = None
try:
block = keyring.get_password('saharaclient_auth',
self._make_key())
if block:
token, _management_url, _tenant_id = block.split('|', 2)
except all_errors:
pass
return token
@property
def tenant_id(self):
if not HAS_KEYRING or not self.args.os_cache:
return None
tenant_id = None
try:
block = keyring.get_password('saharaclient_auth',
self._make_key())
if block:
_token, _management_url, tenant_id = block.split('|', 2)
except all_errors:
pass
return tenant_id
class SavannaClientArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super(SavannaClientArgumentParser, 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 OpenStackSavannaShell(object):
def get_base_parser(self):
parser = SavannaClientArgumentParser(
prog='sahara',
description=__doc__.strip(),
epilog='See "sahara 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)
# NA for Savanna
# parser.add_argument('--version',
# action='version',
# version=saharaclient.__version__)
parser.add_argument('--debug',
default=False,
action='store_true',
help="Print debugging output.")
parser.add_argument('--os-cache',
default=strutils.bool_from_string(
cliutils.env('OS_CACHE', default=False)),
action='store_true',
help="Use the auth token cache. Defaults to False "
"if env[OS_CACHE] is not set.")
# TODO(mattf) - add get_timings support to Client
# parser.add_argument('--timings',
# default=False,
# action='store_true',
# help="Print call timing info")
# TODO(mattf) - use timeout
# parser.add_argument('--timeout',
# default=600,
# metavar='<seconds>',
# type=positive_non_zero_float,
# help="Set HTTP call timeout (in seconds)")
parser.add_argument('--os-username',
metavar='<auth-user-name>',
default=cliutils.env('OS_USERNAME',
'SAHARA_USERNAME'),
help='Defaults to env[OS_USERNAME].')
parser.add_argument('--os_username',
help=argparse.SUPPRESS)
parser.add_argument('--os-password',
metavar='<auth-password>',
default=cliutils.env('OS_PASSWORD',
'SAHARA_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=cliutils.env('OS_TENANT_NAME',
'SAHARA_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=cliutils.env('OS_TENANT_ID'),
help='Defaults to env[OS_TENANT_ID].')
parser.add_argument('--os-auth-url',
metavar='<auth-url>',
default=cliutils.env('OS_AUTH_URL', 'SAHARA_URL'),
help='Defaults to env[OS_AUTH_URL].')
parser.add_argument('--os_auth_url',
help=argparse.SUPPRESS)
# NA for Savanna
# parser.add_argument('--os-region-name',
# metavar='<region-name>',
# default=utils.env('OS_REGION_NAME', 'SAHARA_REGION_NAME'),
# help='Defaults to env[OS_REGION_NAME].')
# parser.add_argument('--os_region_name',
# help=argparse.SUPPRESS)
parser.add_argument('--os-auth-system',
metavar='<auth-system>',
default=cliutils.env('OS_AUTH_SYSTEM'),
help='Defaults to env[OS_AUTH_SYSTEM].')
parser.add_argument('--os_auth_system',
help=argparse.SUPPRESS)
parser.add_argument('--service-type',
metavar='<service-type>',
help='Defaults to data_processing for all '
'actions.')
parser.add_argument('--service_type',
help=argparse.SUPPRESS)
# NA for Savanna
# parser.add_argument('--service-name',
# metavar='<service-name>',
# default=utils.env('SAHARA_SERVICE_NAME'),
# help='Defaults to env[SAHARA_SERVICE_NAME]')
# parser.add_argument('--service_name',
# help=argparse.SUPPRESS)
# NA for Savanna
# parser.add_argument('--volume-service-name',
# metavar='<volume-service-name>',
# default=utils.env('NOVA_VOLUME_SERVICE_NAME'),
# help='Defaults to env[NOVA_VOLUME_SERVICE_NAME]')
# parser.add_argument('--volume_service_name',
# help=argparse.SUPPRESS)
parser.add_argument('--endpoint-type',
metavar='<endpoint-type>',
default=cliutils.env(
'SAHARA_ENDPOINT_TYPE',
default=DEFAULT_ENDPOINT_TYPE),
help='Defaults to env[SAHARA_ENDPOINT_TYPE] or '
+ DEFAULT_ENDPOINT_TYPE + '.')
# NOTE(dtroyer): We can't add --endpoint_type here due to argparse
# thinking usage-list --end is ambiguous; but it
# works fine with only --endpoint-type present
# Go figure. I'm leaving this here for doc purposes.
#parser.add_argument('--endpoint_type',
# help=argparse.SUPPRESS)
parser.add_argument('--sahara-api-version',
metavar='<sahara-api-ver>',
default=cliutils.env(
'SAHARA_API_VERSION',
default=DEFAULT_API_VERSION),
help='Accepts "api", '
'defaults to env[SAHARA_API_VERSION].')
parser.add_argument('--sahara_api_version',
help=argparse.SUPPRESS)
parser.add_argument('--os-cacert',
metavar='<ca-certificate>',
default=cliutils.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].')
# NA for Savanna
# parser.add_argument('--insecure',
# default=utils.env('NOVACLIENT_INSECURE', default=False),
# action='store_true',
# help="Explicitly allow novaclient to perform \"insecure\" "
# "SSL (https) requests. The server's certificate will "
# "not be verified against any certificate authorities. "
# "This option should be used with caution.")
parser.add_argument('--bypass-url',
metavar='<bypass-url>',
default=cliutils.env('BYPASS_URL', default=None),
dest='bypass_url',
help="Use this API endpoint instead of the "
"Service Catalog.")
parser.add_argument('--bypass_url',
help=argparse.SUPPRESS)
# The auth-system-plugins might require some extra options
nova_auth_plugin.load_auth_system_opts(parser)
return parser
def get_subcommand_parser(self, version):
parser = self.get_base_parser()
self.subcommands = {}
subparsers = parser.add_subparsers(metavar='<subcommand>')
try:
actions_module = {
'api': shell_api,
}[version]
except KeyError:
actions_module = shell_api
actions_module = shell_api
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(),
self._discover_via_contrib_path(version),
self._discover_via_entry_points()):
extension = nova_extension.Extension(name, module)
extensions.append(extension)
return extensions
def _discover_via_python_path(self):
for (module_loader, name, _ispkg) in pkgutil.iter_modules():
if name.endswith('_python_savannaclient_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)
if hasattr(module, 'extension_name'):
name = module.extension_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 _discover_via_entry_points(self):
for ep in pkg_resources.iter_entry_points('saharaclient.extension'):
name = ep.name
module = ep.load()
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 hyphen-separated instead of underscores.
command = attr[3:].replace('_', '-')
callback = getattr(actions_module, attr)
desc = callback.__doc__ or ''
action_help = desc.strip()
arguments = getattr(callback, 'arguments', [])
subparser = \
subparsers.add_parser(command,
help=action_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
streamformat = "%(levelname)s (%(module)s:%(lineno)d) %(message)s"
# Set up the root logger to debug so that the submodules can
# print debug messages
logging.basicConfig(level=logging.DEBUG,
format=streamformat)
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)
# Discover available auth plugins
nova_auth_plugin.discover_auth_systems()
# build available subcommands based on version
self.extensions = \
self._discover_extensions(options.sahara_api_version)
self._run_extension_hooks('__pre_parse_args__')
# NOTE(dtroyer): Hackery to handle --endpoint_type due to argparse
# thinking usage-list --end is ambiguous; but it
# works fine with only --endpoint-type present
# Go figure.
if '--endpoint_type' in argv:
spot = argv.index('--endpoint_type')
argv[spot] = '--endpoint-type'
subcommand_parser = \
self.get_subcommand_parser(options.sahara_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_tenant_name, os_tenant_id, os_auth_url,
# os_region_name, os_auth_system, endpoint_type, insecure,
# service_type, service_name, volume_service_name,
# bypass_url, os_cache, cacert) = ( #, timeout) = (
# args.os_username,
# args.os_tenant_name, args.os_tenant_id,
# args.os_auth_url,
# args.os_region_name,
# args.os_auth_system,
# args.endpoint_type, args.insecure,
# args.service_type,
# args.service_name, args.volume_service_name,
# args.bypass_url, args.os_cache,
# args.os_cacert, args.timeout)
(os_username, os_tenant_name, os_tenant_id,
os_auth_url, os_auth_system, endpoint_type,
service_type, bypass_url, os_cache,
cacert) = \
(args.os_username, args.os_tenant_name, args.os_tenant_id,
args.os_auth_url, args.os_auth_system, args.endpoint_type,
args.service_type, args.bypass_url, args.os_cache,
args.os_cacert)
if os_auth_system and os_auth_system != "keystone":
auth_plugin = nova_auth_plugin.load_plugin(os_auth_system)
else:
auth_plugin = None
# Fetched and set later as needed
os_password = None
if not endpoint_type:
endpoint_type = DEFAULT_ENDPOINT_TYPE
if not service_type:
service_type = DEFAULT_SERVICE_TYPE
# NA for Savanna - there is only one service this CLI accesses
# 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 cliutils.isunauthenticated(args.func):
if auth_plugin:
auth_plugin.parse_opts(args)
if not auth_plugin or not auth_plugin.opts:
if not os_username:
raise exc.CommandError("You must provide a username "
"via either --os-username or "
"env[OS_USERNAME]")
if not os_tenant_name and not os_tenant_id:
raise exc.CommandError("You must provide a tenant name "
"or tenant id via --os-tenant-name, "
"--os-tenant-id, env[OS_TENANT_NAME] "
"or env[OS_TENANT_ID]")
if not os_auth_url:
if os_auth_system and os_auth_system != 'keystone':
os_auth_url = auth_plugin.get_auth_url()
if not os_auth_url:
raise exc.CommandError("You must provide an auth url "
"via either --os-auth-url or "
"env[OS_AUTH_URL] or specify an "
"auth_system which defines a "
"default url with --os-auth-system "
"or env[OS_AUTH_SYSTEM]")
# NA for Savanna
# if (options.os_compute_api_version and
# options.os_compute_api_version != '1.0'):
# if not os_tenant_name and not os_tenant_id:
# raise exc.CommandError("You must provide a tenant name "
# "or tenant id via --os-tenant-name, "
# "--os-tenant-id, env[OS_TENANT_NAME] "
# "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]")
# NOTE: The Sahara client authenticates when you create it. So instead of
# creating here and authenticating later, which is what the novaclient
# does, we just create the client later.
# Now check for the password/token of which pieces of the
# identifying keyring key can come from the underlying client
if not cliutils.isunauthenticated(args.func):
# NA for Savanna - Client can't be used with SecretsHelper
# helper = SecretsHelper(args, self.cs.client)
if (auth_plugin and auth_plugin.opts and
"os_password" not in auth_plugin.opts):
use_pw = False
else:
use_pw = True
# tenant_id, auth_token, management_url = (helper.tenant_id,
# helper.auth_token,
# helper.management_url)
#
# if tenant_id and auth_token and management_url:
# self.cs.client.tenant_id = tenant_id
# self.cs.client.auth_token = auth_token
# self.cs.client.management_url = management_url
# # authenticate just sets up some values in this case, no REST
# # calls
# self.cs.authenticate()
if use_pw:
# Auth using token must have failed or not happened
# at all, so now switch to password mode and save
# the token when its gotten... using our keyring
# saver
# os_password = helper.password
os_password = args.os_password
if not os_password:
raise exc.CommandError(
'Expecting a password provided via either '
'--os-password, env[OS_PASSWORD], or '
'prompted response')
# self.cs.client.password = os_password
# self.cs.client.keyring_saver = helper
# NA for Savanna
# try:
# if not utils.isunauthenticated(args.func):
# self.cs.authenticate()
# except exc.Unauthorized:
# raise exc.CommandError("Invalid OpenStack Sahara credentials.")
# except exc.AuthorizationFailure:
# raise exc.CommandError("Unable to authorize user")
self.cs = client.Client(username=os_username,
api_key=os_password,
project_id=os_tenant_id,
project_name=os_tenant_name,
auth_url=os_auth_url,
savanna_url=bypass_url)
args.func(self.cs, args)
# TODO(mattf) - add get_timings support to Client
# if args.timings:
# self._dump_timings(self.cs.get_timings())
def _dump_timings(self, timings):
class Tyme(object):
def __init__(self, url, seconds):
self.url = url
self.seconds = seconds
results = [Tyme(url, end - start) for url, start, end in timings]
total = 0.0
for tyme in results:
total += tyme.seconds
results.append(Tyme("Total", total))
cliutils.print_list(results, ["url", "seconds"], sortby_index=None)
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):
"""Prints all of the commands and options to stdout so that the
sahara.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))
@cliutils.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:
OpenStackSavannaShell().main(map(strutils.safe_decode, sys.argv[1:]))
except Exception as e:
logger.debug(e, exc_info=1)
print("ERROR: %s" % strutils.safe_encode(six.text_type(e)),
file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()

View File

View File

View File

@ -22,10 +22,10 @@ import fixtures
import mock
from testtools import matchers
import savannaclient.api.client
from savannaclient.openstack.common.apiclient import exceptions
import savannaclient.shell
from savannaclient.tests.nova import utils
import saharaclient.api.client
from saharaclient.openstack.common.apiclient import exceptions
import saharaclient.shell
from saharaclient.tests.nova import utils
FAKE_ENV = {'OS_USERNAME': 'username',
'OS_PASSWORD': 'password',
@ -89,7 +89,7 @@ class ShellTest(utils.TestCase):
try:
sys.stdout = six.StringIO()
sys.stderr = six.StringIO()
_shell = savannaclient.shell.OpenStackSavannaShell()
_shell = saharaclient.shell.OpenStackSavannaShell()
_shell.main(argstr.split())
except SystemExit:
exc_type, exc_value, exc_traceback = sys.exc_info()
@ -212,7 +212,7 @@ class ShellTest(utils.TestCase):
# @mock.patch('sys.stdin', side_effect=mock.MagicMock)
# @mock.patch('getpass.getpass', return_value='password')
# def test_password(self, mock_getpass, mock_stdin):
@mock.patch('savannaclient.api.client.Client', FakePluginClient)
@mock.patch('saharaclient.api.client.Client', FakePluginClient)
def test_password(self):
ex = (
'+------+----------+---------------+\n'
@ -272,7 +272,7 @@ class ShellTest(utils.TestCase):
# def test_v_unknown_service_type(self, mock_client):
# self._test_service_type('unknown', 'compute', mock_client)
@mock.patch('savannaclient.api.client.Client', FakePluginClient)
@mock.patch('saharaclient.api.client.Client', FakePluginClient)
def test_image_list(self):
ex = (
'+------+------------+----------+------+-------------+\n'

View File

@ -15,7 +15,7 @@
import testtools
from savannaclient.api import base
from saharaclient.api import base
class ResourceTest(testtools.TestCase):

View File

@ -0,0 +1 @@
from saharaclient.api import base as base # noqa

View File

@ -13,33 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from savannaclient.openstack.common import importutils
from saharaclient import client as saharaclient
class UnsupportedVersion(Exception):
"""Indicates that the user is trying to use an unsupported
version of the API.
"""
pass
def get_client_class(version):
version_map = {
'1.0': 'savannaclient.api.client.Client',
'1.1': 'savannaclient.api.client.Client',
}
try:
client_path = version_map[str(version)]
except (KeyError, ValueError):
supported_versions = ''.join(version_map.keys())
msg = ("Invalid client version '%(version)s'; must be one of: "
"%(versions)s") % {'version': version,
'versions': supported_versions}
raise UnsupportedVersion(msg)
return importutils.import_class(client_path)
def Client(version, *args, **kwargs):
client_class = get_client_class(version)
return client_class(*args, **kwargs)
Client = saharaclient.Client

View File

@ -1,2 +0,0 @@
import six
six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))

View File

@ -1,765 +1 @@
# Copyright 2010 Jacob Kaplan-Moss
# Copyright 2011 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
###
### This code is taken from python-novaclient. Goal is minimal modification.
###
"""
Command-line interface to the OpenStack Sahara API.
"""
from __future__ import print_function
import argparse
import getpass
import glob
import imp
import itertools
import logging
import os
import pkgutil
import sys
import pkg_resources
import six
HAS_KEYRING = False
all_errors = ValueError
try:
import keyring
HAS_KEYRING = True
try:
if isinstance(keyring.get_keyring(), keyring.backend.GnomeKeyring):
import gnomekeyring
all_errors = (ValueError,
gnomekeyring.IOError,
gnomekeyring.NoKeyringDaemonError)
except Exception:
pass
except ImportError:
pass
from savannaclient.api import client
from savannaclient.api import shell as shell_api
from savannaclient.nova import auth_plugin as nova_auth_plugin
from savannaclient.nova import extension as nova_extension
from savannaclient.openstack.common.apiclient import exceptions as exc
from savannaclient.openstack.common import cliutils
from savannaclient.openstack.common import strutils
DEFAULT_SAHARA_API_VERSION = 'api'
DEFAULT_ENDPOINT_TYPE = 'publicURL'
DEFAULT_SAHARA_SERVICE_TYPE = 'data_processing'
logger = logging.getLogger(__name__)
def positive_non_zero_float(text):
if text is None:
return None
try:
value = float(text)
except ValueError:
msg = "%s must be a float" % text
raise argparse.ArgumentTypeError(msg)
if value <= 0:
msg = "%s must be greater than 0" % text
raise argparse.ArgumentTypeError(msg)
return value
class SecretsHelper(object):
def __init__(self, args, client):
self.args = args
self.client = client
self.key = None
def _validate_string(self, text):
if text is None or len(text) == 0:
return False
return True
def _make_key(self):
if self.key is not None:
return self.key
keys = [
self.client.auth_url,
self.client.projectid,
self.client.user,
self.client.region_name,
self.client.endpoint_type,
self.client.service_type,
self.client.service_name,
self.client.volume_service_name,
]
for (index, key) in enumerate(keys):
if key is None:
keys[index] = '?'
else:
keys[index] = str(keys[index])
self.key = "/".join(keys)
return self.key
def _prompt_password(self, verify=True):
pw = None
if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
# Check for Ctl-D
try:
while True:
pw1 = getpass.getpass('OS Password: ')
if verify:
pw2 = getpass.getpass('Please verify: ')
else:
pw2 = pw1
if pw1 == pw2 and self._validate_string(pw1):
pw = pw1
break
except EOFError:
pass
return pw
def save(self, auth_token, management_url, tenant_id):
if not HAS_KEYRING or not self.args.os_cache:
return
if auth_token == self.auth_token and \
management_url == self.management_url:
# Nothing changed....
return
if not all([management_url, auth_token, tenant_id]):
raise ValueError("Unable to save empty management url/auth token")
value = "|".join([str(auth_token),
str(management_url),
str(tenant_id)])
keyring.set_password("savannaclient_auth", self._make_key(), value)
@property
def password(self):
if self._validate_string(self.args.os_password):
return self.args.os_password
verify_pass = \
strutils.bool_from_string(cliutils.env("OS_VERIFY_PASSWORD"))
return self._prompt_password(verify_pass)
@property
def management_url(self):
if not HAS_KEYRING or not self.args.os_cache:
return None
management_url = None
try:
block = keyring.get_password('savannaclient_auth',
self._make_key())
if block:
_token, management_url, _tenant_id = block.split('|', 2)
except all_errors:
pass
return management_url
@property
def auth_token(self):
# Now is where it gets complicated since we
# want to look into the keyring module, if it
# exists and see if anything was provided in that
# file that we can use.
if not HAS_KEYRING or not self.args.os_cache:
return None
token = None
try:
block = keyring.get_password('savannaclient_auth',
self._make_key())
if block:
token, _management_url, _tenant_id = block.split('|', 2)
except all_errors:
pass
return token
@property
def tenant_id(self):
if not HAS_KEYRING or not self.args.os_cache:
return None
tenant_id = None
try:
block = keyring.get_password('savannaclient_auth',
self._make_key())
if block:
_token, _management_url, tenant_id = block.split('|', 2)
except all_errors:
pass
return tenant_id
class SavannaClientArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super(SavannaClientArgumentParser, 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 OpenStackSavannaShell(object):
def get_base_parser(self):
parser = SavannaClientArgumentParser(
prog='sahara',
description=__doc__.strip(),
epilog='See "sahara 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)
# NA for Savanna
# parser.add_argument('--version',
# action='version',
# version=savannaclient.__version__)
parser.add_argument('--debug',
default=False,
action='store_true',
help="Print debugging output.")
parser.add_argument('--os-cache',
default=strutils.bool_from_string(
cliutils.env('OS_CACHE', default=False)),
action='store_true',
help="Use the auth token cache. Defaults to False "
"if env[OS_CACHE] is not set.")
# TODO(mattf) - add get_timings support to Client
# parser.add_argument('--timings',
# default=False,
# action='store_true',
# help="Print call timing info")
# TODO(mattf) - use timeout
# parser.add_argument('--timeout',
# default=600,
# metavar='<seconds>',
# type=positive_non_zero_float,
# help="Set HTTP call timeout (in seconds)")
parser.add_argument('--os-username',
metavar='<auth-user-name>',
default=cliutils.env('OS_USERNAME',
'SAHARA_USERNAME'),
help='Defaults to env[OS_USERNAME].')
parser.add_argument('--os_username',
help=argparse.SUPPRESS)
parser.add_argument('--os-password',
metavar='<auth-password>',
default=cliutils.env('OS_PASSWORD',
'SAHARA_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=cliutils.env('OS_TENANT_NAME',
'SAHARA_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=cliutils.env('OS_TENANT_ID'),
help='Defaults to env[OS_TENANT_ID].')
parser.add_argument('--os-auth-url',
metavar='<auth-url>',
default=cliutils.env('OS_AUTH_URL', 'SAHARA_URL'),
help='Defaults to env[OS_AUTH_URL].')
parser.add_argument('--os_auth_url',
help=argparse.SUPPRESS)
# NA for Savanna
# parser.add_argument('--os-region-name',
# metavar='<region-name>',
# default=utils.env('OS_REGION_NAME', 'SAVANNA_REGION_NAME'),
# help='Defaults to env[OS_REGION_NAME].')
# parser.add_argument('--os_region_name',
# help=argparse.SUPPRESS)
parser.add_argument('--os-auth-system',
metavar='<auth-system>',
default=cliutils.env('OS_AUTH_SYSTEM'),
help='Defaults to env[OS_AUTH_SYSTEM].')
parser.add_argument('--os_auth_system',
help=argparse.SUPPRESS)
parser.add_argument('--service-type',
metavar='<service-type>',
help='Defaults to data_processing for all '
'actions.')
parser.add_argument('--service_type',
help=argparse.SUPPRESS)
# NA for Savanna
# parser.add_argument('--service-name',
# metavar='<service-name>',
# default=utils.env('SAVANNA_SERVICE_NAME'),
# help='Defaults to env[SAVANNA_SERVICE_NAME]')
# parser.add_argument('--service_name',
# help=argparse.SUPPRESS)
# NA for Savanna
# parser.add_argument('--volume-service-name',
# metavar='<volume-service-name>',
# default=utils.env('NOVA_VOLUME_SERVICE_NAME'),
# help='Defaults to env[NOVA_VOLUME_SERVICE_NAME]')
# parser.add_argument('--volume_service_name',
# help=argparse.SUPPRESS)
parser.add_argument('--endpoint-type',
metavar='<endpoint-type>',
default=cliutils.env(
'SAHARA_ENDPOINT_TYPE',
default=DEFAULT_ENDPOINT_TYPE),
help='Defaults to env[SAHARA_ENDPOINT_TYPE] or '
+ DEFAULT_ENDPOINT_TYPE + '.')
# NOTE(dtroyer): We can't add --endpoint_type here due to argparse
# thinking usage-list --end is ambiguous; but it
# works fine with only --endpoint-type present
# Go figure. I'm leaving this here for doc purposes.
#parser.add_argument('--endpoint_type',
# help=argparse.SUPPRESS)
parser.add_argument('--sahara-api-version',
metavar='<sahara-api-ver>',
default=cliutils.env(
'SAHARA_API_VERSION',
default=DEFAULT_SAHARA_API_VERSION),
help='Accepts "api", '
'defaults to env[SAHARA_API_VERSION].')
parser.add_argument('--sahara_api_version',
help=argparse.SUPPRESS)
parser.add_argument('--os-cacert',
metavar='<ca-certificate>',
default=cliutils.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].')
# NA for Savanna
# parser.add_argument('--insecure',
# default=utils.env('NOVACLIENT_INSECURE', default=False),
# action='store_true',
# help="Explicitly allow novaclient to perform \"insecure\" "
# "SSL (https) requests. The server's certificate will "
# "not be verified against any certificate authorities. "
# "This option should be used with caution.")
parser.add_argument('--bypass-url',
metavar='<bypass-url>',
default=cliutils.env('BYPASS_URL', default=None),
dest='bypass_url',
help="Use this API endpoint instead of the "
"Service Catalog.")
parser.add_argument('--bypass_url',
help=argparse.SUPPRESS)
# The auth-system-plugins might require some extra options
nova_auth_plugin.load_auth_system_opts(parser)
return parser
def get_subcommand_parser(self, version):
parser = self.get_base_parser()
self.subcommands = {}
subparsers = parser.add_subparsers(metavar='<subcommand>')
try:
actions_module = {
'api': shell_api,
}[version]
except KeyError:
actions_module = shell_api
actions_module = shell_api
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(),
self._discover_via_contrib_path(version),
self._discover_via_entry_points()):
extension = nova_extension.Extension(name, module)
extensions.append(extension)
return extensions
def _discover_via_python_path(self):
for (module_loader, name, _ispkg) in pkgutil.iter_modules():
if name.endswith('_python_savannaclient_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)
if hasattr(module, 'extension_name'):
name = module.extension_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 _discover_via_entry_points(self):
for ep in pkg_resources.iter_entry_points('savannaclient.extension'):
name = ep.name
module = ep.load()
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 hyphen-separated instead of underscores.
command = attr[3:].replace('_', '-')
callback = getattr(actions_module, attr)
desc = callback.__doc__ or ''
action_help = desc.strip()
arguments = getattr(callback, 'arguments', [])
subparser = \
subparsers.add_parser(command,
help=action_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
streamformat = "%(levelname)s (%(module)s:%(lineno)d) %(message)s"
# Set up the root logger to debug so that the submodules can
# print debug messages
logging.basicConfig(level=logging.DEBUG,
format=streamformat)
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)
# Discover available auth plugins
nova_auth_plugin.discover_auth_systems()
# build available subcommands based on version
self.extensions = \
self._discover_extensions(options.sahara_api_version)
self._run_extension_hooks('__pre_parse_args__')
# NOTE(dtroyer): Hackery to handle --endpoint_type due to argparse
# thinking usage-list --end is ambiguous; but it
# works fine with only --endpoint-type present
# Go figure.
if '--endpoint_type' in argv:
spot = argv.index('--endpoint_type')
argv[spot] = '--endpoint-type'
subcommand_parser = \
self.get_subcommand_parser(options.sahara_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_tenant_name, os_tenant_id, os_auth_url,
# os_region_name, os_auth_system, endpoint_type, insecure,
# service_type, service_name, volume_service_name,
# bypass_url, os_cache, cacert) = ( #, timeout) = (
# args.os_username,
# args.os_tenant_name, args.os_tenant_id,
# args.os_auth_url,
# args.os_region_name,
# args.os_auth_system,
# args.endpoint_type, args.insecure,
# args.service_type,
# args.service_name, args.volume_service_name,
# args.bypass_url, args.os_cache,
# args.os_cacert, args.timeout)
(os_username, os_tenant_name, os_tenant_id,
os_auth_url, os_auth_system, endpoint_type,
service_type, bypass_url, os_cache,
cacert) = \
(args.os_username, args.os_tenant_name, args.os_tenant_id,
args.os_auth_url, args.os_auth_system, args.endpoint_type,
args.service_type, args.bypass_url, args.os_cache,
args.os_cacert)
if os_auth_system and os_auth_system != "keystone":
auth_plugin = nova_auth_plugin.load_plugin(os_auth_system)
else:
auth_plugin = None
# Fetched and set later as needed
os_password = None
if not endpoint_type:
endpoint_type = DEFAULT_ENDPOINT_TYPE
if not service_type:
service_type = DEFAULT_SAHARA_SERVICE_TYPE
# NA for Savanna - there is only one service this CLI accesses
# 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 cliutils.isunauthenticated(args.func):
if auth_plugin:
auth_plugin.parse_opts(args)
if not auth_plugin or not auth_plugin.opts:
if not os_username:
raise exc.CommandError("You must provide a username "
"via either --os-username or "
"env[OS_USERNAME]")
if not os_tenant_name and not os_tenant_id:
raise exc.CommandError("You must provide a tenant name "
"or tenant id via --os-tenant-name, "
"--os-tenant-id, env[OS_TENANT_NAME] "
"or env[OS_TENANT_ID]")
if not os_auth_url:
if os_auth_system and os_auth_system != 'keystone':
os_auth_url = auth_plugin.get_auth_url()
if not os_auth_url:
raise exc.CommandError("You must provide an auth url "
"via either --os-auth-url or "
"env[OS_AUTH_URL] or specify an "
"auth_system which defines a "
"default url with --os-auth-system "
"or env[OS_AUTH_SYSTEM]")
# NA for Savanna
# if (options.os_compute_api_version and
# options.os_compute_api_version != '1.0'):
# if not os_tenant_name and not os_tenant_id:
# raise exc.CommandError("You must provide a tenant name "
# "or tenant id via --os-tenant-name, "
# "--os-tenant-id, env[OS_TENANT_NAME] "
# "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]")
# NOTE: The Savanna client authenticates when you create it. So instead of
# creating here and authenticating later, which is what the novaclient
# does, we just create the client later.
# Now check for the password/token of which pieces of the
# identifying keyring key can come from the underlying client
if not cliutils.isunauthenticated(args.func):
# NA for Savanna - Client can't be used with SecretsHelper
# helper = SecretsHelper(args, self.cs.client)
if (auth_plugin and auth_plugin.opts and
"os_password" not in auth_plugin.opts):
use_pw = False
else:
use_pw = True
# tenant_id, auth_token, management_url = (helper.tenant_id,
# helper.auth_token,
# helper.management_url)
#
# if tenant_id and auth_token and management_url:
# self.cs.client.tenant_id = tenant_id
# self.cs.client.auth_token = auth_token
# self.cs.client.management_url = management_url
# # authenticate just sets up some values in this case, no REST
# # calls
# self.cs.authenticate()
if use_pw:
# Auth using token must have failed or not happened
# at all, so now switch to password mode and save
# the token when its gotten... using our keyring
# saver
# os_password = helper.password
os_password = args.os_password
if not os_password:
raise exc.CommandError(
'Expecting a password provided via either '
'--os-password, env[OS_PASSWORD], or '
'prompted response')
# self.cs.client.password = os_password
# self.cs.client.keyring_saver = helper
# NA for Savanna
# try:
# if not utils.isunauthenticated(args.func):
# self.cs.authenticate()
# except exc.Unauthorized:
# raise exc.CommandError("Invalid OpenStack Savanna credentials.")
# except exc.AuthorizationFailure:
# raise exc.CommandError("Unable to authorize user")
self.cs = client.Client(username=os_username,
api_key=os_password,
project_id=os_tenant_id,
project_name=os_tenant_name,
auth_url=os_auth_url,
savanna_url=bypass_url)
args.func(self.cs, args)
# TODO(mattf) - add get_timings support to Client
# if args.timings:
# self._dump_timings(self.cs.get_timings())
def _dump_timings(self, timings):
class Tyme(object):
def __init__(self, url, seconds):
self.url = url
self.seconds = seconds
results = [Tyme(url, end - start) for url, start, end in timings]
total = 0.0
for tyme in results:
total += tyme.seconds
results.append(Tyme("Total", total))
cliutils.print_list(results, ["url", "seconds"], sortby_index=None)
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):
"""Prints all of the commands and options to stdout so that the
sahara.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))
@cliutils.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:
OpenStackSavannaShell().main(map(strutils.safe_decode, sys.argv[1:]))
except Exception as e:
logger.debug(e, exc_info=1)
print("ERROR: %s" % strutils.safe_encode(six.text_type(e)),
file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
from saharaclient.shell import main as main # noqa

View File

@ -1,6 +1,6 @@
[metadata]
name = python-savannaclient
summary = Client library for Savanna API
summary = Client library for Sahara API
description-file =
README.rst
license = Apache License, Version 2.0
@ -28,10 +28,11 @@ packages =
[entry_points]
console_scripts =
savanna = savannaclient.shell:main
sahara = saharaclient.shell:main
# TODO(slukjanov): remove this code (temp to migrate to the new name)
sahara = savannaclient.shell:main
savanna = saharaclient.shell:main
[build_sphinx]
all_files = 1