summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.coveragerc1
-rw-r--r--openstack-common.conf7
-rw-r--r--releasenotes/notes/remove-old-cli-commands-06b9936ce044dd0f.yaml7
-rw-r--r--requirements.txt2
-rw-r--r--saharaclient/_i18n.py (renamed from saharaclient/openstack/common/_i18n.py)10
-rw-r--r--saharaclient/api/base.py2
-rw-r--r--saharaclient/api/shell.py1012
-rw-r--r--saharaclient/openstack/__init__.py0
-rw-r--r--saharaclient/openstack/common/__init__.py0
-rw-r--r--saharaclient/openstack/common/apiclient/__init__.py0
-rw-r--r--saharaclient/openstack/common/apiclient/auth.py234
-rw-r--r--saharaclient/openstack/common/apiclient/exceptions.py479
-rw-r--r--saharaclient/openstack/common/cliutils.py272
-rw-r--r--saharaclient/shell.py732
-rw-r--r--saharaclient/tests/unit/nova/__init__.py0
-rw-r--r--saharaclient/tests/unit/nova/test_shell.py366
-rw-r--r--saharaclient/tests/unit/nova/utils.py57
-rw-r--r--setup.cfg3
-rw-r--r--tox.ini5
19 files changed, 9 insertions, 3180 deletions
diff --git a/.coveragerc b/.coveragerc
index 2b789e1..1640032 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -2,7 +2,6 @@
branch = True
source = saharaclient
omit =
- */openstack/common/*
.tox/*
saharaclient/tests/*
diff --git a/openstack-common.conf b/openstack-common.conf
deleted file mode 100644
index 0b4ad3f..0000000
--- a/openstack-common.conf
+++ /dev/null
@@ -1,7 +0,0 @@
-[DEFAULT]
-base=saharaclient
-
-module=apiclient.auth
-module=apiclient.exceptions
-module=cliutils
-module=_i18n
diff --git a/releasenotes/notes/remove-old-cli-commands-06b9936ce044dd0f.yaml b/releasenotes/notes/remove-old-cli-commands-06b9936ce044dd0f.yaml
new file mode 100644
index 0000000..3a7ab2e
--- /dev/null
+++ b/releasenotes/notes/remove-old-cli-commands-06b9936ce044dd0f.yaml
@@ -0,0 +1,7 @@
+---
+prelude: >
+ Old CLI commands are removed. Please use OpenStackClient
+ instead.
+deprecations:
+ - Old CLI commands are removed. Please use OpenStackClient
+ instead.
diff --git a/requirements.txt b/requirements.txt
index 6d5dbee..2ed76f0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,8 +11,6 @@ oslo.log>=3.11.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0
oslo.i18n>=2.1.0 # Apache-2.0
oslo.utils>=3.16.0 # Apache-2.0
-python-keystoneclient!=2.1.0,>=2.0.0 # Apache-2.0
python-openstackclient>=2.1.0 # Apache-2.0
requests>=2.10.0 # Apache-2.0
six>=1.9.0 # MIT
-PrettyTable<0.8,>=0.7 # BSD
diff --git a/saharaclient/openstack/common/_i18n.py b/saharaclient/_i18n.py
index 5cc57a1..f0055e9 100644
--- a/saharaclient/openstack/common/_i18n.py
+++ b/saharaclient/_i18n.py
@@ -11,19 +11,12 @@
# under the License.
"""oslo.i18n integration module.
-
See http://docs.openstack.org/developer/oslo.i18n/usage.html
-
"""
try:
import oslo_i18n
- # NOTE(dhellmann): This reference to o-s-l-o will be replaced by the
- # application name when this module is synced into the separate
- # repository. It is OK to have more than one translation function
- # using the same domain, since there will still only be one message
- # catalog.
_translators = oslo_i18n.TranslatorFactory(domain='saharaclient')
# The primary translation function using the well-known name "_"
@@ -39,7 +32,4 @@ try:
_LE = _translators.log_error
_LC = _translators.log_critical
except ImportError:
- # NOTE(dims): Support for cases where a project wants to use
- # code from oslo-incubator, but is not ready to be internationalized
- # (like tempest)
_ = _LI = _LW = _LE = _LC = lambda x: x
diff --git a/saharaclient/api/base.py b/saharaclient/api/base.py
index 36c9e45..de9c16c 100644
--- a/saharaclient/api/base.py
+++ b/saharaclient/api/base.py
@@ -20,7 +20,7 @@ import logging
import six
from six.moves.urllib import parse
-from saharaclient.openstack.common._i18n import _
+from saharaclient._i18n import _
LOG = logging.getLogger(__name__)
diff --git a/saharaclient/api/shell.py b/saharaclient/api/shell.py
deleted file mode 100644
index 40c339c..0000000
--- a/saharaclient/api/shell.py
+++ /dev/null
@@ -1,1012 +0,0 @@
-# Copyright 2013 Red Hat, 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 argparse
-import datetime
-import inspect
-import json
-import os.path
-import sys
-
-from saharaclient.openstack.common.apiclient import exceptions
-from saharaclient.openstack.common import cliutils as utils
-
-
-def _print_list_field(field):
- return lambda obj: ', '.join(getattr(obj, field))
-
-
-def _filter_call_args(args, func, remap={}):
- """Filter args according to func's parameter list.
-
- Take three arguments:
- * args - a dictionary
- * func - a function
- * remap - a dictionary
- Remove from dct all the keys which are not among the parameters
- of func. Before filtering, remap the keys in the args dict
- according to remap dict.
- """
-
- for name, new_name in remap.items():
- if name in args:
- args[new_name] = args[name]
- del args[name]
-
- valid_args = inspect.getargspec(func).args
- for name in args.keys():
- if name not in valid_args:
- print('WARNING: "%s" is not a valid parameter and will be '
- 'discarded from the request' % name)
- del args[name]
-
-
-def _print_node_group_field(cluster):
- return ', '.join(map(lambda x: ': '.join(x),
- [(node_group['name'],
- str(node_group['count']))
- for node_group in cluster.node_groups]))
-
-
-def _show_node_group_template(template):
- template._info['node_processes'] = (
- ', '.join(template._info['node_processes'])
- )
- utils.print_dict(template._info)
-
-
-def _show_cluster_template(template):
- template._info['node_groups'] = _print_node_group_field(template)
- utils.print_dict(template._info)
-
-
-def _show_cluster(cluster):
- # TODO(mattf): Make this pretty, e.g format node_groups and info urls
- # Forcing wrap=47 allows for clean display on a terminal of width 80
- utils.print_dict(cluster._info, wrap=47)
-
-
-def _show_job_binary_data(data):
- columns = ('id', 'name')
- utils.print_list(data, columns)
-
-
-def _show_data_source(source):
- # TODO(mattf): why are we passing credentials around like this?
- if 'credentials' in source._info:
- del source._info['credentials']
- utils.print_dict(source._info)
-
-
-def _show_job_binary(binary):
- # TODO(mattf): why are we passing credentials around like this?
- if 'extra' in binary._info:
- del binary._info['extra']
- utils.print_dict(binary._info)
-
-
-def _show_job_template(template):
- # TODO(mattf): Make "mains" property pretty
- # TODO(mattf): handle/remove "extra" creds
- utils.print_dict(template._info)
-
-
-def _show_job(job):
- # TODO(mattf): make display of info pretty, until then
- # extract the important status information
- job._info['status'] = job._info['info']['status']
- del job._info['info']
- utils.print_dict(job._info)
-
-
-def _get_by_id_or_name(manager, id=None, name=None, **kwargs):
- if not (name or id):
- raise exceptions.CommandError("either NAME or ID is required")
- if id:
- return manager.get(id, **kwargs)
- ls = manager.find(name=name)
- if len(ls) == 0:
- raise exceptions.CommandError("%s '%s' not found" %
- (manager.resource_class.resource_name,
- name))
- elif len(ls) > 1:
- raise exceptions.CommandError("%s '%s' not unique, try by ID" %
- (manager.resource_class.resource_name,
- name))
- return manager.get(ls[0].id, **kwargs)
-
-
-#
-# Plugins
-# ~~~~~~~
-# plugin-list
-#
-# plugin-show --name <plugin> [--version <version>]
-#
-
-def do_plugin_list(cs, args):
- """Print a list of available plugins."""
- plugins = cs.plugins.list()
- columns = ('name', 'versions', 'title')
- utils.print_list(plugins, columns,
- {'versions': _print_list_field('versions')})
-
-
-@utils.arg('--name',
- metavar='<plugin>',
- required=True,
- help='Name of the plugin.')
-# TODO(mattf) - saharaclient does not support query w/ version
-# @utils.arg('--version',
-# metavar='<version>',
-# help='Optional version')
-def do_plugin_show(cs, args):
- """Show details of a plugin."""
- plugin = cs.plugins.get(args.name)
- plugin._info['versions'] = ', '.join(plugin._info['versions'])
- utils.print_dict(plugin._info)
-
-
-#
-# Image Registry
-# ~~~~~~~~~~~~~~
-# image-list [--tag <tag>]*
-#
-# image-show --name <image>|--id <image_id>
-#
-# image-register --name <image>|--id <image_id>
-# [--username <name>] [--description <desc>]
-#
-# image-unregister --name <image>|--id <image_id>
-#
-# image-add-tag --name <image>|--id <image_id> --tag <tag>+
-#
-# image-remove-tag --name <image>|--id <image_id> --tag <tag>+
-#
-
-# TODO(mattf): [--tag <tag>]*
-def do_image_list(cs, args):
- """Print a list of available images."""
- images = cs.images.list()
- columns = ('name', 'id', 'username', 'tags', 'description')
- utils.print_list(images, columns, {'tags': _print_list_field('tags')})
-
-
-@utils.arg('--name',
- help='Name of the image.')
-@utils.arg('--id',
- metavar='<image_id>',
- help='ID of the image.')
-def do_image_show(cs, args):
- """Show details of an image."""
- image = _get_by_id_or_name(cs.images, args.id, args.name)
- del image._info['metadata']
- image._info['tags'] = ', '.join(image._info['tags'])
- utils.print_dict(image._info)
-
-
-# TODO(mattf): Add --name, must lookup in glance index
-@utils.arg('--id',
- metavar='<image_id>',
- required=True,
- help='ID of image, run "glance image-list" to see all IDs.')
-@utils.arg('--username',
- default='root',
- metavar='<name>',
- help='Username of privileged user in the image.')
-@utils.arg('--description',
- default='',
- metavar='<desc>',
- help='Description of the image.')
-def do_image_register(cs, args):
- """Register an image from the Image index."""
- # TODO(mattf): image register should not be through update
- cs.images.update_image(args.id, args.username, args.description)
- # TODO(mattf): No indication of result, expect image details
-
-
-@utils.arg('--name',
- help='Name of the image.')
-@utils.arg('--id',
- metavar='<image_id>',
- help='ID of image to unregister.')
-def do_image_unregister(cs, args):
- """Unregister an image."""
- cs.images.unregister_image(
- args.id or _get_by_id_or_name(cs.images, name=args.name).id
- )
- # TODO(mattf): No indication of result, expect result to display
-
-
-@utils.arg('--name',
- help='Name of the image.')
-@utils.arg('--id',
- metavar='<image_id>',
- help='ID of image to tag.')
-# TODO(mattf): Change --tag to --tag+
-@utils.arg('--tag',
- metavar='<tag>',
- required=True,
- help='Tag to add.')
-def do_image_add_tag(cs, args):
- """Add a tag to an image."""
- # TODO(mattf): Need proper add_tag API call
- id = args.id or _get_by_id_or_name(cs.images, name=args.name).id
- cs.images.update_tags(id, cs.images.get(id).tags + [args.tag, ])
- # TODO(mattf): No indication of result, expect image details
-
-
-@utils.arg('--name',
- help='Name of the image.')
-@utils.arg('--id',
- metavar='<image_id>',
- help='Image to tag.')
-# TODO(mattf): Change --tag to --tag+
-@utils.arg('--tag',
- metavar='<tag>',
- required=True,
- help='Tag to remove.')
-def do_image_remove_tag(cs, args):
- """Remove a tag from an image."""
- # TODO(mattf): Need proper remove_tag API call
- id = args.id or _get_by_id_or_name(cs.images, name=args.name).id
- cs.images.update_tags(id,
- filter(lambda x: x != args.tag,
- cs.images.get(id).tags))
- # TODO(mattf): No indication of result, expect image details
-
-
-#
-# Clusters
-# ~~~~~~~~
-# cluster-list
-#
-# cluster-show --name <cluster>|--id <cluster_id> [--json] [--show-progress]
-#
-# cluster-create [--json <file>]
-#
-# cluster-scale --name <cluster>|--id <cluster_id> [--json <file>]
-#
-# cluster-delete --name <cluster>|--id <cluster_id>
-#
-
-def do_cluster_list(cs, args):
- """Print a list of available clusters."""
- clusters = cs.clusters.list()
- for cluster in clusters:
- cluster.node_count = sum(map(lambda g: g['count'],
- cluster.node_groups))
- columns = ('name', 'id', 'status', 'node_count')
- utils.print_list(clusters, columns)
-
-
-@utils.arg('--name',
- help='Name of the cluster.')
-@utils.arg('--id',
- metavar='<cluster_id>',
- help='ID of the cluster to show.')
-@utils.arg('--show-progress',
- help='Show provision progress events of the cluster.')
-@utils.arg('--json',
- action='store_true',
- default=False,
- help='Print JSON representation of the cluster.')
-def do_cluster_show(cs, args):
- """Show details of a cluster."""
- cluster = _get_by_id_or_name(cs.clusters, args.id, args.name,
- show_progress=args.show_progress)
- if args.json:
- print(json.dumps(cluster._info))
- else:
- _show_cluster(cluster)
-
-
-@utils.arg('--json',
- default=sys.stdin,
- type=argparse.FileType('r'),
- help='JSON representation of cluster.')
-@utils.arg('--count',
- default=1,
- type=int,
- help='Number of clusters to create.')
-def do_cluster_create(cs, args):
- """Create a cluster."""
- # TODO(mattf): improve template validation, e.g. template w/o name key
- template = json.loads(args.json.read())
- # The neutron_management_network parameter to clusters.create is
- # called net_id. Therefore, we must translate before invoking
- # create w/ **template. It may be desirable to simple change
- # clusters.create in the future.
- remap = {'neutron_management_network': 'net_id'}
- template['count'] = args.count
- _filter_call_args(template, cs.clusters.create, remap)
-
- _show_cluster(cs.clusters.create(**template))
-
-
-@utils.arg('--name',
- help='Name of the cluster.')
-@utils.arg('--id',
- metavar='<cluster_id>',
- help='ID of the cluster.')
-@utils.arg('--json',
- default=sys.stdin,
- type=argparse.FileType('r'),
- help='JSON representation of cluster scale.')
-def do_cluster_scale(cs, args):
- """Scale a cluster."""
- cluster_id = args.id or _get_by_id_or_name(cs.clusters, name=args.name).id
- scale_template = json.loads(args.json.read())
- _show_cluster(cs.clusters.scale(cluster_id, **scale_template))
-
-
-@utils.arg('--name',
- help='Name of the cluster.')
-@utils.arg('--id',
- metavar='<cluster_id>',
- help='ID of the cluster to delete.')
-def do_cluster_delete(cs, args):
- """Delete a cluster."""
- cs.clusters.delete(
- args.id or _get_by_id_or_name(cs.clusters, name=args.name).id
- )
- # TODO(mattf): No indication of result
-
-
-#
-# Node Group Templates
-# ~~~~~~~~~~~~~~~~~~~~
-# node-group-template-list
-#
-# node-group-template-show --name <template>|--id <template_id> [--json]
-#
-# node-group-template-create [--json <file>]
-#
-# node-group-template-delete --name <template>|--id <template_id>
-#
-# node-group-template-update --name <template>|--id <template_id> --json <file>
-#
-
-def do_node_group_template_list(cs, args):
- """Print a list of available node group templates."""
- templates = cs.node_group_templates.list()
- columns = ('name', 'id', 'plugin_name', 'node_processes', 'description')
- utils.print_list(templates, columns,
- {'node_processes': _print_list_field('node_processes')})
-
-
-@utils.arg('--name',
- help='Name of the node group template.')
-@utils.arg('--id',
- metavar='<template_id>',
- help='ID of the node group template to show.')
-@utils.arg('--json',
- action='store_true',
- default=False,
- help='Print JSON representation of node group template.')
-def do_node_group_template_show(cs, args):
- """Show details of a node group template."""
- template = _get_by_id_or_name(cs.node_group_templates, args.id, args.name)
- if args.json:
- print(json.dumps(template._info))
- else:
- _show_node_group_template(template)
-
-
-@utils.arg('--json',
- default=sys.stdin,
- type=argparse.FileType('r'),
- help='JSON representation of node group template.')
-def do_node_group_template_create(cs, args):
- """Create a node group template."""
- # TODO(mattf): improve template validation, e.g. template w/o name key
- template = json.loads(args.json.read())
- _filter_call_args(template, cs.node_group_templates.create)
-
- _show_node_group_template(cs.node_group_templates.create(**template))
-
-
-@utils.arg('--name',
- help='Name of the node group template.')
-@utils.arg('--id',
- metavar='<template_id>',
- help='ID of the node group template to delete.')
-def do_node_group_template_delete(cs, args):
- """Delete a node group template."""
- cs.node_group_templates.delete(
- args.id or
- _get_by_id_or_name(cs.node_group_templates, name=args.name).id
- )
- # TODO(mattf): No indication of result
-
-
-@utils.arg('--name',
- help='Name of the node group template to update.')
-@utils.arg('--id',
- metavar='<template_id>',
- help='ID of the node group template to update.')
-@utils.arg('--json',
- default=sys.stdin,
- type=argparse.FileType('r'),
- help='JSON representation of the node group template update.')
-def do_node_group_template_update(cs, args):
- """Update a node group template."""
- template = _get_by_id_or_name(cs.node_group_templates,
- name=args.name,
- id=args.id)
- update_template = json.loads(args.json.read())
- _filter_call_args(update_template, cs.node_group_templates.update)
- for param in ["plugin_name", "hadoop_version", "name", "flavor_id"]:
- if param not in update_template:
- update_template[param] = getattr(template, param, None)
-
- result = cs.node_group_templates.update(
- args.id or
- template._get_by_id_or_name(cs.node_group_templates,
- name=args.name).id,
- **update_template
- )
-
- _show_node_group_template(result)
-
-
-#
-# Cluster Templates
-# ~~~~~~~~~~~~~~~~~
-# cluster-template-list
-#
-# cluster-template-show --name <template>|--id <template_id> [--json]
-#
-# cluster-template-create [--json <file>]
-#
-# cluster-template-delete --name <template>|--id <template_id>
-#
-
-def do_cluster_template_list(cs, args):
- """Print a list of available cluster templates."""
- templates = cs.cluster_templates.list()
- columns = ('name', 'id', 'plugin_name', 'node_groups', 'description')
- utils.print_list(templates, columns,
- {'node_groups': _print_node_group_field})
-
-
-@utils.arg('--name',
- help='Name of the cluster template.')
-@utils.arg('--id',
- metavar='<template_id>',
- help='ID of the cluster template to show.')
-@utils.arg('--json',
- action='store_true',
- default=False,
- help='Print JSON representation of cluster template.')
-def do_cluster_template_show(cs, args):
- """Show details of a cluster template."""
- template = _get_by_id_or_name(cs.cluster_templates, args.id, args.name)
- if args.json:
- print(json.dumps(template._info))
- else:
- _show_cluster_template(template)
-
-
-@utils.arg('--json',
- default=sys.stdin,
- type=argparse.FileType('r'),
- help='JSON representation of cluster template.')
-def do_cluster_template_create(cs, args):
- """Create a cluster template."""
- # TODO(mattf): improve template validation, e.g. template w/o name key
- template = json.loads(args.json.read())
- remap = {'neutron_management_network': 'net_id'}
- _filter_call_args(template, cs.cluster_templates.create, remap)
-
- _show_cluster_template(cs.cluster_templates.create(**template))
-
-
-@utils.arg('--name',
- help='Name of the cluster template.')
-@utils.arg('--id',
- metavar='<template_id>',
- help='ID of the cluster template to delete.')
-def do_cluster_template_delete(cs, args):
- """Delete a cluster template."""
- cs.cluster_templates.delete(
- args.id or _get_by_id_or_name(cs.cluster_templates, name=args.name).id
- )
- # TODO(mattf): No indication of result
-
-
-@utils.arg('--name',
- help='Name of the cluster template to update.')
-@utils.arg('--id',
- metavar='<template_id>',
- help='ID of the cluster template to update.')
-@utils.arg('--json',
- default=sys.stdin,
- type=argparse.FileType('r'),
- help='JSON representation of cluster template update.')
-def do_cluster_template_update(cs, args):
- """Update a cluster template."""
- template = _get_by_id_or_name(cs.cluster_templates,
- name=args.name,
- id=args.id)
- update_template = json.loads(args.json.read())
- _filter_call_args(update_template, cs.cluster_templates.update)
- for param in ["name", "plugin_name", "hadoop_version"]:
- if param not in update_template:
- update_template[param] = getattr(template, param, None)
-
- result = cs.cluster_templates.update(
- args.id or
- _get_by_id_or_name(cs.node_group_templates, name=args.name).id,
- **update_template
- )
-
- _show_cluster_template(result)
-
-
-#
-# Data Sources
-# ~~~~~~~~~~~~
-# data-source-list
-#
-# data-source-show --name <name>|--id <id>
-#
-# data-source-create --name <name> --type <type>
-# --url <url>
-# [--user <user> --password <password>]
-# [--description <desc>]
-# NB: user & password if type is swift
-#
-# data-source-delete --name <name>|--id <id>
-#
-
-def do_data_source_list(cs, args):
- """Print a list of available data sources."""
- sources = cs.data_sources.list()
- columns = ('name', 'id', 'type', 'description')
- utils.print_list(sources, columns)
-
-
-@utils.arg('--name',
- help='Name of the data source.')
-@utils.arg('--id',
- help='ID of the data source.')
-def do_data_source_show(cs, args):
- """Show details of a data source."""
- _show_data_source(_get_by_id_or_name(cs.data_sources, args.id, args.name))
-
-
-@utils.arg('--name',
- required=True,
- help='Name of the data source.')
-@utils.arg('--type',
- required=True,
- help='Type of the data source.')
-@utils.arg('--url',
- required=True,
- help='URL for the data source.')
-@utils.arg('--description',
- default='',
- help='Description of the data source.')
-@utils.arg('--user',
- default=None,
- help='Username for accessing the data source URL.')
-@utils.arg('--password',
- default=None,
- help='Password for accessing the data source URL.')
-def do_data_source_create(cs, args):
- """Create a data source that provides job input or receives job output."""
- _show_data_source(cs.data_sources.create(args.name, args.description,
- args.type, args.url,
- args.user, args.password))
-
-
-@utils.arg('--name',
- help='Name of the data source.')
-@utils.arg('--id',
- help='ID of data source to delete.')
-def do_data_source_delete(cs, args):
- """Delete a data source."""
- cs.data_sources.delete(
- args.id or _get_by_id_or_name(cs.data_sources, name=args.name).id
- )
- # TODO(mattf): No indication of result
-
-
-@utils.arg('--name',
- help="Name of the data source to update.")
-@utils.arg('--id',
- help="ID of the data source to update.")
-@utils.arg('--json',
- default=sys.stdin,
- type=argparse.FileType('r'),
- help='JSON containing the data source fields to update.')
-def do_data_source_update(cs, args):
- """Update a data source."""
- update_data = json.loads(args.json.read())
- result = cs.data_sources.update(
- args.id or _get_by_id_or_name(cs.data_sources, name=args.name).id,
- update_data
- )
- _show_data_source(result)
-
-
-#
-# Job Binary Internals
-# ~~~~~~~~~~~~~~~~~~~~
-# job-binary-data-list
-#
-# job-binary-data-create [--file <file>] [--name <name>]
-#
-# job-binary-data-delete --id <id>
-#
-
-def do_job_binary_data_list(cs, args):
- """Print a list of internally stored job binary data."""
- _show_job_binary_data(cs.job_binary_internals.list())
-
-
-@utils.arg('--file',
- default=sys.stdin,
- type=argparse.FileType('r'),
- help='Data to store.')
-@utils.arg('--name',
- help="Name of the job binary internal.")
-def do_job_binary_data_create(cs, args):
- """Store data in the internal DB.
-
- Use 'swift upload' instead of this command.
- Use this command only if Swift is not available.
- """
- if args.name:
- name = args.name
- elif args.file is not sys.stdin:
- name = os.path.basename(args.file.name)
- else:
- name = datetime.datetime.now().strftime('d%Y%m%d%H%M%S')
- # Should be %F-%T except for type validation errors
- _show_job_binary_data((cs.job_binary_internals.create(
- name,
- args.file.read()),)
- )
-
-
-@utils.arg('--id',
- required=True,
- help='ID of internally stored job binary data.')
-def do_job_binary_data_delete(cs, args):
- """Delete an internally stored job binary data."""
- cs.job_binary_internals.delete(args.id)
- # TODO(mattf): No indication of result
- # TODO(mattf): Appears no DB constraints for removing data used by job
-
-
-#
-# Job Binaries
-# ~~~~~~~~~~~~
-# job-binary-list
-#
-# job-binary-show --name <name>|--id <id>
-#
-# job-binary-create --name <name> --url <url>
-# [--user <user> --password <password>]
-# [--description <desc>]
-#
-# job-binary-delete --name <name>|--id <id>
-#
-
-def do_job_binary_list(cs, args):
- """Print a list of job binaries."""
- binaries = cs.job_binaries.list()
- columns = ('id', 'name', 'description')
- utils.print_list(binaries, columns)
-
-
-@utils.arg('--name',
- help='Name of the job binary.')
-@utils.arg('--id',
- help='ID of the job binary.')
-def do_job_binary_show(cs, args):
- """Show details of a job binary."""
- _show_job_binary(_get_by_id_or_name(cs.job_binaries, args.id, args.name))
-
-
-@utils.arg('--name',
- required=True,
- help='Name of the job binary.')
-@utils.arg('--url',
- required=True,
- help='URL for the job binary.')
-@utils.arg('--description',
- default='',
- help='Description of the job binary.')
-@utils.arg('--user',
- default=None,
- help='Username for accessing the job binary URL.')
-@utils.arg('--password',
- default=None,
- help='Password for accessing the job binary URL.')
-def do_job_binary_create(cs, args):
- """Record a job binary."""
- # TODO(mattf): make credentials consistent w/ data source
- extra = {}
- if args.user:
- extra['user'] = args.user
- if args.password:
- extra['password'] = args.password
- _show_job_binary(cs.job_binaries.create(args.name, args.url,
- args.description, extra))
-
-
-@utils.arg('--name',
- help='Name of the job binary.')
-@utils.arg('--id',
- help='ID of the job binary to delete.')
-def do_job_binary_delete(cs, args):
- """Delete a job binary."""
- cs.job_binaries.delete(
- args.id or _get_by_id_or_name(cs.job_binaries, name=args.name).id
- )
- # TODO(mattf): No indication of result
-
-
-@utils.arg('--name',
- help='Name of the job binary to update.')
-@utils.arg('--id',
- metavar='<job_binary_id>',
- help='ID of the job binary to update.')
-@utils.arg('--json',
- default=sys.stdin,
- type=argparse.FileType('r'),
- help='JSON representation of job binary update.')
-def do_job_binary_update(cs, args):
- """Update a job binary."""
- update_data = json.loads(args.json.read())
- result = cs.job_binaries.update(
- args.id or
- _get_by_id_or_name(cs.job_binaries, name=args.name).id,
- update_data
- )
-
- _show_job_binary(result)
-
-
-#
-# Jobs
-# ~~~~
-# job-template-list
-#
-# job-template-show --name <name>|--id <id>
-#
-# job-template-create --name <name>
-# --type <Pig|Hive|MapReduce|Java|...>
-# [--mains <array of string>]
-# [--libs <array of string>]
-# [--description <desc>]
-#
-# job-template-delete --name <name>|--id <id>
-#
-
-def do_job_template_list(cs, args):
- """Print a list of job templates."""
- templates = cs.jobs.list()
- columns = ('id', 'name', 'description')
- utils.print_list(templates, columns)
-
-
-@utils.arg('--name',
- help='Name of the job template.')
-@utils.arg('--id',
- help='ID of the job template.')
-def do_job_template_show(cs, args):
- """Show details of a job template."""
- _show_job_template(_get_by_id_or_name(cs.jobs, args.id, args.name))
-
-
-@utils.arg('--name',
- help='Name of the job template.')
-@utils.arg('--type',
- help='Type of the job template.')
-@utils.arg('--main',
- action='append',
- default=[],
- help='ID for job\'s main job-binary.')
-@utils.arg('--lib',
- action='append',
- default=[],
- help='ID of job\'s lib job-binary, repeatable.')
-@utils.arg('--description',
- default='',
- help='Description of the job template.')
-@utils.arg('--json',
- default=None,
- type=argparse.FileType('r'),
- help='JSON representation of job template.')
-def do_job_template_create(cs, args):
- """Create a job template."""
- template = json.loads(args.json.read()) if args.json else {}
- _filter_call_args(template, cs.jobs.create)
- template = {
- "name": args.name or template.get("name") or None,
- "type": args.type or template.get("type") or None,
- "mains": args.main or template.get("mains") or [],
- "libs": args.lib or template.get("libs") or [],
- "description": args.description or template.get("description") or '',
- "interface": template.get("interface") or []
- }
- if not template["name"]:
- raise Exception("name is required")
- if not template["type"]:
- raise Exception("type is required")
-
- _show_job_template(cs.jobs.create(**template))
-
-
-@utils.arg('--name',
- help='Name of the job template.')
-@utils.arg('--id',
- help='ID of the job template.')
-def do_job_template_delete(cs, args):
- """Delete a job template."""
- cs.jobs.delete(
- args.id or _get_by_id_or_name(cs.jobs, name=args.name).id
- )
- # TODO(mattf): No indication of result
-
-
-#
-# Job Executions
-# ~~~~~~~~~~~~~~
-# job-list
-#
-# job-show --id <id>
-#
-# job-create --job-template <id> --cluster <id>
-# [--input-data <id>] [--output-data <id>]
-# [--param <name=value>]
-# [--arg <arg>]
-# [--config <name=value>]
-#
-# job-delete --id <id>
-#
-
-def do_job_list(cs, args):
- """Print a list of jobs."""
- jobs = cs.job_executions.list()
- for job in jobs:
- # why is status in info.status?
- job.status = job.info['status']
- # TODO(mattf): why can cluster_id be None?
- columns = ('id', 'cluster_id', 'start_time', 'status')
- utils.print_list(jobs, columns, sortby_index=2)
-
-
-@utils.arg('--id',
- required=True,
- help='ID of the job.')
-def do_job_show(cs, args):
- """Show details of a job."""
- _show_job(cs.job_executions.get(args.id))
-
-
-@utils.arg('--job-template',
- required=True,
- help='ID of the job template to run.')
-@utils.arg('--cluster',
- required=False,
- help='ID of the cluster to run the job in.')
-@utils.arg('--input-data',
- default=None,
- help='ID of the input data source.')
-@utils.arg('--output-data',
- default=None,
- help='ID of the output data source.')
-@utils.arg('--param',
- metavar='name=value',
- action='append',
- default=[],
- help='Parameters to add to the job, repeatable.')
-@utils.arg('--arg',
- action='append',
- default=[],
- help='Arguments to add to the job, repeatable.')
-@utils.arg('--config',
- metavar='name=value',
- action='append',
- default=[],
- help='Config parameters to add to the job, repeatable.')
-@utils.arg('--json',
- default=None,
- type=argparse.FileType('r'),
- help='JSON representation of the job.')
-def do_job_create(cs, args):
- """Create a job."""
- job = json.loads(args.json.read()) if args.json else {}
- remap = {"job_configs": "configs"}
- _filter_call_args(job, cs.job_executions.create, remap)
- _convert = lambda ls: dict(map(lambda i: i.split('=', 1), ls))
- job = {
- "cluster_id": args.cluster or job.get("cluster_id") or None,
- "input_id": args.input_data or job.get("input_id") or None,
- "output_id": args.output_data or job.get("output_id") or None,
- "interface": job.get("interface") or [],
- "configs": job.get("configs") or {}
- }
- if any((args.config, args.param, args.arg)):
- job["configs"] = {"configs": _convert(args.config),
- "args": args.arg,
- "params": _convert(args.param)}
- if not job["cluster_id"]:
- raise Exception("cluster is required")
- _show_job(cs.job_executions.create(args.job_template, **job))
-
-
-@utils.arg('--id',
- required=True,
- help='ID of a job.')
-def do_job_delete(cs, args):
- """Delete a job."""
- cs.job_executions.delete(args.id)
- # TODO(mattf): No indication of result
-
-
-#
-# Job Types
-# ~~~~~~~~~
-# job-type-list [--type] [--plugin [--plugin-version]]
-#
-
-def _print_plugin_field(job_type):
-
- def plugin_version_string(plugin):
- versions = ", ".join(plugin["versions"].keys())
- if versions:
- versions = "(" + versions + ")"
- return plugin["name"] + versions
-
- return ", ".join(map(lambda x: plugin_version_string(x), job_type.plugins))
-
-
-@utils.arg('--type',
- metavar='<job_type>',
- default=None,
- help='Report only on this job type.')
-@utils.arg('--plugin',
- metavar='<plugin>',
- default=None,
- help='Report only job types supported by this plugin.')
-@utils.arg('--plugin-version',
- metavar='<plugin_version>',
- default=None,
- help='Report only on job types supported by this version '
- 'of a specified plugin. Only valid with --plugin.')
-def do_job_type_list(cs, args):
- """Show supported job types."""
- search_opts = {}
- if args.type:
- search_opts["type"] = args.type
- if args.plugin:
- search_opts["plugin"] = args.plugin
- if args.plugin_version:
- search_opts["version"] = args.plugin_version
- elif args.plugin_version:
- raise exceptions.CommandError(
- 'The --plugin-version option is only valid when '
- '--plugin is specified')
-
- job_types = cs.job_types.list(search_opts)
- columns = ('name', 'plugin(versions)')
- utils.print_list(job_types, columns,
- {'plugin(versions)': _print_plugin_field})
diff --git a/saharaclient/openstack/__init__.py b/saharaclient/openstack/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/saharaclient/openstack/__init__.py
+++ /dev/null
diff --git a/saharaclient/openstack/common/__init__.py b/saharaclient/openstack/common/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/saharaclient/openstack/common/__init__.py
+++ /dev/null
diff --git a/saharaclient/openstack/common/apiclient/__init__.py b/saharaclient/openstack/common/apiclient/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/saharaclient/openstack/common/apiclient/__init__.py
+++ /dev/null
diff --git a/saharaclient/openstack/common/apiclient/auth.py b/saharaclient/openstack/common/apiclient/auth.py
deleted file mode 100644
index d27450c..0000000
--- a/saharaclient/openstack/common/apiclient/auth.py
+++ /dev/null
@@ -1,234 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# Copyright 2013 Spanish National Research Council.
-# 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.
-
-# E0202: An attribute inherited from %s hide this method
-# pylint: disable=E0202
-
-########################################################################
-#
-# THIS MODULE IS DEPRECATED
-#
-# Please refer to
-# https://etherpad.openstack.org/p/kilo-saharaclient-library-proposals for
-# the discussion leading to this deprecation.
-#
-# We recommend checking out the python-openstacksdk project
-# (https://launchpad.net/python-openstacksdk) instead.
-#
-########################################################################
-
-import abc
-import argparse
-import os
-
-import six
-from stevedore import extension
-
-from saharaclient.openstack.common.apiclient import exceptions
-
-
-_discovered_plugins = {}
-
-
-def discover_auth_systems():
- """Discover the available auth-systems.
-
- This won't take into account the old style auth-systems.
- """
- global _discovered_plugins
- _discovered_plugins = {}
-
- def add_plugin(ext):
- _discovered_plugins[ext.name] = ext.plugin
-
- ep_namespace = "saharaclient.openstack.common.apiclient.auth"
- mgr = extension.ExtensionManager(ep_namespace)
- mgr.map(add_plugin)
-
-
-def load_auth_system_opts(parser):
- """Load options needed by the available auth-systems into a parser.
-
- This function will try to populate the parser with options from the
- available plugins.
- """
- group = parser.add_argument_group("Common auth options")
- BaseAuthPlugin.add_common_opts(group)
- for name, auth_plugin in six.iteritems(_discovered_plugins):
- group = parser.add_argument_group(
- "Auth-system '%s' options" % name,
- conflict_handler="resolve")
- auth_plugin.add_opts(group)
-
-
-def load_plugin(auth_system):
- try:
- plugin_class = _discovered_plugins[auth_system]
- except KeyError:
- raise exceptions.AuthSystemNotFound(auth_system)
- return plugin_class(auth_system=auth_system)
-
-
-def load_plugin_from_args(args):
- """Load required plugin and populate it with options.
-
- Try to guess auth system if it is not specified. Systems are tried in
- alphabetical order.
-
- :type args: argparse.Namespace
- :raises: AuthPluginOptionsMissing
- """
- auth_system = args.os_auth_system
- if auth_system:
- plugin = load_plugin(auth_system)
- plugin.parse_opts(args)
- plugin.sufficient_options()
- return plugin
-
- for plugin_auth_system in sorted(six.iterkeys(_discovered_plugins)):
- plugin_class = _discovered_plugins[plugin_auth_system]
- plugin = plugin_class()
- plugin.parse_opts(args)
- try:
- plugin.sufficient_options()
- except exceptions.AuthPluginOptionsMissing:
- continue
- return plugin
- raise exceptions.AuthPluginOptionsMissing(["auth_system"])
-
-
-@six.add_metaclass(abc.ABCMeta)
-class BaseAuthPlugin(object):
- """Base class for authentication plugins.
-
- An authentication plugin needs to override at least the authenticate
- method to be a valid plugin.
- """
-
- auth_system = None
- opt_names = []
- common_opt_names = [
- "auth_system",
- "username",
- "password",
- "tenant_name",
- "token",
- "auth_url",
- ]
-
- def __init__(self, auth_system=None, **kwargs):
- self.auth_system = auth_system or self.auth_system
- self.opts = dict((name, kwargs.get(name))
- for name in self.opt_names)
-
- @staticmethod
- def _parser_add_opt(parser, opt):
- """Add an option to parser in two variants.
-
- :param opt: option name (with underscores)
- """
- dashed_opt = opt.replace("_", "-")
- env_var = "OS_%s" % opt.upper()
- arg_default = os.environ.get(env_var, "")
- arg_help = "Defaults to env[%s]." % env_var
- parser.add_argument(
- "--os-%s" % dashed_opt,
- metavar="<%s>" % dashed_opt,
- default=arg_default,
- help=arg_help)
- parser.add_argument(
- "--os_%s" % opt,
- metavar="<%s>" % dashed_opt,
- help=argparse.SUPPRESS)
-
- @classmethod
- def add_opts(cls, parser):
- """Populate the parser with the options for this plugin.
- """
- for opt in cls.opt_names:
- # use `BaseAuthPlugin.common_opt_names` since it is never
- # changed in child classes
- if opt not in BaseAuthPlugin.common_opt_names:
- cls._parser_add_opt(parser, opt)
-
- @classmethod
- def add_common_opts(cls, parser):
- """Add options that are common for several plugins.
- """
- for opt in cls.common_opt_names:
- cls._parser_add_opt(parser, opt)
-
- @staticmethod
- def get_opt(opt_name, args):
- """Return option name and value.
-
- :param opt_name: name of the option, e.g., "username"
- :param args: parsed arguments
- """
- return (opt_name, getattr(args, "os_%s" % opt_name, None))
-
- def parse_opts(self, args):
- """Parse the actual auth-system options if any.
-
- This method is expected to populate the attribute `self.opts` with a
- dict containing the options and values needed to make authentication.
- """
- self.opts.update(dict(self.get_opt(opt_name, args)
- for opt_name in self.opt_names))
-
- def authenticate(self, http_client):
- """Authenticate using plugin defined method.
-
- The method usually analyses `self.opts` and performs
- a request to authentication server.
-
- :param http_client: client object that needs authentication
- :type http_client: HTTPClient
- :raises: AuthorizationFailure
- """
- self.sufficient_options()
- self._do_authenticate(http_client)
-
- @abc.abstractmethod
- def _do_authenticate(self, http_client):
- """Protected method for authentication.
- """
-
- def sufficient_options(self):
- """Check if all required options are present.
-
- :raises: AuthPluginOptionsMissing
- """
- missing = [opt
- for opt in self.opt_names
- if not self.opts.get(opt)]
- if missing:
- raise exceptions.AuthPluginOptionsMissing(missing)
-
- @abc.abstractmethod
- def token_and_endpoint(self, endpoint_type, service_type):
- """Return token and endpoint.
-
- :param service_type: Service type of the endpoint
- :type service_type: string
- :param endpoint_type: Type of endpoint.
- Possible values: public or publicURL,
- internal or internalURL,
- admin or adminURL
- :type endpoint_type: string
- :returns: tuple of token and endpoint strings
- :raises: EndpointException
- """
diff --git a/saharaclient/openstack/common/apiclient/exceptions.py b/saharaclient/openstack/common/apiclient/exceptions.py
deleted file mode 100644
index ce1c53b..0000000
--- a/saharaclient/openstack/common/apiclient/exceptions.py
+++ /dev/null
@@ -1,479 +0,0 @@
-# Copyright 2010 Jacob Kaplan-Moss
-# Copyright 2011 Nebula, Inc.
-# Copyright 2013 Alessio Ababilov
-# Copyright 2013 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.
-
-"""
-Exception definitions.
-"""
-
-########################################################################
-#
-# THIS MODULE IS DEPRECATED
-#
-# Please refer to
-# https://etherpad.openstack.org/p/kilo-saharaclient-library-proposals for
-# the discussion leading to this deprecation.
-#
-# We recommend checking out the python-openstacksdk project
-# (https://launchpad.net/python-openstacksdk) instead.
-#
-########################################################################
-
-import inspect
-import sys
-
-import six
-
-from saharaclient.openstack.common._i18n import _
-
-
-class ClientException(Exception):
- """The base exception class for all exceptions this library raises.
- """
- pass
-
-
-class ValidationError(ClientException):
- """Error in validation on API client side."""
- pass
-
-
-class UnsupportedVersion(ClientException):
- """User is trying to use an unsupported version of the API."""
- pass
-
-
-class CommandError(ClientException):
- """Error in CLI tool."""
- pass
-
-
-class AuthorizationFailure(ClientException):
- """Cannot authorize API client."""
- pass
-
-
-class ConnectionError(ClientException):
- """Cannot connect to API service."""
- pass
-
-
-class ConnectionRefused(ConnectionError):
- """Connection refused while trying to connect to API service."""
- pass
-
-
-class AuthPluginOptionsMissing(AuthorizationFailure):
- """Auth plugin misses some options."""
- def __init__(self, opt_names):
- super(AuthPluginOptionsMissing, self).__init__(
- _("Authentication failed. Missing options: %s") %
- ", ".join(opt_names))
- self.opt_names = opt_names
-
-
-class AuthSystemNotFound(AuthorizationFailure):
- """User has specified an AuthSystem that is not installed."""
- def __init__(self, auth_system):
- super(AuthSystemNotFound, self).__init__(
- _("AuthSystemNotFound: %r") % auth_system)
- self.auth_system = auth_system
-
-
-class NoUniqueMatch(ClientException):
- """Multiple entities found instead of one."""
- pass
-
-
-class EndpointException(ClientException):
- """Something is rotten in Service Catalog."""
- pass
-
-
-class EndpointNotFound(EndpointException):
- """Could not find requested endpoint in Service Catalog."""
- pass
-
-
-class AmbiguousEndpoints(EndpointException):
- """Found more than one matching endpoint in Service Catalog."""
- def __init__(self, endpoints=None):
- super(AmbiguousEndpoints, self).__init__(
- _("AmbiguousEndpoints: %r") % endpoints)
- self.endpoints = endpoints
-
-
-class HttpError(ClientException):
- """The base exception class for all HTTP exceptions.
- """
- http_status = 0
- message = _("HTTP Error")
-
- def __init__(self, message=None, details=None,
- response=None, request_id=None,
- url=None, method=None, http_status=None):
- self.http_status = http_status or self.http_status
- self.message = message or self.message
- self.details = details
- self.request_id = request_id
- self.response = response
- self.url = url
- self.method = method
- formatted_string = "%s (HTTP %s)" % (self.message, self.http_status)
- if request_id:
- formatted_string += " (Request-ID: %s)" % request_id
- super(HttpError, self).__init__(formatted_string)
-
-
-class HTTPRedirection(HttpError):
- """HTTP Redirection."""
- message = _("HTTP Redirection")
-
-
-class HTTPClientError(HttpError):
- """Client-side HTTP error.
-
- Exception for cases in which the client seems to have erred.
- """
- message = _("HTTP Client Error")
-
-
-class HttpServerError(HttpError):
- """Server-side HTTP error.
-
- Exception for cases in which the server is aware that it has
- erred or is incapable of performing the request.
- """
- message = _("HTTP Server Error")
-
-
-class MultipleChoices(HTTPRedirection):
- """HTTP 300 - Multiple Choices.
-
- Indicates multiple options for the resource that the client may follow.
- """
-
- http_status = 300
- message = _("Multiple Choices")
-
-
-class BadRequest(HTTPClientError):
- """HTTP 400 - Bad Request.
-
- The request cannot be fulfilled due to bad syntax.
- """
- http_status = 400
- message = _("Bad Request")
-
-
-class Unauthorized(HTTPClientError):
- """HTTP 401 - Unauthorized.
-
- Similar to 403 Forbidden, but specifically for use when authentication
- is required and has failed or has not yet been provided.
- """
- http_status = 401
- message = _("Unauthorized")
-
-
-class PaymentRequired(HTTPClientError):
- """HTTP 402 - Payment Required.
-
- Reserved for future use.
- """
- http_status = 402
- message = _("Payment Required")
-
-
-class Forbidden(HTTPClientError):
- """HTTP 403 - Forbidden.
-
- The request was a valid request, but the server is refusing to respond
- to it.
- """
- http_status = 403
- message = _("Forbidden")
-
-
-class NotFound(HTTPClientError):
- """HTTP 404 - Not Found.
-
- The requested resource could not be found but may be available again
- in the future.
- """
- http_status = 404
- message = _("Not Found")
-
-
-class MethodNotAllowed(HTTPClientError):
- """HTTP 405 - Method Not Allowed.
-
- A request was made of a resource using a request method not supported
- by that resource.
- """
- http_status = 405
- message = _("Method Not Allowed")
-
-
-class NotAcceptable(HTTPClientError):
- """HTTP 406 - Not Acceptable.
-
- The requested resource is only capable of generating content not
- acceptable according to the Accept headers sent in the request.
- """
- http_status = 406
- message = _("Not Acceptable")
-
-
-class ProxyAuthenticationRequired(HTTPClientError):
- """HTTP 407 - Proxy Authentication Required.
-
- The client must first authenticate itself with the proxy.
- """
- http_status = 407
- message = _("Proxy Authentication Required")
-
-
-class RequestTimeout(HTTPClientError):
- """HTTP 408 - Request Timeout.
-
- The server timed out waiting for the request.
- """
- http_status = 408
- message = _("Request Timeout")
-
-
-class Conflict(HTTPClientError):
- """HTTP 409 - Conflict.
-
- Indicates that the request could not be processed because of conflict
- in the request, such as an edit conflict.
- """
- http_status = 409
- message = _("Conflict")
-
-
-class Gone(HTTPClientError):
- """HTTP 410 - Gone.
-
- Indicates that the resource requested is no longer available and will
- not be available again.
- """
- http_status = 410
- message = _("Gone")
-
-
-class LengthRequired(HTTPClientError):
- """HTTP 411 - Length Required.
-
- The request did not specify the length of its content, which is
- required by the requested resource.
- """
- http_status = 411
- message = _("Length Required")
-
-
-class PreconditionFailed(HTTPClientError):
- """HTTP 412 - Precondition Failed.
-
- The server does not meet one of the preconditions that the requester
- put on the request.
- """
- http_status = 412
- message = _("Precondition Failed")
-
-
-class RequestEntityTooLarge(HTTPClientError):
- """HTTP 413 - Request Entity Too Large.
-
- The request is larger than the server is willing or able to process.
- """
- http_status = 413
- message = _("Request Entity Too Large")
-
- def __init__(self, *args, **kwargs):
- try:
- self.retry_after = int(kwargs.pop('retry_after'))
- except (KeyError, ValueError):
- self.retry_after = 0
-
- super(RequestEntityTooLarge, self).__init__(*args, **kwargs)
-
-
-class RequestUriTooLong(HTTPClientError):
- """HTTP 414 - Request-URI Too Long.
-
- The URI provided was too long for the server to process.
- """
- http_status = 414
- message = _("Request-URI Too Long")
-
-
-class UnsupportedMediaType(HTTPClientError):
- """HTTP 415 - Unsupported Media Type.
-
- The request entity has a media type which the server or resource does
- not support.
- """
- http_status = 415
- message = _("Unsupported Media Type")
-
-
-class RequestedRangeNotSatisfiable(HTTPClientError):
- """HTTP 416 - Requested Range Not Satisfiable.
-
- The client has asked for a portion of the file, but the server cannot
- supply that portion.
- """
- http_status = 416
- message = _("Requested Range Not Satisfiable")
-
-
-class ExpectationFailed(HTTPClientError):
- """HTTP 417 - Expectation Failed.
-
- The server cannot meet the requirements of the Expect request-header field.
- """
- http_status = 417
- message = _("Expectation Failed")
-
-
-class UnprocessableEntity(HTTPClientError):
- """HTTP 422 - Unprocessable Entity.
-
- The request was well-formed but was unable to be followed due to semantic
- errors.
- """
- http_status = 422
- message = _("Unprocessable Entity")
-
-
-class InternalServerError(HttpServerError):
- """HTTP 500 - Internal Server Error.
-
- A generic error message, given when no more specific message is suitable.
- """
- http_status = 500
- message = _("Internal Server Error")
-
-
-# NotImplemented is a python keyword.
-class HttpNotImplemented(HttpServerError):
- """HTTP 501 - Not Implemented.
-
- The server either does not recognize the request method, or it lacks
- the ability to fulfill the request.
- """
- http_status = 501
- message = _("Not Implemented")
-
-
-class BadGateway(HttpServerError):
- """HTTP 502 - Bad Gateway.
-
- The server was acting as a gateway or proxy and received an invalid
- response from the upstream server.
- """
- http_status = 502
- message = _("Bad Gateway")
-
-
-class ServiceUnavailable(HttpServerError):
- """HTTP 503 - Service Unavailable.
-
- The server is currently unavailable.
- """
- http_status = 503
- message = _("Service Unavailable")
-
-
-class GatewayTimeout(HttpServerError):
- """HTTP 504 - Gateway Timeout.
-
- The server was acting as a gateway or proxy and did not receive a timely
- response from the upstream server.
- """
- http_status = 504
- message = _("Gateway Timeout")
-
-
-class HttpVersionNotSupported(HttpServerError):
- """HTTP 505 - HttpVersion Not Supported.
-
- The server does not support the HTTP protocol version used in the request.
- """
- http_status = 505
- message = _("HTTP Version Not Supported")
-
-
-# _code_map contains all the classes that have http_status attribute.
-_code_map = dict(
- (getattr(obj, 'http_status', None), obj)
- for name, obj in six.iteritems(vars(sys.modules[__name__]))
- if inspect.isclass(obj) and getattr(obj, 'http_status', False)
-)
-
-
-def from_response(response, method, url):
- """Returns an instance of :class:`HttpError` or subclass based on response.
-
- :param response: instance of `requests.Response` class
- :param method: HTTP method used for request
- :param url: URL used for request
- """
-
- req_id = response.headers.get("x-openstack-request-id")
- # NOTE(hdd) true for older versions of nova and cinder
- if not req_id:
- req_id = response.headers.get("x-compute-request-id")
- kwargs = {
- "http_status": response.status_code,
- "response": response,
- "method": method,
- "url": url,
- "request_id": req_id,
- }
- if "retry-after" in response.headers:
- kwargs["retry_after"] = response.headers["retry-after"]
-
- content_type = response.headers.get("Content-Type", "")
- if content_type.startswith("application/json"):
- try:
- body = response.json()
- except ValueError:
- pass
- else:
- if isinstance(body, dict):
- error = body.get(list(body)[0])
- if isinstance(error, dict):
- kwargs["message"] = (error.get("message") or
- error.get("faultstring"))
- kwargs["details"] = (error.get("details") or
- six.text_type(body))
- elif content_type.startswith("text/"):
- kwargs["details"] = response.text
-
- try:
- cls = _code_map[response.status_code]
- except KeyError:
- if 500 <= response.status_code < 600:
- cls = HttpServerError
- elif 400 <= response.status_code < 500:
- cls = HTTPClientError
- else:
- cls = HttpError
- return cls(**kwargs)
diff --git a/saharaclient/openstack/common/cliutils.py b/saharaclient/openstack/common/cliutils.py
deleted file mode 100644
index 4b30d89..0000000
--- a/saharaclient/openstack/common/cliutils.py
+++ /dev/null
@@ -1,272 +0,0 @@
-# Copyright 2012 Red Hat, Inc.
-#
-# 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.
-
-# W0603: Using the global statement
-# W0621: Redefining name %s from outer scope
-# pylint: disable=W0603,W0621
-
-from __future__ import print_function
-
-import getpass
-import inspect
-import os
-import sys
-import textwrap
-
-from oslo_utils import encodeutils
-from oslo_utils import strutils
-import prettytable
-import six
-from six import moves
-
-from saharaclient.openstack.common._i18n import _
-
-
-class MissingArgs(Exception):
- """Supplied arguments are not sufficient for calling a function."""
- def __init__(self, missing):
- self.missing = missing
- msg = _("Missing arguments: %s") % ", ".join(missing)
- super(MissingArgs, self).__init__(msg)
-
-
-def validate_args(fn, *args, **kwargs):
- """Check that the supplied args are sufficient for calling a function.
-
- >>> validate_args(lambda a: None)
- Traceback (most recent call last):
- ...
- MissingArgs: Missing argument(s): a
- >>> validate_args(lambda a, b, c, d: None, 0, c=1)
- Traceback (most recent call last):
- ...
- MissingArgs: Missing argument(s): b, d
-
- :param fn: the function to check
- :param arg: the positional arguments supplied
- :param kwargs: the keyword arguments supplied
- """
- argspec = inspect.getargspec(fn)
-
- num_defaults = len(argspec.defaults or [])
- required_args = argspec.args[:len(argspec.args) - num_defaults]
-
- def isbound(method):
- return getattr(method, '__self__', None) is not None
-
- if isbound(fn):
- required_args.pop(0)
-
- missing = [arg for arg in required_args if arg not in kwargs]
- missing = missing[len(args):]
- if missing:
- raise MissingArgs(missing)
-
-
-def arg(*args, **kwargs):
- """Decorator for CLI args.
-
- Example:
-
- >>> @arg("name", help="Name of the new entity")
- ... def entity_create(args):
- ... pass
- """
- def _decorator(func):
- add_arg(func, *args, **kwargs)
- return func
- return _decorator
-
-
-def env(*args, **kwargs):
- """Returns the first environment variable set.
-
- If all are empty, defaults to '' or keyword arg `default`.
- """
- for arg in args:
- value = os.environ.get(arg)
- if value:
- return value
- return kwargs.get('default', '')
-
-
-def add_arg(func, *args, **kwargs):
- """Bind CLI arguments to a shell.py `do_foo` function."""
-
- if not hasattr(func, 'arguments'):
- func.arguments = []
-
- # NOTE(sirp): avoid dups that can occur when the module is shared across
- # tests.
- if (args, kwargs) not in func.arguments:
- # Because of the semantics of decorator composition if we just append
- # to the options list positional options will appear to be backwards.
- func.arguments.insert(0, (args, kwargs))
-
-
-def unauthenticated(func):
- """Adds 'unauthenticated' attribute to decorated function.
-
- Usage:
-
- >>> @unauthenticated
- ... def mymethod(f):
- ... pass
- """
- func.unauthenticated = True
- return func
-
-
-def isunauthenticated(func):
- """Checks if the function does not require authentication.
-
- Mark such functions with the `@unauthenticated` decorator.
-
- :returns: bool
- """
- return getattr(func, 'unauthenticated', False)
-
-
-def print_list(objs, fields, formatters=None, sortby_index=0,
- mixed_case_fields=None, field_labels=None):
- """Print a list of objects as a table, one row per object.
-
- :param objs: iterable of :class:`Resource`
- :param fields: attributes that correspond to columns, in order
- :param formatters: `dict` of callables for field formatting
- :param sortby_index: index of the field for sorting table rows
- :param mixed_case_fields: fields corresponding to object attributes that
- have mixed case names (e.g., 'serverId')
- :param field_labels: Labels to use in the heading of the table, default to
- fields.
- """
- formatters = formatters or {}
- mixed_case_fields = mixed_case_fields or []
- field_labels = field_labels or fields
- if len(field_labels) != len(fields):
- raise ValueError(_("Field labels list %(labels)s has different number "
- "of elements than fields list %(fields)s"),
- {'labels': field_labels, 'fields': fields})
-
- if sortby_index is None:
- kwargs = {}
- else:
- kwargs = {'sortby': field_labels[sortby_index]}
- pt = prettytable.PrettyTable(field_labels)
- pt.align = 'l'
-
- 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 six.PY3:
- print(encodeutils.safe_encode(pt.get_string(**kwargs)).decode())
- else:
- print(encodeutils.safe_encode(pt.get_string(**kwargs)))
-
-
-def print_dict(dct, dict_property="Property", wrap=0, dict_value='Value'):
- """Print a `dict` as a table of two columns.
-
- :param dct: `dict` to print
- :param dict_property: name of the first column
- :param wrap: wrapping for the second column
- :param dict_value: header label for the value (second) column
- """
- pt = prettytable.PrettyTable([dict_property, dict_value])
- pt.align = 'l'
- for k, v in sorted(dct.items()):
- # convert dict to str to check length
- if isinstance(v, dict):
- v = six.text_type(v)
- if wrap > 0:
- v = textwrap.fill(six.text_type(v), wrap)
- # if value has a newline, add in multiple rows
- # e.g. fault with stacktrace
- if v and isinstance(v, six.string_types) and r'\n' in v:
- lines = v.strip().split(r'\n')
- col1 = k
- for line in lines:
- pt.add_row([col1, line])
- col1 = ''
- else:
- pt.add_row([k, v])
-
- if six.PY3:
- print(encodeutils.safe_encode(pt.get_string()).decode())
- else:
- print(encodeutils.safe_encode(pt.get_string()))
-
-
-def get_password(max_password_prompts=3):
- """Read password from TTY."""
- verify = strutils.bool_from_string(env("OS_VERIFY_PASSWORD"))
- pw = None
- if hasattr(sys.stdin, "isatty") and sys.stdin.isatty():
- # Check for Ctrl-D
- try:
- for __ in moves.range(max_password_prompts):
- pw1 = getpass.getpass("OS Password: ")
- if verify:
- pw2 = getpass.getpass("Please verify: ")
- else:
- pw2 = pw1
- if pw1 == pw2 and pw1:
- pw = pw1
- break
- except EOFError:
- pass
- return pw
-
-
-def service_type(stype):
- """Adds 'service_type' attribute to decorated function.
-
- Usage:
-
- .. code-block:: python
-
- @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 exit(msg=''):
- if msg:
- print (msg, file=sys.stderr)
- sys.exit(1)
diff --git a/saharaclient/shell.py b/saharaclient/shell.py
deleted file mode 100644
index b0236eb..0000000
--- a/saharaclient/shell.py
+++ /dev/null
@@ -1,732 +0,0 @@
-# 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 logging
-import sys
-import warnings
-
-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 keystoneauth1.identity.generic import password
-from keystoneauth1.identity.generic import token
-from keystoneauth1.loading import session
-from keystoneclient.auth.identity import v3 as identity
-from oslo_utils import encodeutils
-from oslo_utils import strutils
-
-from saharaclient.api import client
-from saharaclient.api import shell as shell_api
-from saharaclient.openstack.common.apiclient import auth
-from saharaclient.openstack.common.apiclient import exceptions as exc
-from saharaclient.openstack.common import cliutils
-from saharaclient import version
-
-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 SaharaClientArgumentParser(argparse.ArgumentParser):
-
- def __init__(self, *args, **kwargs):
- super(SaharaClientArgumentParser, 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 OpenStackSaharaShell(object):
-
- def get_base_parser(self):
- parser = SaharaClientArgumentParser(
- 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)
-
- parser.add_argument('--version',
- action='version',
- version=version.version_info.version_string())
-
- 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('--region-name',
- metavar='<region-name>',
- default=cliutils.env('SAHARA_REGION_NAME',
- 'OS_REGION_NAME'),
- help='Defaults to env[OS_REGION_NAME].')
- parser.add_argument('--region_name',
- 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
-# 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
-# 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',
- 'OS_ENDPOINT_TYPE',
- default=DEFAULT_ENDPOINT_TYPE),
- help=('Defaults to env[SAHARA_ENDPOINT_TYPE] or'
- ' env[OS_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('--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)
-
- parser.add_argument('--os-tenant-name',
- default=cliutils.env('OS_TENANT_NAME'),
- help='Defaults to env[OS_TENANT_NAME].')
-
- parser.add_argument('--os-tenant-id',
- default=cliutils.env('OS_TENANT_ID'),
- help='Defaults to env[OS_TENANT_ID].')
-
- parser.add_argument('--os-auth-system',
- default=cliutils.env('OS_AUTH_SYSTEM'),
- help='Defaults to env[OS_AUTH_SYSTEM].')
-
- parser.add_argument('--os-auth-token',
- default=cliutils.env('OS_AUTH_TOKEN'),
- help='Defaults to env[OS_AUTH_TOKEN].')
-
- # Use Keystoneclient/Keystoneauth API to parse authentication arguments
- session.Session().register_argparse_arguments(parser)
- identity.Password.register_argparse_arguments(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)
-
- self._add_bash_completion_subparser(subparsers)
-
- return parser
-
- 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 _get_keystone_auth(self, session, auth_url, **kwargs):
- auth_token = kwargs.pop('auth_token', None)
- if auth_token:
- return token.Token(auth_url, auth_token, **kwargs)
- else:
- return password.Password(
- auth_url,
- username=kwargs.pop('username'),
- user_id=kwargs.pop('user_id'),
- password=kwargs.pop('password'),
- user_domain_id=kwargs.pop('user_domain_id'),
- user_domain_name=kwargs.pop('user_domain_name'),
- **kwargs)
-
- 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)
- self.options = options
-
- # 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)
-
- # 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_cacert, insecure, region_name) = (
- (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_cacert, args.insecure,
- args.region_name)
- )
-
- if os_auth_system and os_auth_system != "keystone":
- auth_plugin = auth.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 - 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_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
-# 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 - 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
-
- # V3 stuff
- project_info_provided = (self.options.os_tenant_name or
- self.options.os_tenant_id or
- (self.options.os_project_name and
- (self.options.os_project_domain_name or
- self.options.os_project_domain_id)) or
- self.options.os_project_id)
-
- if (not project_info_provided):
- raise exc.CommandError(
- ("You must provide a tenant_name, tenant_id, "
- "project_id or project_name (with "
- "project_domain_name or project_domain_id) via "
- " --os-tenant-name (env[OS_TENANT_NAME]),"
- " --os-tenant-id (env[OS_TENANT_ID]),"
- " --os-project-id (env[OS_PROJECT_ID])"
- " --os-project-name (env[OS_PROJECT_NAME]),"
- " --os-project-domain-id "
- "(env[OS_PROJECT_DOMAIN_ID])"
- " --os-project-domain-name "
- "(env[OS_PROJECT_DOMAIN_NAME])"))
-
- if not os_auth_url:
- raise exc.CommandError(
- "You must provide an auth url "
- "via either --os-auth-url or env[OS_AUTH_URL]")
-
- keystone_session = None
- keystone_auth = None
- if not auth_plugin:
- project_id = args.os_project_id or args.os_tenant_id
- project_name = args.os_project_name or args.os_tenant_name
-
- keystone_session = (session.Session().
- load_from_argparse_arguments(args))
- keystone_auth = self._get_keystone_auth(
- keystone_session,
- args.os_auth_url,
- username=args.os_username,
- user_id=args.os_user_id,
- user_domain_id=args.os_user_domain_id,
- user_domain_name=args.os_user_domain_name,
- password=args.os_password,
- auth_token=args.os_auth_token,
- project_id=project_id,
- project_name=project_name,
- project_domain_id=args.os_project_domain_id,
- project_domain_name=args.os_project_domain_name)
-
- 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,
- sahara_url=bypass_url,
- endpoint_type=endpoint_type,
- session=keystone_session,
- auth=keystone_auth,
- cacert=os_cacert,
- insecure=insecure,
- service_type=service_type,
- region_name=region_name)
-
- 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 do_bash_completion(self, _args):
- """Prints arguments for bash-completion.
-
- 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():
- warnings.simplefilter('once', category=DeprecationWarning)
- warnings.warn('The sahara CLI is deprecated in favor of OpenStackClient '
- 'plugin and will not be maintained anymore. '
- 'For a Python library, continue using python-saharaclient.',
- DeprecationWarning)
- warnings.resetwarnings()
- try:
- argv = [encodeutils.safe_decode(a) for a in sys.argv[1:]]
- OpenStackSaharaShell().main(argv)
-
- except Exception as e:
- logger.debug(e, exc_info=1)
- print("ERROR: %s" % encodeutils.safe_encode(six.text_type(e)),
- file=sys.stderr)
- sys.exit(1)
-
-
-if __name__ == "__main__":
- main()
diff --git a/saharaclient/tests/unit/nova/__init__.py b/saharaclient/tests/unit/nova/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/saharaclient/tests/unit/nova/__init__.py
+++ /dev/null
diff --git a/saharaclient/tests/unit/nova/test_shell.py b/saharaclient/tests/unit/nova/test_shell.py
deleted file mode 100644
index a99a745..0000000
--- a/saharaclient/tests/unit/nova/test_shell.py
+++ /dev/null
@@ -1,366 +0,0 @@
-#
-# 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 re
-import sys
-
-import fixtures
-import mock
-import six
-from testtools import matchers
-
-import saharaclient.api.client
-from saharaclient.openstack.common.apiclient import exceptions
-import saharaclient.shell
-from saharaclient.tests.unit.nova import utils
-
-FAKE_ENV = {'OS_USERNAME': 'username',
- 'OS_PASSWORD': 'password',
- 'OS_TENANT_NAME': 'tenant_name',
- 'OS_AUTH_URL': 'http://no.where'}
-
-FAKE_ENV2 = {'OS_USERNAME': 'username',
- 'OS_PASSWORD': 'password',
- 'OS_TENANT_ID': 'tenant_id',
- 'OS_AUTH_URL': 'http://no.where'}
-
-
-class FakePlugin(object):
- name = 'fake'
- versions = ['1.0', ]
- title = 'a fake plugin'
-
-
-class FakePluginManager(object):
- def list(self):
- return (FakePlugin(),)
-
-
-class FakeImage(object):
- name = 'fake'
- id = 'aaa-bb-ccc'
- username = 'you'
- description = None
- tags = []
-
-
-class FakeImageManager(object):
- def list(self):
- return (FakeImage(),)
-
-
-class FakePluginClient(object):
- def __init__(self, *args, **kwargs):
- self.plugins = FakePluginManager()
- self.images = FakeImageManager()
-
-
-class ShellTest(utils.TestCase):
-
- def make_env(self, exclude=None, fake_env=FAKE_ENV):
- env = dict((k, v) for k, v in fake_env.items() if k != exclude)
- self.useFixture(fixtures.MonkeyPatch('os.environ', env))
-
- def setUp(self):
- super(ShellTest, self).setUp()
-# NA atm
-# self.useFixture(fixtures.MonkeyPatch(
-# 'novaclient.client.get_client_class',
-# mock.MagicMock))
-# self.nc_util = mock.patch('novaclient.utils.isunauthenticated').start()
-# self.nc_util.return_value = False
-
- def shell(self, argstr, exitcodes=(0,)):
- orig = sys.stdout
- orig_stderr = sys.stderr
- try:
- sys.stdout = six.StringIO()
- sys.stderr = six.StringIO()
- _shell = saharaclient.shell.OpenStackSaharaShell()
- _shell.main(argstr.split())
- except SystemExit:
- exc_type, exc_value, exc_traceback = sys.exc_info()
- self.assertIn(exc_value.code, exitcodes)
- finally:
- stdout = sys.stdout.getvalue()
- sys.stdout.close()
- sys.stdout = orig
- stderr = sys.stderr.getvalue()
- sys.stderr.close()
- sys.stderr = orig_stderr
- return (stdout, stderr)
-
- def test_help_unknown_command(self):
- self.assertRaises(exceptions.CommandError, self.shell, 'help foofoo')
-
-# NA
-# def test_invalid_timeout(self):
-# for f in [0, -1, -10]:
-# cmd_text = '--timeout %s' % (f)
-# stdout, stderr = self.shell(cmd_text, exitcodes=[0, 2])
-# required = [
-# 'argument --timeout: %s must be greater than 0' % (f),
-# ]
-# for r in required:
-# self.assertIn(r, stderr)
-
- def test_help(self):
- required = [
- '.*?^usage: sahara',
- '.*?^\s+plugin-list\s+Print a list of available plugins.',
- '.*?^See "sahara help COMMAND" for help on a specific command',
- ]
- stdout, stderr = self.shell('help')
- for r in required:
- self.assertThat((stdout + stderr),
- matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))
-
- def test_help_on_subcommand(self):
- required = [
- '.*?^usage: sahara plugin-list',
- '.*?^Print a list of available plugins.',
- ]
- stdout, stderr = self.shell('help plugin-list')
- for r in required:
- self.assertThat((stdout + stderr),
- matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))
-
- def test_help_no_options(self):
- required = [
- '.*?^usage: sahara',
- '.*?^\s+plugin-list\s+Print a list of available plugins.',
- '.*?^See "sahara help COMMAND" for help on a specific command',
- ]
- stdout, stderr = self.shell('')
- for r in required:
- self.assertThat((stdout + stderr),
- matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))
-
- def test_bash_completion(self):
- stdout, stderr = self.shell('bash-completion')
- # just check we have some output
- required = [
- '.*help',
- '.*plugin-list',
- '.*plugin-show',
- '.*--name']
- for r in required:
- self.assertThat((stdout + stderr),
- matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))
-
- def test_no_username(self):
- required = ('You must provide a username'
- ' via either --os-username or env[OS_USERNAME]',)
- self.make_env(exclude='OS_USERNAME')
- try:
- self.shell('plugin-list')
- except exceptions.CommandError as message:
- self.assertEqual(required, message.args)
- else:
- self.fail('CommandError not raised')
-
- def test_no_tenant_name(self):
- required = (
- 'You must provide a tenant_name, tenant_id, '
- 'project_id or project_name (with '
- 'project_domain_name or project_domain_id) via '
- ' --os-tenant-name (env[OS_TENANT_NAME]),'
- ' --os-tenant-id (env[OS_TENANT_ID]),'
- ' --os-project-id (env[OS_PROJECT_ID])'
- ' --os-project-name (env[OS_PROJECT_NAME]),'
- ' --os-project-domain-id '
- '(env[OS_PROJECT_DOMAIN_ID])'
- ' --os-project-domain-name '
- '(env[OS_PROJECT_DOMAIN_NAME])',
- )
- self.make_env(exclude='OS_TENANT_NAME')
- try:
- self.shell('plugin-list')
- except exceptions.CommandError as message:
- self.assertEqual(required, message.args)
- else:
- self.fail('CommandError not raised')
-
- def test_no_tenant_id(self):
- required = (
- 'You must provide a tenant_name, tenant_id, '
- 'project_id or project_name (with '
- 'project_domain_name or project_domain_id) via '
- ' --os-tenant-name (env[OS_TENANT_NAME]),'
- ' --os-tenant-id (env[OS_TENANT_ID]),'
- ' --os-project-id (env[OS_PROJECT_ID])'
- ' --os-project-name (env[OS_PROJECT_NAME]),'
- ' --os-project-domain-id '
- '(env[OS_PROJECT_DOMAIN_ID])'
- ' --os-project-domain-name '
- '(env[OS_PROJECT_DOMAIN_NAME])',
- )
- self.make_env(exclude='OS_TENANT_ID', fake_env=FAKE_ENV2)
- try:
- self.shell('plugin-list')
- except exceptions.CommandError as message:
- self.assertEqual(required, message.args)
- else:
- self.fail('CommandError not raised')
-
- def test_no_auth_url(self):
- required = ('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]',)
- self.make_env(exclude='OS_AUTH_URL')
- try:
- self.shell('plugin-list')
- except exceptions.CommandError as message:
- self.assertEqual(required, message.args)
- else:
- self.fail('CommandError not raised')
-
-# @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('saharaclient.api.client.Client', FakePluginClient)
- def test_password(self):
- ex = (
- '+------+----------+---------------+\n'
- '| name | versions | title |\n'
- '+------+----------+---------------+\n'
- '| fake | 1.0 | a fake plugin |\n'
- '+------+----------+---------------+\n'
- )
-# self.make_env(exclude='OS_PASSWORD')
- self.make_env()
- stdout, stderr = self.shell('plugin-list')
- self.assertEqual(ex, (stdout + stderr))
-
-# @mock.patch('sys.stdin', side_effect=mock.MagicMock)
-# @mock.patch('getpass.getpass', side_effect=EOFError)
-# def test_no_password(self, mock_getpass, mock_stdin):
- def test_no_password(self):
- required = ('Expecting a password provided'
- ' via either --os-password, env[OS_PASSWORD],'
- ' or prompted response',)
- self.make_env(exclude='OS_PASSWORD')
- try:
- self.shell('plugin-list')
- except exceptions.CommandError as message:
- self.assertEqual(required, message.args)
- else:
- self.fail('CommandError not raised')
-
-# TODO(mattf) Only one version of API right now
-# def _test_service_type(self, version, service_type, mock_client):
-# if version is None:
-# cmd = 'list'
-# else:
-# cmd = '--os-compute-api-version %s list' % version
-# self.make_env()
-# self.shell(cmd)
-# _, client_kwargs = mock_client.call_args
-# self.assertEqual(service_type, client_kwargs['service_type'])
-#
-# @mock.patch('novaclient.client.Client')
-# def test_default_service_type(self, mock_client):
-# self._test_service_type(None, 'compute', mock_client)
-#
-# @mock.patch('novaclient.client.Client')
-# def test_v1_1_service_type(self, mock_client):
-# self._test_service_type('1.1', 'compute', mock_client)
-#
-# @mock.patch('novaclient.client.Client')
-# def test_v2_service_type(self, mock_client):
-# self._test_service_type('2', 'compute', mock_client)
-#
-# @mock.patch('novaclient.client.Client')
-# def test_v3_service_type(self, mock_client):
-# self._test_service_type('3', 'computev3', mock_client)
-#
-# @mock.patch('novaclient.client.Client')
-# def test_v_unknown_service_type(self, mock_client):
-# self._test_service_type('unknown', 'compute', mock_client)
-
- @mock.patch('saharaclient.api.client.Client', FakePluginClient)
- def test_image_list(self):
- ex = (
- '+------+------------+----------+------+-------------+\n'
- '| name | id | username | tags | description |\n'
- '+------+------------+----------+------+-------------+\n'
- '| fake | aaa-bb-ccc | you | | None |\n'
- '+------+------------+----------+------+-------------+\n'
- )
- self.make_env()
- stdout, stderr = self.shell('image-list')
- self.assertEqual(ex, (stdout + stderr))
-
-
-class ShellTestKeystoneV3(ShellTest):
-
- FAKE_V3_ENV = {'OS_USERNAME': 'username',
- 'OS_PASSWORD': 'password',
- 'OS_PROJECT_NAME': 'project_name',
- 'OS_PROJECT_DOMAIN_NAME': 'project_domain_name',
- 'OS_USER_DOMAIN_NAME': 'user_domain_name',
- 'OS_AUTH_URL': 'http://no.where/v3'}
-
- version_id = u'v3'
- links = [{u'href': u'http://no.where/v3', u'rel': u'self'}]
-
- def make_env(self, exclude=None, fake_env=FAKE_V3_ENV):
- if 'OS_AUTH_URL' in fake_env:
- fake_env.update({'OS_AUTH_URL': 'http://no.where/v3'})
- env = dict((k, v) for k, v in fake_env.items() if k != exclude)
- self.useFixture(fixtures.MonkeyPatch('os.environ', env))
-
- def test_no_tenant_name(self):
- # In V3, tenant_name = project_name
- required = (
- 'You must provide a tenant_name, tenant_id, '
- 'project_id or project_name (with '
- 'project_domain_name or project_domain_id) via '
- ' --os-tenant-name (env[OS_TENANT_NAME]),'
- ' --os-tenant-id (env[OS_TENANT_ID]),'
- ' --os-project-id (env[OS_PROJECT_ID])'
- ' --os-project-name (env[OS_PROJECT_NAME]),'
- ' --os-project-domain-id '
- '(env[OS_PROJECT_DOMAIN_ID])'
- ' --os-project-domain-name '
- '(env[OS_PROJECT_DOMAIN_NAME])',
- )
- self.make_env(exclude='OS_PROJECT_NAME')
- try:
- self.shell('plugin-list')
- except exceptions.CommandError as message:
- self.assertEqual(required, message.args)
- else:
- self.fail('CommandError not raised')
-
- def test_job_list(self):
- expected = '\n'.join([
- '+----+------------+------------+--------+',
- '| id | cluster_id | start_time | status |',
- '+----+------------+------------+--------+',
- '+----+------------+------------+--------+',
- ''
- ])
-
- mock_get_service_type_method_name = (
- 'saharaclient.api.client.Client._determine_service_type')
- mock_job_executions_class_name = (
- 'saharaclient.api.job_executions.JobExecutionsManager')
-
- with mock.patch(mock_get_service_type_method_name) as mock_st:
- with mock.patch(mock_job_executions_class_name):
- mock_st.return_value = 'data-processing'
- self.make_env()
- stdout, stderr = self.shell('job-list')
- self.assertEqual((stdout + stderr), expected)
diff --git a/saharaclient/tests/unit/nova/utils.py b/saharaclient/tests/unit/nova/utils.py
deleted file mode 100644
index 5c7acba..0000000
--- a/saharaclient/tests/unit/nova/utils.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import os
-
-import fixtures
-import requests
-import testtools
-
-
-class TestCase(testtools.TestCase):
- TEST_REQUEST_BASE = {
- 'verify': True,
- }
-
- def setUp(self):
- super(TestCase, self).setUp()
- if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
- os.environ.get('OS_STDOUT_CAPTURE') == '1'):
- stdout = self.useFixture(fixtures.StringStream('stdout')).stream
- self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
- if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
- os.environ.get('OS_STDERR_CAPTURE') == '1'):
- stderr = self.useFixture(fixtures.StringStream('stderr')).stream
- self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
-
-
-class TestResponse(requests.Response):
- """Wrap requests.Response and provide a way to initialize with a dict."""
-
- def __init__(self, data):
- self._text = None
- super(TestResponse, self)
- if isinstance(data, dict):
- self.status_code = data.get('status_code', None)
- self.headers = data.get('headers', None)
- # Fake the text attribute to streamline Response creation
- self._text = data.get('text', None)
- else:
- self.status_code = data
-
- def __eq__(self, other):
- return self.__dict__ == other.__dict__
-
- @property
- def text(self):
- return self._text
diff --git a/setup.cfg b/setup.cfg
index f9e9b98..9523624 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -27,9 +27,6 @@ packages =
saharaclient
[entry_points]
-console_scripts =
- sahara = saharaclient.shell:main
-
openstack.cli.extension =
data_processing = saharaclient.osc.plugin
diff --git a/tox.ini b/tox.ini
index e9745a7..d50df85 100644
--- a/tox.ini
+++ b/tox.ini
@@ -62,7 +62,4 @@ commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasen
[flake8]
show-source = true
builtins = _
-exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,tools
-
-[hacking]
-import_exceptions = saharaclient.openstack.common._i18n._
+exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,tools