def test_get_plugins_installed_type_south(self, mocker): @asyncio.coroutine def mock_folders(): yield TestPluginDiscovery.mock_south_folders @asyncio.coroutine def mock_c_folders(): yield TestPluginDiscovery.mock_c_south_folders mock_get_folders = mocker.patch.object(PluginDiscovery, "get_plugin_folders", return_value=next( mock_folders())) mock_get_plugin_config = mocker.patch.object( PluginDiscovery, "get_plugin_config", side_effect=TestPluginDiscovery.mock_plugins_south_config) mock_get_c_folders = mocker.patch.object(utils, "find_c_plugin_libs", return_value=next( mock_c_folders())) mock_get_c_plugin_config = mocker.patch.object( utils, "get_plugin_info", side_effect=TestPluginDiscovery.mock_c_plugins_south_config) plugins = PluginDiscovery.get_plugins_installed("south") expected_plugin = TestPluginDiscovery.mock_plugins_south_config expected_plugin.extend(TestPluginDiscovery.mock_c_plugins_south_config) # FIXME: ordering issue # assert expected_plugin == plugins assert 1 == mock_get_folders.call_count assert 2 == mock_get_plugin_config.call_count assert 1 == mock_get_c_folders.call_count assert 1 == mock_get_c_plugin_config.call_count
def test_get_rules_plugins_installed(self, mocker): @asyncio.coroutine def mock_folders(): yield TestPluginDiscovery.mock_py_rule_folders @asyncio.coroutine def mock_c_folders(): yield TestPluginDiscovery.mock_c_rule_folders mock_get_py_folders = mocker.patch.object(PluginDiscovery, "get_plugin_folders", return_value=next( mock_folders())) mock_get_py_plugin_config = mocker.patch.object( PluginDiscovery, "get_plugin_config", side_effect=TestPluginDiscovery.mock_py_rule_config) mock_get_c_folders = mocker.patch.object(utils, "find_c_plugin_libs", return_value=next( mock_c_folders())) mock_get_c_plugin_config = mocker.patch.object( utils, "get_plugin_info", side_effect=TestPluginDiscovery.mock_c_rule_config) plugins = PluginDiscovery.get_plugins_installed("notificationRule") # expected_plugin = TestPluginDiscovery.mock_c_plugins_config[4] # FIXME: ordering issue # assert expected_plugin == plugins assert 1 == mock_get_py_folders.call_count assert 1 == mock_get_py_plugin_config.call_count assert 1 == mock_get_c_folders.call_count assert 1 == mock_get_c_plugin_config.call_count
async def update_plugin(request: web.Request) -> web.Response: """ update plugin :Example: curl -X PUT http://localhost:8081/fledge/plugins/south/sinusoid/update curl -X PUT http://localhost:8081/fledge/plugins/north/http_north/update """ _type = request.match_info.get('type', None) name = request.match_info.get('name', None) try: # TODO: FOGL-3063, FOGL-3064 _type = _type.lower() if _type not in ['north', 'south']: raise ValueError("Invalid plugin type. Must be 'north' or 'south'") # Check requested plugin name is installed or not installed_plugins = PluginDiscovery.get_plugins_installed(_type, False) installed_plugin_name = [ p_name["name"] for p_name in installed_plugins ] if name not in installed_plugin_name: raise KeyError( "{} plugin is not yet installed. So update is not possible.". format(name)) # Tracked plugins from asset tracker tracked_plugins = await _get_plugin_and_sch_name_from_asset_tracker( _type) sch_list = [] for p in tracked_plugins: if name == p['plugin']: sch_info = await _get_sch_id_and_enabled_by_name(p['service']) if sch_info[0]['enabled'] == 't': status, reason = await server.Server.scheduler.disable_schedule( uuid.UUID(sch_info[0]['id'])) if status: _logger.warning( "{} {} instance is disabled as {} plugin is updating.." .format(p['service'], _type, p['plugin'])) sch_list.append(sch_info[0]['id']) # Plugin update is running as a background task loop = request.loop request._type = _type request._name = name request._sch_list = sch_list loop.call_later(1, do_update, request) except KeyError as ex: raise web.HTTPNotFound(reason=ex) except ValueError as ex: raise web.HTTPBadRequest(reason=ex) except Exception as ex: raise web.HTTPInternalServerError(reason=ex) return web.json_response({ "message": "{} plugin update in process. Wait for few minutes to complete.". format(name) })
async def remove_plugin(request): """ Remove installed plugin from fledge type: installed plugin type name: installed plugin name Example: curl -X DELETE http://localhost:8081/fledge/plugins/south/sinusoid curl -X DELETE http://localhost:8081/fledge/plugins/north/http_north curl -X DELETE http://localhost:8081/fledge/plugins/filter/expression curl -X DELETE http://localhost:8081/fledge/plugins/notificationDelivery/alexa curl -X DELETE http://localhost:8081/fledge/plugins/notificationRule/Average """ plugin_type = request.match_info.get('type', None) name = request.match_info.get('name', None) try: plugin_type = str(plugin_type).lower() if not str(plugin_type).startswith('notification') else plugin_type if plugin_type not in valid_plugin_types: raise ValueError("Invalid plugin type. Please provide valid type: {}".format(valid_plugin_types)) installed_plugin = PluginDiscovery.get_plugins_installed(plugin_type, False) if name not in [plugin['name'] for plugin in installed_plugin]: raise KeyError("Invalid plugin name {} or plugin is not installed".format(name)) if plugin_type in ['notificationDelivery', 'notificationRule']: notification_instances_plugin_used_in = await check_plugin_usage_in_notification_instances(name) if notification_instances_plugin_used_in: raise RuntimeError("{} cannot be removed. This is being used by {} instances". format(name, notification_instances_plugin_used_in)) plugin_type = 'notify' if plugin_type == 'notificationDelivery' else 'rule' else: get_tracked_plugins = await check_plugin_usage(plugin_type, name) if get_tracked_plugins: e = "{} cannot be removed. This is being used by {} instances".\ format(name, get_tracked_plugins[0]['service_list']) _logger.error(e) raise RuntimeError(e) else: _logger.info("No entry found for {name} plugin in asset tracker; or " "{name} plugin may have been added in disabled state & never used".format(name=name)) res, log_path, is_package = purge_plugin(plugin_type, name) if res != 0: e_msg = "Something went wrong. Please check log {}".format(log_path) _logger.error(e_msg) raise RuntimeError(e_msg) else: if is_package: storage_client = connect.get_storage_async() audit_log = AuditLogger(storage_client) audit_detail = {'package_name': "fledge-{}-{}".format(plugin_type, name)} await audit_log.information('PKGRM', audit_detail) except (ValueError, RuntimeError) as ex: raise web.HTTPBadRequest(reason=str(ex)) except KeyError as ex: raise web.HTTPNotFound(reason=str(ex)) except PackageError as e: msg = "Failed to remove package for plugin {}".format(name) raise web.HTTPBadRequest(body=json.dumps({"message": msg, "link": str(e)}), reason=msg) else: _logger.info('{} plugin removed successfully'.format(name)) return web.json_response({'message': '{} plugin removed successfully'.format(name)}, status=200)
async def get_plugins_installed(request): """ get list of installed plugins :Example: curl -X GET http://localhost:8081/fledge/plugins/installed curl -X GET http://localhost:8081/fledge/plugins/installed?config=true curl -X GET http://localhost:8081/fledge/plugins/installed?type=north|south|filter|notificationDelivery|notificationRule curl -X 'GET http://localhost:8081/fledge/plugins/installed?type=north&config=true' """ plugin_type = None is_config = False if 'type' in request.query and request.query['type'] != '': plugin_type = request.query['type'].lower( ) if request.query['type'] not in [ 'notificationDelivery', 'notificationRule' ] else request.query['type'] if plugin_type is not None and plugin_type not in [ 'north', 'south', 'filter', 'notificationDelivery', 'notificationRule' ]: raise web.HTTPBadRequest( reason= "Invalid plugin type. Must be 'north' or 'south' or 'filter' or 'notificationDelivery' or 'notificationRule'." ) if 'config' in request.query: config = request.query['config'] if config not in ['true', 'false', True, False]: raise web.HTTPBadRequest(reason='Only "true", "false", true, false' ' are allowed for value of config.') is_config = True if ( (type(config) is str and config.lower() in ['true']) or ((type(config) is bool and config is True))) else False plugins_list = PluginDiscovery.get_plugins_installed( plugin_type, is_config) return web.json_response({"plugins": plugins_list})
async def update_plugin(request: web.Request) -> web.Response: """ update plugin :Example: curl -sX PUT http://localhost:8081/fledge/plugins/south/sinusoid/update curl -sX PUT http://localhost:8081/fledge/plugins/north/http_north/update curl -sX PUT http://localhost:8081/fledge/plugins/filter/metadata/update curl -sX PUT http://localhost:8081/fledge/plugins/notificationDelivery/asset/update curl -sX PUT http://localhost:8081/fledge/plugins/notificationRule/OutOfBound/update """ _type = request.match_info.get('type', None) name = request.match_info.get('name', None) try: _type = _type.lower( ) if not str(_type).startswith('notification') else _type if _type not in [ 'north', 'south', 'filter', 'notificationDelivery', 'notificationRule' ]: raise ValueError( "Invalid plugin type. Must be 'north', 'south', 'filter', 'notificationDelivery' " "or 'notificationRule'") # Check requested plugin name is installed or not installed_plugins = PluginDiscovery.get_plugins_installed(_type, False) installed_plugin_name = [ p_name["name"] for p_name in installed_plugins ] if name not in installed_plugin_name: raise KeyError( "{} plugin is not yet installed. So update is not possible.". format(name)) sch_list = [] notification_list = [] if _type in ['notificationDelivery', 'notificationRule']: # Check Notification service is enabled or not payload = PayloadBuilder().SELECT( "id", "enabled", "schedule_name").WHERE(['process_name', '=', 'notification_c']).payload() storage_client = connect.get_storage_async() result = await storage_client.query_tbl_with_payload( 'schedules', payload) sch_info = result['rows'] if sch_info and sch_info[0]['enabled'] == 't': # Find notification instances which are used by requested plugin name # If its config item 'enable' is true then update to false config_mgr = ConfigurationManager(storage_client) all_notifications = await config_mgr._read_all_child_category_names( "Notifications") for notification in all_notifications: notification_config = await config_mgr._read_category_val( notification['child']) notification_name = notification_config['name']['value'] channel = notification_config['channel']['value'] rule = notification_config['rule']['value'] is_enabled = True if notification_config['enable'][ 'value'] == 'true' else False if (channel == name and is_enabled) or (rule == name and is_enabled): _logger.warning( "Disabling {} notification instance, as {} {} plugin is updating..." .format(notification_name, name, _type)) await config_mgr.set_category_item_value_entry( notification_name, "enable", "false") notification_list.append(notification_name) _type = "notify" if _type == 'notificationDelivery' else "rule" else: # Tracked plugins from asset tracker tracked_plugins = await _get_plugin_and_sch_name_from_asset_tracker( _type) filters_used_by = [] if _type == 'filter': # In case of filter, for asset_tracker table we are inserting filter category_name in plugin column # instead of filter plugin name by Design # Hence below query is required to get actual plugin name from filters table storage_client = connect.get_storage_async() payload = PayloadBuilder().SELECT("name").WHERE( ['plugin', '=', name]).payload() result = await storage_client.query_tbl_with_payload( 'filters', payload) filters_used_by = [r['name'] for r in result['rows']] for p in tracked_plugins: if (name == p['plugin'] and not _type == 'filter') or ( p['plugin'] in filters_used_by and _type == 'filter'): sch_info = await _get_sch_id_and_enabled_by_name( p['service']) if sch_info[0]['enabled'] == 't': status, reason = await server.Server.scheduler.disable_schedule( uuid.UUID(sch_info[0]['id'])) if status: _logger.warning( "Disabling {} {} instance, as {} plugin is updating..." .format(p['service'], _type, name)) sch_list.append(sch_info[0]['id']) # Plugin update is running as a background task loop = request.loop request._type = _type request._name = name request._sch_list = sch_list request._notification_list = notification_list loop.call_later(1, do_update, request) except KeyError as ex: raise web.HTTPNotFound(reason=str(ex)) except ValueError as ex: raise web.HTTPBadRequest(reason=str(ex)) except Exception as ex: raise web.HTTPInternalServerError(reason=str(ex)) return web.json_response({ "message": "{} plugin update in process. Wait for few minutes to complete.". format(name) })
def _get_installed_plugins(): return PluginDiscovery.get_plugins_installed("south", False)