# Copyright 2015 - Mirantis, 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. import argparse import collections import inspect import json import os from cinderclient import utils as cinder_base from cinderclient.v2 import client as cinderclient from glanceclient.v2 import client as glanceclient from heatclient.openstack.common.apiclient import base as heat_base from heatclient.v1 import client as heatclient from keystoneclient import base as keystone_base from keystoneclient.v3 import client as keystoneclient from novaclient.openstack.common.apiclient import base as nova_base from novaclient import client as novaclient # TODO(nmakhotkin): Find a rational way to do it for neutron. # TODO(nmakhotkin): Implement recursive way of searching for managers # TODO(nmakhotkin): (e.g. keystone). """It is simple CLI tool which allows to see and update mapping.json file if needed. mapping.json contains all allowing OpenStack actions sorted by service name. Usage example: python tools/get_action_list.py nova The result will be simple JSON containing action name as a key and method path as a value. For updating mapping.json it is need to copy all keys and values of the result to corresponding section of mapping.json: ...mapping.json... "nova": { }, ...mapping.json... Note: in case of Keystone service, correct OS_AUTH_URL v3 and the rest auth info must be provided. It can be provided either via environment variables or CLI arguments. See --help for details. """ BASE_HEAT_MANAGER = heat_base.HookableMixin BASE_NOVA_MANAGER = nova_base.HookableMixin BASE_KEYSTONE_MANAGER = keystone_base.Manager BASE_CINDER_MANAGER = cinder_base.HookableMixin def get_parser(): parser = argparse.ArgumentParser( description='Gets All needed methods of OpenStack clients.', usage="python get_action_list.py " ) parser.add_argument( 'service', choices=['nova', 'glance', 'heat', 'cinder', 'keystone'], help='Service name which methods need to be found.' ) parser.add_argument( '--os-username', dest='username', default=os.environ.get('OS_USERNAME', 'admin'), help='Authentication username (Env: OS_USERNAME)' ) parser.add_argument( '--os-password', dest='password', default=os.environ.get('OS_PASSWORD', 'openstack'), help='Authentication password (Env: OS_PASSWORD)' ) parser.add_argument( '--os-tenant-name', dest='tenant_name', default=os.environ.get('OS_TENANT_NAME', 'Default'), help='Authentication tenant name (Env: OS_TENANT_NAME)' ) parser.add_argument( '--os-auth-url', dest='auth_url', default=os.environ.get('OS_AUTH_URL'), help='Authentication URL (Env: OS_AUTH_URL)' ) return parser GLANCE_NAMESPACE_LIST = [ 'image_members', 'image_tags', 'images', 'schemas', 'tasks' ] def get_nova_client(**kwargs): return novaclient.Client(2) def get_keystone_client(**kwargs): return keystoneclient.Client(**kwargs) def get_glance_client(**kwargs): return glanceclient.Client(kwargs.get('auth_url')) def get_heat_client(**kwargs): return heatclient.Client('') def get_cinder_client(**kwargs): return cinderclient.Client() CLIENTS = { 'nova': get_nova_client, 'heat': get_heat_client, 'cinder': get_cinder_client, 'keystone': get_keystone_client, 'glance': get_glance_client, # 'neutron': get_nova_client } BASE_MANAGERS = { 'nova': BASE_NOVA_MANAGER, 'heat': BASE_HEAT_MANAGER, 'cinder': BASE_CINDER_MANAGER, 'keystone': BASE_KEYSTONE_MANAGER, 'glance': None, # 'neutron': BASE_NOVA_MANAGER } NAMESPACES = { 'glance': GLANCE_NAMESPACE_LIST } ALLOWED_ATTRS = ['service_catalog', 'catalog'] FORBIDDEN_METHODS = [ 'add_hook', 'alternate_service_type', 'completion_cache', 'run_hooks', 'write_to_completion_cache', 'model', 'build_key_only_query', 'build_url', 'head', 'put' ] def get_public_attrs(obj): all_attrs = dir(obj) return [a for a in all_attrs if not a.startswith('_')] def get_public_methods(attr, client): hierarchy_list = attr.split('.') attribute = client for attr in hierarchy_list: attribute = getattr(attribute, attr) all_attributes_list = get_public_attrs(attribute) methods = [] for a in all_attributes_list: allowed = a in ALLOWED_ATTRS forbidden = a in FORBIDDEN_METHODS if (not forbidden and (allowed or inspect.ismethod(getattr(attribute, a)))): methods.append(a) return methods def get_manager_list(service_name, client): base_manager = BASE_MANAGERS[service_name] if not base_manager: return NAMESPACES[service_name] public_attrs = get_public_attrs(client) manager_list = [] for attr in public_attrs: if (isinstance(getattr(client, attr), base_manager) or attr in ALLOWED_ATTRS): manager_list.append(attr) return manager_list def get_mapping_for_service(service, client): mapping = collections.OrderedDict() for man in get_manager_list(service, client): public_methods = get_public_methods(man, client) for method in public_methods: key = "%s_%s" % (man, method) value = "%s.%s" % (man, method) mapping[key] = value return mapping def print_mapping(mapping): print(json.dumps(mapping, indent=8, separators=(',', ': '))) if __name__ == "__main__": args = get_parser().parse_args() auth_info = { 'username': args.username, 'tenant_name': args.tenant_name, 'password': args.password, 'auth_url': args.auth_url } service = args.service client = CLIENTS.get(service)(**auth_info) print("Find methods for service: %s..." % service) print_mapping(get_mapping_for_service(service, client))