def4b17934
nova/db/__init__.py was importing * from nova.db.api. This meant that any time any code anywhere within the nova.db package was imported then nova.db.api was too, leading to a cascade of imports that may not have been desired. Also, in general, code in __init__.py is a pain. Therefore, this change adjusts code that so that either: * nova.db.api is used directly * nova.db.api is imported as 'db' In either case, the functionality remains the same. The primary goal of this change was to make it possible to import the model files without having to import the db api. Moving the model files to a different place in the directory hierarchy was considered, but given that "code in __init__.py is a pain" this mode was chosen. This looks like a very large change, but it is essentially adjusting package names, many in mocks. Change-Id: Ic1fd7c87ceda05eeb96735da2a415ef37060bb1a
175 lines
5.8 KiB
Python
175 lines
5.8 KiB
Python
# Copyright 2016 Cloudbase Solutions Srl
|
|
# 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.
|
|
|
|
"""
|
|
CLI interface for nova policy rule commands.
|
|
"""
|
|
|
|
import functools
|
|
import os
|
|
import sys
|
|
|
|
from oslo_config import cfg
|
|
|
|
from nova.cmd import common as cmd_common
|
|
import nova.conf
|
|
from nova import config
|
|
from nova import context as nova_context
|
|
from nova.db import api as db
|
|
from nova import exception
|
|
from nova.i18n import _
|
|
from nova import policies
|
|
from nova import version
|
|
|
|
CONF = nova.conf.CONF
|
|
|
|
|
|
cli_opts = [
|
|
cfg.ListOpt(
|
|
'os-roles',
|
|
metavar='<auth-roles>',
|
|
default=os.environ.get('OS_ROLES'),
|
|
help=_('Defaults to env[OS_ROLES].')),
|
|
cfg.StrOpt(
|
|
'os-user-id',
|
|
metavar='<auth-user-id>',
|
|
default=os.environ.get('OS_USER_ID'),
|
|
help=_('Defaults to env[OS_USER_ID].')),
|
|
cfg.StrOpt(
|
|
'os-tenant-id',
|
|
metavar='<auth-tenant-id>',
|
|
default=os.environ.get('OS_TENANT_ID'),
|
|
help=_('Defaults to env[OS_TENANT_ID].')),
|
|
]
|
|
|
|
|
|
class PolicyCommands(object):
|
|
"""Commands for policy rules."""
|
|
|
|
_ACCEPTABLE_TARGETS = [
|
|
'project_id', 'user_id', 'quota_class', 'availability_zone',
|
|
'instance_id']
|
|
|
|
@cmd_common.args('--api-name', dest='api_name', metavar='<API name>',
|
|
help='Will return only passing policy rules containing '
|
|
'the given API name.')
|
|
@cmd_common.args('--target', nargs='+', dest='target', metavar='<Target>',
|
|
help='Will return only passing policy rules for the '
|
|
'given target. The available targets are %s. When '
|
|
'"instance_id" is used, the other targets will be '
|
|
'overwritten.' % ','.join(_ACCEPTABLE_TARGETS))
|
|
def check(self, api_name=None, target=None):
|
|
"""Prints all passing policy rules for the given user.
|
|
|
|
:param api_name: If None, all passing policy rules will be printed,
|
|
otherwise, only passing policies that contain the
|
|
given api_name in their names.
|
|
:param target: The target against which the policy rule authorization
|
|
will be tested. If None, the given user will be
|
|
considered as the target.
|
|
"""
|
|
context = self._get_context()
|
|
api_name = api_name or ''
|
|
target = self._get_target(context, target)
|
|
|
|
allowed_operations = self._filter_rules(context, api_name, target)
|
|
|
|
if allowed_operations:
|
|
print('\n'.join(allowed_operations))
|
|
return 0
|
|
else:
|
|
print('No rules matched or allowed')
|
|
return 1
|
|
|
|
def _get_context(self):
|
|
return nova_context.RequestContext(
|
|
roles=CONF.os_roles,
|
|
user_id=CONF.os_user_id,
|
|
project_id=CONF.os_tenant_id)
|
|
|
|
def _get_target(self, context, target):
|
|
"""Processes and validates the CLI given target and adapts it for
|
|
policy authorization.
|
|
|
|
:returns: None if the given target is None, otherwise returns a proper
|
|
authorization target.
|
|
:raises nova.exception.InvalidAttribute: if a key in the given target
|
|
is not an acceptable.
|
|
:raises nova.exception.InstanceNotFound: if 'instance_id' is given, and
|
|
there is no instance match the id.
|
|
"""
|
|
if not target:
|
|
return None
|
|
|
|
new_target = {}
|
|
for t in target:
|
|
key, value = t.split('=')
|
|
if key not in self._ACCEPTABLE_TARGETS:
|
|
raise exception.InvalidAttribute(attr=key)
|
|
new_target[key] = value
|
|
|
|
# if the target is an instance_id, return an instance instead.
|
|
instance_id = new_target.get('instance_id')
|
|
if instance_id:
|
|
admin_ctxt = nova_context.get_admin_context()
|
|
instance = db.instance_get_by_uuid(admin_ctxt, instance_id)
|
|
new_target = {'user_id': instance['user_id'],
|
|
'project_id': instance['project_id']}
|
|
|
|
return new_target
|
|
|
|
def _filter_rules(self, context, api_name, target):
|
|
all_rules = policies.list_rules()
|
|
return [rule.name for rule in all_rules if api_name in rule.name and
|
|
context.can(rule.name, target, fatal=False)]
|
|
|
|
|
|
CATEGORIES = {
|
|
'policy': PolicyCommands,
|
|
}
|
|
|
|
|
|
add_command_parsers = functools.partial(cmd_common.add_command_parsers,
|
|
categories=CATEGORIES)
|
|
|
|
|
|
category_opt = cfg.SubCommandOpt('category',
|
|
title='Command categories',
|
|
help='Available categories',
|
|
handler=add_command_parsers)
|
|
|
|
|
|
def main():
|
|
"""Parse options and call the appropriate class/method."""
|
|
CONF.register_cli_opts(cli_opts)
|
|
CONF.register_cli_opt(category_opt)
|
|
config.parse_args(sys.argv)
|
|
|
|
if CONF.category.name == "version":
|
|
print(version.version_string_with_package())
|
|
return 0
|
|
|
|
if CONF.category.name == "bash-completion":
|
|
cmd_common.print_bash_completion(CATEGORIES)
|
|
return 0
|
|
|
|
try:
|
|
fn, fn_args, fn_kwargs = cmd_common.get_action_fn()
|
|
ret = fn(*fn_args, **fn_kwargs)
|
|
return ret
|
|
except Exception as ex:
|
|
print(_("error: %s") % ex)
|
|
return 1
|