Exemplo n.º 1
0
    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
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
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)
    })
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
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})
Exemplo n.º 6
0
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)
    })
Exemplo n.º 7
0
def _get_installed_plugins():
    return PluginDiscovery.get_plugins_installed("south", False)