Skip to content

Commit

Permalink
Rename multi_tenancy to aaa_mode for analytics API
Browse files Browse the repository at this point in the history
Handle keystone v2 and v3 token infos returned by
VNC API. Enable cloud-admin-only aaa_mode by default

Change analytics DB and underlay to overlay mapper to
use local admin port when quering opserver

Do not cache auth_token in vnc lib

Change-Id: Id715e40fe3996964b5298da1cd63c248243071dd
Closes-Bug: #1599654
  • Loading branch information
Megh Bhatt committed Jul 27, 2016
1 parent 306d40e commit a2a7c92
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 33 deletions.
2 changes: 0 additions & 2 deletions src/api-lib/vnc_api.py
Expand Up @@ -1038,8 +1038,6 @@ def virtual_network_subnet_ip_count(self, vnobj, subnet_list):
#end virtual_network_subnet_ip_count

def get_auth_token(self):
if self._auth_token:
return self._auth_token
self._headers = self._authenticate(headers=self._headers)
return self._auth_token

Expand Down
15 changes: 10 additions & 5 deletions src/opserver/analytics_db.py
Expand Up @@ -399,20 +399,25 @@ def db_purge(self, purge_cutoff, purge_id):
return self.db_purge_cql(purge_cutoff, purge_id)
# end db_purge

def get_dbusage_info(self, rest_api_ip, rest_api_port):
def get_dbusage_info(self, ip, port, user, password):
"""Collects database usage information from all db nodes
Returns:
A dictionary with db node name as key and db usage in % as value
"""

to_return = {}
try:
uve_url = "http://" + rest_api_ip + ":" + str(rest_api_port) + "/analytics/uves/database-nodes?cfilt=DatabaseUsageInfo"
node_dburls = json.loads(urllib2.urlopen(uve_url).read())
uve_url = "http://" + ip + ":" + str(port) + \
"/analytics/uves/database-nodes?cfilt=DatabaseUsageInfo"
data = OpServerUtils.get_url_http(uve_url, user, password)
node_dburls = json.loads(data)

for node_dburl in node_dburls:
# calculate disk usage percentage for analytics in each cassandra node
db_uve_state = json.loads(urllib2.urlopen(node_dburl['href']).read())
# calculate disk usage percentage for analytics in each
# cassandra node
db_uve_data = OpServerUtils.get_url_http(node_dburl['href'],
user, password)
db_uve_state = json.loads(db_uve_data)
db_usage_in_perc = (100*
float(db_uve_state['DatabaseUsageInfo']['database_usage'][0]['analytics_db_size_1k'])/
float(db_uve_state['DatabaseUsageInfo']['database_usage'][0]['disk_space_available_1k'] +
Expand Down
26 changes: 14 additions & 12 deletions src/opserver/opserver.py
Expand Up @@ -47,7 +47,8 @@
ModuleCategoryMap, Module2NodeType, NodeTypeNames, ModuleIds,\
INSTANCE_ID_DEFAULT, COLLECTOR_DISCOVERY_SERVICE_NAME,\
ANALYTICS_API_SERVER_DISCOVERY_SERVICE_NAME, ALARM_GENERATOR_SERVICE_NAME, \
OpServerAdminPort, CLOUD_ADMIN_ROLE
OpServerAdminPort, CLOUD_ADMIN_ROLE, AnalyticsAPIAAAModes, \
AAA_MODE_CLOUD_ADMIN_ONLY, AAA_MODE_NO_AUTH
from sandesh.viz.constants import _TABLES, _OBJECT_TABLES,\
_OBJECT_TABLE_SCHEMA, _OBJECT_TABLE_COLUMN_VALUES, \
_STAT_TABLES, STAT_OBJECTID_FIELD, STAT_VT_PREFIX, \
Expand Down Expand Up @@ -777,7 +778,7 @@ def _parse_args(self, args_str=' '.join(sys.argv[1:])):
'partitions' : 15,
'sandesh_send_rate_limit': SandeshSystem. \
get_sandesh_send_rate_limit(),
'multi_tenancy' : False,
'aaa_mode' : AAA_MODE_CLOUD_ADMIN_ONLY,
'api_server' : '127.0.0.1:8082',
'admin_port' : OpServerAdminPort,
'cloud_admin_role' : CLOUD_ADMIN_ROLE,
Expand Down Expand Up @@ -811,9 +812,6 @@ def _parse_args(self, args_str=' '.join(sys.argv[1:])):
config.read(args.conf_file)
if 'DEFAULTS' in config.sections():
defaults.update(dict(config.items("DEFAULTS")))
if 'multi_tenancy' in config.options('DEFAULTS'):
defaults['multi_tenancy'] = config.getboolean(
'DEFAULTS', 'multi_tenancy')
if 'REDIS' in config.sections():
redis_opts.update(dict(config.items('REDIS')))
if 'DISCOVERY' in config.sections():
Expand Down Expand Up @@ -909,8 +907,8 @@ def _parse_args(self, args_str=' '.join(sys.argv[1:])):
help="Sandesh send rate limit in messages/sec")
parser.add_argument("--cloud_admin_role",
help="Name of cloud-admin role")
parser.add_argument("--multi_tenancy", action="store_true",
help="Validate resource permissions (implies token validation)")
parser.add_argument("--aaa_mode", choices=AnalyticsAPIAAAModes,
help="AAA mode")
parser.add_argument("--auth_host",
help="IP address of keystone server")
parser.add_argument("--auth_protocol",
Expand Down Expand Up @@ -946,7 +944,7 @@ def _parse_args(self, args_str=' '.join(sys.argv[1:])):
self._args.auth_host, self._args.auth_port)
auth_conf_info['api_server_use_ssl'] = False
auth_conf_info['cloud_admin_access_only'] = \
self._args.multi_tenancy
False if self._args.aaa_mode == AAA_MODE_NO_AUTH else True
auth_conf_info['cloud_admin_role'] = self._args.cloud_admin_role
auth_conf_info['admin_port'] = self._args.admin_port
api_server_info = self._args.api_server.split(':')
Expand Down Expand Up @@ -1175,8 +1173,10 @@ def _query(self, request):

if tabl == OVERLAY_TO_UNDERLAY_FLOW_MAP:
overlay_to_underlay_map = OverlayToUnderlayMapper(
request.json, self._args.host_ip,
self._args.rest_api_port, self._logger)
request.json, 'localhost',
self._args.auth_conf_info['admin_port'],
self._args.auth_conf_info['admin_user'],
self._args.auth_conf_info['admin_password'], self._logger)
try:
yield overlay_to_underlay_map.process_query()
except OverlayToUnderlayMapperError as e:
Expand Down Expand Up @@ -2001,8 +2001,10 @@ def _auto_purge(self):
while True:
trigger_purge = False
db_node_usage = self._analytics_db.get_dbusage_info(
self._args.rest_api_ip,
self._args.rest_api_port)
'localhost',
self._args.auth_conf_info['admin_port'],
self._args.auth_conf_info['admin_user'],
self._args.auth_conf_info['admin_password'])
self._logger.info("node usage:" + str(db_node_usage) )
self._logger.info("threshold:" + str(self._args.db_purge_threshold))

Expand Down
7 changes: 5 additions & 2 deletions src/opserver/overlay_to_underlay_mapper.py
Expand Up @@ -27,10 +27,12 @@ class OverlayToUnderlayMapperError(Exception):
class OverlayToUnderlayMapper(object):

def __init__(self, query_json, analytics_api_ip,
analytics_api_port, logger):
analytics_api_port, user, password, logger):
self.query_json = query_json
self._analytics_api_ip = analytics_api_ip
self._analytics_api_port = analytics_api_port
self._user = user
self._password = password
self._logger = logger
if self.query_json is not None:
self._start_time = self.query_json['start_time']
Expand Down Expand Up @@ -233,7 +235,8 @@ def _send_query(self, query):
self._logger.debug('Sending query: %s' % (query))
opserver_url = OpServerUtils.opserver_query_url(self._analytics_api_ip,
str(self._analytics_api_port))
resp = OpServerUtils.post_url_http(opserver_url, query, True)
resp = OpServerUtils.post_url_http(opserver_url, query, self._user,
self._password, True)
try:
resp = json.loads(resp)
value = resp['value']
Expand Down
27 changes: 17 additions & 10 deletions src/opserver/test/test_overlay_to_underlay_mapper.py
Expand Up @@ -235,7 +235,7 @@ def test_get_overlay_flow_data_noerror(self, mock_send_query,
overlay_to_underlay_mapper = \
OverlayToUnderlayMapper(
item['input']['overlay_to_underlay_map_query'],
None, None, logging)
None, None, None, None, logging)
self.assertEqual(item['output']['flowrecord_data'],
overlay_to_underlay_mapper._get_overlay_flow_data())
args, _ = overlay_to_underlay_mapper._send_query.call_args
Expand Down Expand Up @@ -296,7 +296,7 @@ def test_get_overlay_flow_data_raise_exception(self):

for query in queries:
overlay_to_underlay_mapper = \
OverlayToUnderlayMapper(query, None, None, logging)
OverlayToUnderlayMapper(query, None, None, None, None, logging)
self.assertRaises(_OverlayToFlowRecordFieldsNameError,
overlay_to_underlay_mapper._get_overlay_flow_data)
# end test_get_overlay_flow_data_raise_exception
Expand Down Expand Up @@ -618,7 +618,7 @@ def test_get_underlay_flow_data_noerror(self, mock_send_query,
overlay_to_underlay_mapper = \
OverlayToUnderlayMapper(
item['input']['overlay_to_underlay_map_query'],
None, None, logging)
None, None, None, None, logging)
self.assertEqual(item['output']['uflow_data'],
overlay_to_underlay_mapper._get_underlay_flow_data(
item['input']['flow_record_data']))
Expand Down Expand Up @@ -683,7 +683,7 @@ def test_get_underlay_flow_data_raise_exception(self):
for query in queries:
overlay_to_underlay_mapper = \
OverlayToUnderlayMapper(query['overlay_to_underlay_map_query'],
None, None, logging)
None, None, None, None, logging)
self.assertRaises(_UnderlayToUFlowDataFieldsNameError,
overlay_to_underlay_mapper._get_underlay_flow_data,
query['flow_record_data'])
Expand All @@ -696,6 +696,8 @@ def test_send_query_no_error(self, mock_post_url_http):
'input': {
'analytics_api_ip': '10.10.10.1',
'analytics_api_port': 8081,
'username': 'admin',
'password': 'admin123',
'query': {
'table': FLOW_TABLE,
'start_time': 'now-10m', 'end_time': 'now-5m',
Expand All @@ -714,6 +716,8 @@ def test_send_query_no_error(self, mock_post_url_http):
'input': {
'analytics_api_ip': '192.168.10.1',
'analytics_api_port': 8090,
'username': 'admin',
'password': 'admin123',
'query': {
'table': 'StatTable.UFlowData.flow',
'start_time': 1416275005000000,
Expand Down Expand Up @@ -751,11 +755,14 @@ def test_send_query_no_error(self, mock_post_url_http):
for item in input_output_list:
overlay_to_underlay_mapper = \
OverlayToUnderlayMapper(None, item['input']['analytics_api_ip'],
item['input']['analytics_api_port'], logging)
item['input']['analytics_api_port'],
item['input']['username'], item['input']['password'],
logging)
self.assertEqual(overlay_to_underlay_mapper._send_query(
item['input']['query']), item['output']['response']['value'])
OpServerUtils.post_url_http.assert_called_with(
item['output']['query_url'], item['input']['query'], True)
item['output']['query_url'], item['input']['query'],
item['input']['username'], item['input']['password'], True)
# end test_send_query_no_error

@mock.patch('opserver.overlay_to_underlay_mapper.OpServerUtils.post_url_http')
Expand Down Expand Up @@ -810,7 +817,7 @@ def test_send_query_raise_exception(self, mock_post_url_http):
for item in queries:
overlay_to_underlay_mapper = \
OverlayToUnderlayMapper(None, item['analytics_api_ip'],
item['analytics_api_port'], logging)
item['analytics_api_port'], None, None, logging)
self.assertRaises(_QueryError,
overlay_to_underlay_mapper._send_query, item['query'])
# end test_send_query_raise_exception
Expand Down Expand Up @@ -888,7 +895,7 @@ def test_send_response_no_error(self):
overlay_to_underlay_mapper = \
OverlayToUnderlayMapper(
item['input']['overlay_to_underlay_map_query'],
None, None, logging)
None, None, None, None, logging)
self.assertEqual(item['output']['underlay_response'],
json.loads(overlay_to_underlay_mapper._send_response(
item['input']['uflow_data'])))
Expand All @@ -911,7 +918,7 @@ def test_send_response_raise_exception(self):
for item in input_list:
overlay_to_underlay_mapper = \
OverlayToUnderlayMapper(item['overlay_to_underlay_map_query'],
None, None, logging)
None, None, None, None, logging)
self.assertRaises(_UnderlayToUFlowDataFieldsNameError,
overlay_to_underlay_mapper._send_response, item['uflow_data'])
# end test_send_response_raise_exception
Expand Down Expand Up @@ -956,7 +963,7 @@ def test_process_query(self, mock_get_overlay_flow_data,
[json.dumps(item['response']) for item in test_data]
for item in test_data:
overlay_to_underlay_mapper = \
OverlayToUnderlayMapper(None, None, None, logging)
OverlayToUnderlayMapper(None, None, None, None, None, logging)
self.assertEqual(item['response'],
json.loads(overlay_to_underlay_mapper.process_query()))
overlay_to_underlay_mapper._get_overlay_flow_data.called_with()
Expand Down
14 changes: 12 additions & 2 deletions src/opserver/vnc_cfg_api_client.py
Expand Up @@ -66,8 +66,18 @@ def is_role_cloud_admin(self, user_token):
self._logger.error(
'Token info for %s NOT FOUND' % str(user_token))
return False
roles_list = [roles['name'] for roles in \
result['token_info']['access']['user']['roles']]
# Handle v2 and v3 responses
token_info = result['token_info']
if 'access' in token_info:
roles_list = [roles['name'] for roles in \
token_info['access']['user']['roles']]
elif 'token' in token_info:
roles_list = [roles['name'] for roles in \
token_info['token']['roles']]
else:
self._logger.error('Role info for %s NOT FOUND: %s' % \
(str(user_token), str(token_info)))
return False
return self._conf_info['cloud_admin_role'] in roles_list
# end is_role_cloud_admin

Expand Down
8 changes: 8 additions & 0 deletions src/sandesh/common/vns.sandesh
Expand Up @@ -508,3 +508,11 @@ const list<string> ThreadPoolNames = [
]

const string CLOUD_ADMIN_ROLE = "cloud-admin"

const string AAA_MODE_NO_AUTH = "no-auth"
const string AAA_MODE_CLOUD_ADMIN_ONLY = "cloud-admin-only"

const list <string> AnalyticsAPIAAAModes = [
AAA_MODE_NO_AUTH,
AAA_MODE_CLOUD_ADMIN_ONLY,
]

0 comments on commit a2a7c92

Please sign in to comment.