congress-dashboard/congress_dashboard/api/congress.py

387 lines
12 KiB
Python

# Copyright 2014 VMware.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from congressclient.v1 import client as congress_client
from django.conf import settings
# import keystoneauth1.identity.v2 as v2
import keystoneauth1.identity.v3 as v3
import keystoneauth1.session as kssession
from openstack_dashboard.api import base
from oslo_log import log as logging
LITERALS_SEPARATOR = '),'
RULE_SEPARATOR = ':-'
TABLE_SEPARATOR = ':'
LOG = logging.getLogger(__name__)
def format_rule(rule):
"""Make rule's text more human readable."""
head_body = rule.split(RULE_SEPARATOR)
if len(head_body) < 2:
return rule
head = head_body[0]
body = head_body[1]
body_literals = body.split(LITERALS_SEPARATOR)
result = []
for lit in body_literals:
# First remove extra newlines in the literals
lit = lit.strip()
result.append(lit)
# Add newline after each literal in the body.
literals_break = LITERALS_SEPARATOR + '\n'
new_body = literals_break.join(result)
# Add newline after the head.
rules_break = RULE_SEPARATOR + '\n'
return rules_break.join([head, new_body])
def _set_id_as_name_if_empty(apidict, length=0):
try:
if not apidict._apidict.get('name'):
id = apidict._apidict['id']
if length:
id = id[:length]
apidict._apidict['name'] = '(%s)' % id
else:
apidict._apidict['name'] = id
except KeyError:
pass
class PolicyAPIDictWrapper(base.APIDictWrapper):
def set_id_as_name_if_empty(self):
_set_id_as_name_if_empty(self)
def set_id_if_empty(self, id):
apidict_id = self._apidict.get('id')
if not apidict_id or apidict_id == "None":
self._apidict['id'] = id
def set_value(self, key, value):
self._apidict[key] = value
def delete_by_key(self, key):
del self._apidict[key]
class PolicyRule(PolicyAPIDictWrapper):
"""Wrapper for a Congress policy's rule."""
def set_id_as_name_if_empty(self):
pass
class PolicyTable(PolicyAPIDictWrapper):
"""Wrapper for a Congress policy's data table."""
def set_policy_details(self, policy):
self._apidict['policy_name'] = policy['name']
self._apidict['policy_owner_id'] = policy['owner_id']
self._apidict['policy_description'] = policy['description']
def congressclient(request):
"""Instantiate Congress client."""
auth_url = getattr(settings, 'OPENSTACK_KEYSTONE_URL')
user = request.user
session = get_keystone_session(auth_url, user)
region_name = user.services_region
kwargs = {
'session': session,
'auth': None,
'interface': 'publicURL',
'service_type': 'policy',
'region_name': region_name
}
return congress_client.Client(**kwargs)
def get_keystone_session(auth_url, user):
auth = v3.Token(auth_url, user.token.id, project_id=user.tenant_id)
session = kssession.Session(auth=auth)
return session
def policies_list(request):
"""List all policies."""
client = congressclient(request)
policies_list = client.list_policy()
results = policies_list['results']
policies = []
for p in results:
policy = PolicyAPIDictWrapper(p)
# Policies currently have a name but not necessarily a non-"None" id.
# Use the name to identify the policy, needed to differentiate them in
# DataTables.
policy.set_id_if_empty(policy.get('name'))
policies.append(policy)
return policies
def policy_create(request, args):
"""Create a policy with the given properties."""
client = congressclient(request)
policy = client.create_policy(args)
return policy
def policy_delete(request, policy_id):
"""Delete a policy by id."""
client = congressclient(request)
policy = client.delete_policy(policy_id)
return policy
def policy_get(request, policy_name):
"""Get a policy by name."""
# TODO(jwy): Use congress.show_policy() once system policies have unique
# IDs.
policies = policies_list(request)
for p in policies:
if p['name'] == policy_name:
return p
def policy_rule_create(request, policy_name, body=None):
"""Create a rule in the given policy, with the given properties."""
client = congressclient(request)
rule = client.create_policy_rule(policy_name, body=body)
return rule
def policy_rule_delete(request, policy_name, rule_id):
"""Delete a rule by id, from the given policy."""
client = congressclient(request)
rule = client.delete_policy_rule(policy_name, rule_id)
return rule
def policy_rules_list(request, policy_name):
"""List all rules in a policy, given by name."""
client = congressclient(request)
policy_rules_list = client.list_policy_rules(policy_name)
results = policy_rules_list['results']
return [PolicyRule(r) for r in results]
def policy_tables_list(request, policy_name):
"""List all data tables in a policy, given by name."""
client = congressclient(request)
policy_tables_list = client.list_policy_tables(policy_name)
results = policy_tables_list['results']
return [PolicyTable(t) for t in results]
def policy_table_get(request, policy_name, table_name):
"""Get a policy table in a policy, given by name."""
client = congressclient(request)
return client.show_policy_table(policy_name, table_name)
def policy_rows_list(request, policy_name, table_name):
"""List all rows in a policy's data table, given by name."""
client = congressclient(request)
policy_rows_list = client.list_policy_rows(policy_name, table_name)
results = policy_rows_list['results']
policy_rows = []
# Policy table rows currently don't have ids. However, the DataTable object
# requires an id for the table to get rendered properly. Otherwise, the
# same contents are displayed for every row in the table. Assign the rows
# ids here.
id = 0
for row in results:
new_row = PolicyAPIDictWrapper(row)
new_row.set_id_if_empty(id)
id += 1
policy_rows.append(new_row)
return policy_rows
def policy_table_schema_get(request, policy_name, table_name):
"""Get the schema for a policy table, based on the first matching rule."""
column_names = []
rules = policy_rules_list(request, policy_name)
# There might be multiple rules that use the same name in the head. Pick
# the first matching one, which is what the policy engine currently does.
for rule in rules:
rule_def = rule['rule']
head, _ = rule_def.split(RULE_SEPARATOR)
if head.strip().startswith('%s(' % table_name):
start = head.index('(') + 1
end = head.index(')')
column_names = head[start:end].split(',')
break
schema = {'table_id': table_name}
schema['columns'] = [{'name': name.strip(), 'description': None}
for name in column_names]
return schema
def datasources_list(request):
"""List all the data sources."""
client = congressclient(request)
datasources_list = client.list_datasources()
datasources = datasources_list['results']
return [PolicyAPIDictWrapper(d) for d in datasources]
def datasource_get(request, datasource_id):
"""Get a data source by id."""
# TODO(jwy): Need API in congress_client to retrieve data source by id.
datasources = datasources_list(request)
for d in datasources:
if d['id'] == datasource_id:
return d
def datasource_get_by_name(request, datasource_name):
"""Get a data source by name."""
datasources = datasources_list(request)
for d in datasources:
if d['name'] == datasource_name:
return d
def datasource_tables_list(request, datasource_id):
"""List all data tables in a data source, given by id."""
client = congressclient(request)
datasource_tables_list = client.list_datasource_tables(datasource_id)
results = datasource_tables_list['results']
return [PolicyAPIDictWrapper(t) for t in results]
def datasource_rows_list(request, datasource_id, table_name):
"""List all rows in a data source's data table, given by id."""
client = congressclient(request)
datasource_rows_list = client.list_datasource_rows(datasource_id,
table_name)
results = datasource_rows_list['results']
datasource_rows = []
id = 0
for row in results:
new_row = PolicyAPIDictWrapper(row)
new_row.set_id_if_empty(id)
id += 1
datasource_rows.append(new_row)
return datasource_rows
def datasource_schema_get(request, datasource_id):
"""Get the schema for all tables in the given data source."""
client = congressclient(request)
return client.show_datasource_schema(datasource_id)
def datasource_table_schema_get(request, datasource_id, table_name):
"""Get the schema for a data source table."""
client = congressclient(request)
return client.show_datasource_table_schema(datasource_id, table_name)
def datasource_table_schema_get_by_name(request, datasource_name, table_name):
"""Get the schema for a data source table."""
datasource = datasource_get_by_name(request, datasource_name)
client = congressclient(request)
return client.show_datasource_table_schema(datasource['id'], table_name)
def datasource_statuses_list(request):
client = congressclient(request)
datasources_list = client.list_datasources()
datasources = datasources_list['results']
ds_status = []
for ds in datasources:
try:
status = client.list_datasource_status(ds['id'])
except Exception:
LOG.exception("Exception while getting the status")
raise
wrapper = PolicyAPIDictWrapper(ds)
wrapper.set_value('service', ds['name'])
for key in status:
value = status[key]
wrapper.set_value(key, value)
ds_status.append(wrapper)
return ds_status
def datasource_status_list(request, datasource_name):
client = congressclient(request)
try:
status = client.list_datasource_status(datasource_name)
return status
except Exception:
LOG.exception("Failed to retrieve status for datasource %s",
datasource_name)
raise
def supported_driver_list(request):
client = congressclient(request)
try:
data = client.list_drivers()['results']
drivers = [(d['id'], d['id']) for d in data]
return drivers
except Exception:
LOG.exception("Unable to get driver list")
raise
def create_datasource(request, data):
client = congressclient(request)
datasource = client.create_datasource(data)
return datasource
def delete_datasource(request, datasource_name):
client = congressclient(request)
try:
client.delete_datasource(datasource_name)
except Exception:
LOG.exception("deleting datasource %s failed", datasource_name)
raise
def list_policies_from_library(request):
client = congressclient(request)
try:
results = client.list_library_policy()['results']
policies = []
for p in results:
policy = PolicyAPIDictWrapper(p)
policies.append(policy)
return policies
except Exception:
LOG.exception("List library policies failed")
raise
def show_library_policy(request, name):
client = congressclient(request)
try:
policy = client.show_library_policy(name)
rules = [PolicyRule(r) for r in policy['rules']]
return policy, rules
except Exception:
LOG.exception("unable to get library policy '%s' details", name)
raise