diff --git a/src/api-lib/vnc_api.py b/src/api-lib/vnc_api.py index 8daca3bcbda..0db6f9f5911 100644 --- a/src/api-lib/vnc_api.py +++ b/src/api-lib/vnc_api.py @@ -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 diff --git a/src/opserver/analytics_db.py b/src/opserver/analytics_db.py index f7b437150cc..4863c676f9c 100644 --- a/src/opserver/analytics_db.py +++ b/src/opserver/analytics_db.py @@ -399,7 +399,7 @@ 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 @@ -407,12 +407,17 @@ def get_dbusage_info(self, rest_api_ip, rest_api_port): 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'] + diff --git a/src/opserver/opserver.py b/src/opserver/opserver.py index 3fe5c0b1d5f..1e646e2d875 100644 --- a/src/opserver/opserver.py +++ b/src/opserver/opserver.py @@ -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, \ @@ -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, @@ -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(): @@ -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", @@ -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(':') @@ -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: @@ -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)) diff --git a/src/opserver/overlay_to_underlay_mapper.py b/src/opserver/overlay_to_underlay_mapper.py index 1635935aee5..6ea982375b0 100644 --- a/src/opserver/overlay_to_underlay_mapper.py +++ b/src/opserver/overlay_to_underlay_mapper.py @@ -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'] @@ -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'] diff --git a/src/opserver/test/test_overlay_to_underlay_mapper.py b/src/opserver/test/test_overlay_to_underlay_mapper.py index 1594c2f3864..1edc11e96de 100755 --- a/src/opserver/test/test_overlay_to_underlay_mapper.py +++ b/src/opserver/test/test_overlay_to_underlay_mapper.py @@ -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 @@ -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 @@ -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'])) @@ -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']) @@ -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', @@ -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, @@ -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') @@ -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 @@ -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']))) @@ -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 @@ -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() diff --git a/src/opserver/vnc_cfg_api_client.py b/src/opserver/vnc_cfg_api_client.py index dd7ba51b16e..21cb1b8c3df 100644 --- a/src/opserver/vnc_cfg_api_client.py +++ b/src/opserver/vnc_cfg_api_client.py @@ -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 diff --git a/src/sandesh/common/vns.sandesh b/src/sandesh/common/vns.sandesh index c71c94f797e..0e4d3618184 100644 --- a/src/sandesh/common/vns.sandesh +++ b/src/sandesh/common/vns.sandesh @@ -508,3 +508,11 @@ const list 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 AnalyticsAPIAAAModes = [ + AAA_MODE_NO_AUTH, + AAA_MODE_CLOUD_ADMIN_ONLY, +]