def test_select_distinct_payload(self):
     expr = PayloadBuilder().\
         SELECT().DISTINCT(["description"])\
         .WHERE(["id", "<", 1000]).payload()
     assert _payload("data/payload_distinct.json") == json.loads(expr)
Beispiel #2
0
async def check_schedules(storage, schedule_name):
    payload = PayloadBuilder().SELECT("schedule_name").WHERE(
        ['schedule_name', '=', schedule_name]).payload()
    result = await storage.query_tbl_with_payload('schedules', payload)
    return result['count']
Beispiel #3
0
async def check_notification_schedule(storage):
    payload = PayloadBuilder().SELECT("process_name").payload()
    result = await storage.query_tbl_with_payload('schedules', payload)
    return result
Beispiel #4
0
async def delete_statistics_key(storage, key):
    payload = PayloadBuilder().WHERE(['key', '=', key]).payload()
    await storage.delete_from_tbl('statistics', payload)
Beispiel #5
0
async def add_configuration_item(request):
    """
    Args:
        request: A JSON object that defines the config item and has key-pair
                 (default, type, description, value[optional])

    Returns:
        Json response with message key

    :Example:
        curl -d '{"default": "true", "description": "Test description", "type": "boolean"}' -X POST https://localhost:1995/foglamp/category/{category_name}/{new_config_item} --insecure
        curl -d '{"default": "true", "description": "Test description", "type": "boolean", "value": "false"}' -X POST https://localhost:1995/foglamp/category/{category_name}/{new_config_item} --insecure
    """
    category_name = request.match_info.get('category_name', None)
    new_config_item = request.match_info.get('config_item', None)

    try:
        storage_client = connect.get_storage()
        cf_mgr = ConfigurationManager(storage_client)

        data = await request.json()
        if not isinstance(data, dict):
            raise ValueError('Data payload must be a dictionary')

        # if value key is in data then go ahead with data payload and validate
        # else update the data payload with value key and set its value to default value and validate
        val = data.get('value', None)
        if val is None:
            data.update({'value': data.get('default')})
            config_item_dict = {new_config_item: data}
        else:
            config_item_dict = {new_config_item: data}

        # validate configuration category value
        await cf_mgr._validate_category_val(
            category_val=config_item_dict,
            set_value_val_from_default_val=False)

        # validate category
        category = await cf_mgr.get_category_all_items(category_name)
        if category is None:
            raise NameError(
                "No such Category found for {}".format(category_name))

        # check if config item is already in use
        if new_config_item in category.keys():
            raise KeyError(
                "Config item is already in use for {}".format(category_name))

        # merge category values with keep_original_items True
        merge_cat_val = await cf_mgr._merge_category_vals(
            config_item_dict, category, keep_original_items=True)

        # update category value in storage
        payload = PayloadBuilder().SET(value=merge_cat_val).WHERE(
            ["key", "=", category_name]).payload()
        result = storage_client.update_tbl("configuration", payload)
        response = result['response']

        # logged audit new config item for category
        audit = AuditLogger(storage_client)
        audit_details = {
            'category': category_name,
            'item': new_config_item,
            'value': config_item_dict
        }
        await audit.information('CONAD', audit_details)

    except (KeyError, ValueError, TypeError) as ex:
        raise web.HTTPBadRequest(reason=str(ex))
    except NameError as ex:
        raise web.HTTPNotFound(reason=str(ex))
    except Exception as ex:
        raise web.HTTPException(reason=str(ex))

    return web.json_response({
        "message":
        "{} config item has been saved for {} category".format(
            new_config_item, category_name)
    })
 def test_select_payload_with_alias_and_format(self, test_input, expected):
     res = PayloadBuilder().SELECT(test_input).ALIAS('return', ('user_ts', 'timestamp')).\
         FORMAT('return', ('user_ts', "YYYY-MM-DD HH24:MI:SS.MS")).payload()
     assert expected == json.loads(res)
 def test_from_payload(self, test_input, expected):
     res = PayloadBuilder().FROM(test_input).payload()
     assert expected == json.loads(res)
 def test_having_payload(self, expected):
     res = PayloadBuilder().HAVING().payload()
     assert expected == json.loads(res)
 def test_select_payload(self, test_input, expected):
     res = PayloadBuilder().SELECT(test_input).payload()
     assert expected == json.loads(res)
Beispiel #10
0
 def test_and_query_params_payload(self, test_input1, test_input2,
                                   expected):
     res = PayloadBuilder().WHERE(test_input1).AND_WHERE(
         test_input2).query_params()
     assert expected == res
Beispiel #11
0
 def test_or_query_params_payload(self, test_input1, test_input2, expected):
     """Since URL does not support OR hence only 1 value should be parsed as query parameter"""
     res = PayloadBuilder().WHERE(test_input1).OR_WHERE(
         test_input2).query_params()
     assert expected == res
Beispiel #12
0
 def test_query_params_payload(self):
     res = PayloadBuilder().WHERE(["key", "=", "value1"]).query_params()
     assert "key=value1" == res
Beispiel #13
0
 def test_limit_skip_payload(self, test_input, expected):
     res = PayloadBuilder().LIMIT(test_input).SKIP(test_input).payload()
     assert expected == json.loads(res)
Beispiel #14
0
 def test_limit_offset_payload(self, test_input, expected):
     res = PayloadBuilder().LIMIT(test_input).OFFSET(test_input).payload()
     assert expected == json.loads(res)
Beispiel #15
0
 def test_delete_payload(self, test_input, expected):
     res = PayloadBuilder().DELETE(test_input).payload()
     assert expected == json.loads(res)
Beispiel #16
0
 def test_json_properties3(self, test_input1, test_input2, expected):
     res = PayloadBuilder().JSON_PROPERTY(test_input1).JSON_PROPERTY(
         test_input2).payload()
     assert expected == json.loads(res)
Beispiel #17
0
 def test_delete_where_payload(self, input_where, input_table, expected):
     res = PayloadBuilder().DELETE(input_table).WHERE(input_where).payload()
     assert expected == json.loads(res)
Beispiel #18
0
 def test_aggregate_with_where(self):
     res = PayloadBuilder().WHERE(["ts", "newer",
                                   60]).AGGREGATE(["count", "*"]).payload()
     assert _payload("data/payload_aggregate_where.json") == json.loads(res)
Beispiel #19
0
 def test_select_payload_with_alias3(self, test_input, expected):
     res = PayloadBuilder().SELECT(test_input).ALIAS(
         'return', ('name', 'my_name'), ('id', 'my_id')).payload()
     assert expected == json.loads(res)
Beispiel #20
0
 def test_insert_payload(self):
     res = PayloadBuilder().INSERT(key="x").payload()
     assert _payload("data/payload_insert1.json") == json.loads(res)
Beispiel #21
0
async def add_task(request):
    """ Create a new task to run a specific plugin

    :Example:
     curl -X POST http://localhost:8081/foglamp/scheduled/task -d
     '{
        "name": "North Readings to PI",
        "plugin": "pi_server",
        "type": "north",
        "schedule_type": 3,
        "schedule_day": 0,
        "schedule_time": 0,
        "schedule_repeat": 30,
        "schedule_enabled": true
     }'

     curl -sX POST http://localhost:8081/foglamp/scheduled/task -d
     '{"name": "PI-2",
     "plugin": "pi_server",
     "type": "north",
     "schedule_type": 3,
     "schedule_day": 0,
     "schedule_time": 0,
     "schedule_repeat": 30,
     "schedule_enabled": true,
     "config": {
        "producerToken": {"value": "uid=180905062754237&sig=kx5l+"},
        "URL": {"value": "https://10.2.5.22:5460/ingress/messages"}}}'
    """

    try:
        data = await request.json()
        if not isinstance(data, dict):
            raise ValueError('Data payload must be a valid JSON')

        name = data.get('name', None)
        plugin = data.get('plugin', None)
        task_type = data.get('type', None)

        schedule_type = data.get('schedule_type', None)
        schedule_day = data.get('schedule_day', None)
        schedule_time = data.get('schedule_time', None)
        schedule_repeat = data.get('schedule_repeat', None)
        enabled = data.get('schedule_enabled', None)
        config = data.get('config', None)

        if name is None:
            raise web.HTTPBadRequest(
                reason='Missing name property in payload.')
        if plugin is None:
            raise web.HTTPBadRequest(
                reason='Missing plugin property in payload.')
        if task_type is None:
            raise web.HTTPBadRequest(
                reason='Missing type property in payload.')
        if utils.check_reserved(name) is False:
            raise web.HTTPBadRequest(
                reason='Invalid name property in payload.')
        if utils.check_foglamp_reserved(name) is False:
            raise web.HTTPBadRequest(
                reason=
                "'{}' is reserved for FogLAMP and can not be used as task name!"
                .format(name))
        if utils.check_reserved(plugin) is False:
            raise web.HTTPBadRequest(
                reason='Invalid plugin property in payload.')
        if task_type not in ['north']:
            raise web.HTTPBadRequest(reason='Only north type is supported.')

        if schedule_type is None:
            raise web.HTTPBadRequest(reason='schedule_type is mandatory')
        if not isinstance(schedule_type, int) and not schedule_type.isdigit():
            raise web.HTTPBadRequest(
                reason='Error in schedule_type: {}'.format(schedule_type))
        if int(schedule_type) not in list(Schedule.Type):
            raise web.HTTPBadRequest(
                reason='schedule_type error: {}'.format(schedule_type))
        if int(schedule_type) == Schedule.Type.STARTUP:
            raise web.HTTPBadRequest(
                reason='schedule_type cannot be STARTUP: {}'.format(
                    schedule_type))

        schedule_type = int(schedule_type)

        if schedule_day is not None:
            if isinstance(schedule_day, float) or (
                    isinstance(schedule_day, str) and
                (schedule_day.strip() != "" and not schedule_day.isdigit())):
                raise web.HTTPBadRequest(
                    reason='Error in schedule_day: {}'.format(schedule_day))
        else:
            schedule_day = int(
                schedule_day) if schedule_day is not None else None

        if schedule_time is not None and (not isinstance(schedule_time, int)
                                          and not schedule_time.isdigit()):
            raise web.HTTPBadRequest(
                reason='Error in schedule_time: {}'.format(schedule_time))
        else:
            schedule_time = int(
                schedule_time) if schedule_time is not None else None

        if schedule_repeat is not None and (not isinstance(
                schedule_repeat, int) and not schedule_repeat.isdigit()):
            raise web.HTTPBadRequest(
                reason='Error in schedule_repeat: {}'.format(schedule_repeat))
        else:
            schedule_repeat = int(
                schedule_repeat) if schedule_repeat is not None else None

        if schedule_type == Schedule.Type.TIMED:
            if not schedule_time:
                raise web.HTTPBadRequest(
                    reason=
                    'schedule_time cannot be empty/None for TIMED schedule.')
            if schedule_day is not None and (schedule_day < 1
                                             or schedule_day > 7):
                raise web.HTTPBadRequest(
                    reason=
                    'schedule_day {} must either be None or must be an integer, 1(Monday) '
                    'to 7(Sunday).'.format(schedule_day))
            if schedule_time < 0 or schedule_time > 86399:
                raise web.HTTPBadRequest(
                    reason=
                    'schedule_time {} must be an integer and in range 0-86399.'
                    .format(schedule_time))

        if schedule_type == Schedule.Type.INTERVAL:
            if schedule_repeat is None:
                raise web.HTTPBadRequest(
                    reason=
                    'schedule_repeat {} is required for INTERVAL schedule_type.'
                    .format(schedule_repeat))
            elif not isinstance(schedule_repeat, int):
                raise web.HTTPBadRequest(
                    reason='schedule_repeat {} must be an integer.'.format(
                        schedule_repeat))

        if enabled is not None:
            if enabled not in ['true', 'false', True, False]:
                raise web.HTTPBadRequest(
                    reason=
                    'Only "true", "false", true, false are allowed for value of enabled.'
                )
        is_enabled = True if (
            (type(enabled) is str and enabled.lower() in ['true']) or
            ((type(enabled) is bool and enabled is True))) else False

        # Check if a valid plugin has been provided
        try:
            # "plugin_module_path" is fixed by design. It is MANDATORY to keep the plugin in the exactly similar named
            # folder, within the plugin_module_path.
            # if multiple plugin with same name are found, then python plugin import will be tried first
            plugin_module_path = "{}/python/foglamp/plugins/{}/{}".format(
                _FOGLAMP_ROOT, task_type, plugin)
            plugin_info = common.load_and_fetch_python_plugin_info(
                plugin_module_path, plugin, task_type)
            plugin_config = plugin_info['config']
            script = '["tasks/north"]'
            process_name = 'north'
        except FileNotFoundError as ex:
            # Checking for C-type plugins
            script = '["tasks/north_c"]'
            plugin_info = apiutils.get_plugin_info(plugin, dir=task_type)
            if plugin_info['type'] != task_type:
                msg = "Plugin of {} type is not supported".format(
                    plugin_info['type'])
                _logger.exception(msg)
                return web.HTTPBadRequest(reason=msg)
            plugin_config = plugin_info['config']
            process_name = 'north_c'
            if not plugin_config:
                _logger.exception("Plugin %s import problem from path %s. %s",
                                  plugin, plugin_module_path, str(ex))
                raise web.HTTPNotFound(
                    reason='Plugin "{}" import problem from path "{}"'.format(
                        plugin, plugin_module_path))
        except TypeError as ex:
            raise web.HTTPBadRequest(reason=str(ex))
        except Exception as ex:
            _logger.exception("Failed to fetch plugin configuration. %s",
                              str(ex))
            raise web.HTTPInternalServerError(
                reason='Failed to fetch plugin configuration.')

        storage = connect.get_storage_async()
        config_mgr = ConfigurationManager(storage)

        # Abort the operation if there are already executed tasks
        payload = PayloadBuilder() \
            .SELECT(["id", "schedule_name"]) \
            .WHERE(['schedule_name', '=', name]) \
            .LIMIT(1) \
            .payload()

        result = await storage.query_tbl_with_payload('tasks', payload)

        if result['count'] >= 1:
            msg = 'Unable to reuse name {0}, already used by a previous task.'.format(
                name)
            _logger.exception(msg)
            raise web.HTTPBadRequest(reason=msg)

        # Check whether category name already exists
        category_info = await config_mgr.get_category_all_items(
            category_name=name)
        if category_info is not None:
            raise web.HTTPBadRequest(
                reason="The '{}' category already exists".format(name))

        # Check that the schedule name is not already registered
        count = await check_schedules(storage, name)
        if count != 0:
            raise web.HTTPBadRequest(
                reason='A north instance with this name already exists')

        # Check that the process name is not already registered
        count = await check_scheduled_processes(storage, process_name)
        if count == 0:  # Create the scheduled process entry for the new task
            payload = PayloadBuilder().INSERT(name=process_name,
                                              script=script).payload()
            try:
                res = await storage.insert_into_tbl("scheduled_processes",
                                                    payload)
            except StorageServerError as ex:
                _logger.exception("Failed to create scheduled process. %s",
                                  ex.error)
                raise web.HTTPInternalServerError(
                    reason='Failed to create north instance.')
            except Exception as ex:
                _logger.exception("Failed to create scheduled process. %s", ex)
                raise web.HTTPInternalServerError(
                    reason='Failed to create north instance.')

        # If successful then create a configuration entry from plugin configuration
        try:
            # Create a configuration category from the configuration defined in the plugin
            category_desc = plugin_config['plugin']['description']
            await config_mgr.create_category(
                category_name=name,
                category_description=category_desc,
                category_value=plugin_config,
                keep_original_items=True)
            # Create the parent category for all North tasks
            await config_mgr.create_category("North", {}, 'North tasks', True)
            await config_mgr.create_child_category("North", [name])

            # If config is in POST data, then update the value for each config item
            if config is not None:
                if not isinstance(config, dict):
                    raise ValueError('Config must be a JSON object')
                for k, v in config.items():
                    await config_mgr.set_category_item_value_entry(
                        name, k, v['value'])
        except Exception as ex:
            await config_mgr.delete_category_and_children_recursively(name)
            _logger.exception("Failed to create plugin configuration. %s",
                              str(ex))
            raise web.HTTPInternalServerError(
                reason='Failed to create plugin configuration.')

        # If all successful then lastly add a schedule to run the new task at startup
        try:
            schedule = TimedSchedule() if schedule_type == Schedule.Type.TIMED else \
                       IntervalSchedule() if schedule_type == Schedule.Type.INTERVAL else \
                       ManualSchedule()
            schedule.name = name
            schedule.process_name = process_name
            schedule.day = schedule_day
            m, s = divmod(schedule_time if schedule_time is not None else 0,
                          60)
            h, m = divmod(m, 60)
            schedule.time = datetime.time().replace(hour=h, minute=m, second=s)
            schedule.repeat = datetime.timedelta(
                seconds=schedule_repeat if schedule_repeat is not None else 0)
            schedule.exclusive = True
            schedule.enabled = False  # if "enabled" is supplied, it gets activated in save_schedule() via is_enabled flag

            # Save schedule
            await server.Server.scheduler.save_schedule(schedule, is_enabled)
            schedule = await server.Server.scheduler.get_schedule_by_name(name)
        except StorageServerError as ex:
            await config_mgr.delete_category_and_children_recursively(name)
            _logger.exception("Failed to create schedule. %s", ex.error)
            raise web.HTTPInternalServerError(
                reason='Failed to create north instance.')
        except Exception as ex:
            await config_mgr.delete_category_and_children_recursively(name)
            _logger.exception("Failed to create schedule. %s", str(ex))
            raise web.HTTPInternalServerError(
                reason='Failed to create north instance.')

    except ValueError as e:
        raise web.HTTPBadRequest(reason=str(e))
    else:
        return web.json_response({
            'name': name,
            'id': str(schedule.schedule_id)
        })
Beispiel #22
0
 def test_insert_into_payload(self):
     res = PayloadBuilder().INSERT_INTO("test").payload()
     assert _payload("data/payload_from1.json") == json.loads(res)
Beispiel #23
0
async def get_audit_entries(request):
    """ Returns a list of audit trail entries sorted with most recent first and total count
        (including the criteria search if applied)

    :Example:

        curl -X GET http://localhost:8081/foglamp/audit

        curl -X GET http://localhost:8081/foglamp/audit?limit=5

        curl -X GET http://localhost:8081/foglamp/audit?limit=5&skip=3

        curl -X GET http://localhost:8081/foglamp/audit?skip=2

        curl -X GET http://localhost:8081/foglamp/audit?source=PURGE

        curl -X GET http://localhost:8081/foglamp/audit?severity=ERROR

        curl -X GET http://localhost:8081/foglamp/audit?source=LOGGN&severity=INFORMATION&limit=10
    """
    try:
        limit = request.query.get(
            'limit') if 'limit' in request.query else __DEFAULT_LIMIT
        offset = request.query.get(
            'skip') if 'skip' in request.query else __DEFAULT_OFFSET
        source = request.query.get(
            'source') if 'source' in request.query else None
        severity = request.query.get(
            'severity') if 'severity' in request.query else None

        # HACK: This way when we can more future we do not get an exponential
        # explosion of if statements
        payload = PayloadBuilder().WHERE(['1', '=', '1'])
        if source is not None and source != "":
            payload.AND_WHERE(['code', '=', source])

        if severity is not None and severity != "":
            payload.AND_WHERE(['level', '=', Severity[severity].value])

        _and_where_payload = payload.chain_payload()
        # SELECT *, count(*) OVER() FROM log - No support yet from storage layer
        # TODO: FOGL-740, FOGL-663 once ^^ resolved we should replace below storage call for getting total rows
        # TODO: FOGL-643 - Aggregate with alias support needed to use payload builder
        aggregate = {"operation": "count", "column": "*", "alias": "count"}
        d = OrderedDict()
        d['aggregate'] = aggregate
        d.update(_and_where_payload)
        total_count_payload = json.dumps(d)

        # SELECT count (*) FROM log <_and_where_payload>
        storage_client = connect.get_storage()
        result = storage_client.query_tbl_with_payload('log',
                                                       total_count_payload)
        total_count = result['rows'][0]['count']

        payload.ORDER_BY(['ts', 'desc'])
        payload.LIMIT(int(limit))

        if offset != '' and int(offset) > 0:
            payload.OFFSET(int(offset))

        # SELECT * FROM log <payload.payload()>
        results = storage_client.query_tbl_with_payload(
            'log', payload.payload())
        res = []
        for row in results['rows']:
            r = dict()
            r["details"] = row["log"]
            severity_level = int(row["level"])
            r["severity"] = Severity(
                severity_level).name if severity_level in range(
                    1, 5) else "UNKNOWN"
            r["source"] = row["code"]
            r["timestamp"] = row["ts"]

            res.append(r)

        return web.json_response({'audit': res, 'totalCount': total_count})

    except ValueError as ex:
        raise web.HTTPNotFound(reason=str(ex))
Beispiel #24
0
 def test_update_table_payload(self, test_input, expected):
     res = PayloadBuilder().UPDATE_TABLE(test_input).payload()
     assert expected == json.loads(res)
Beispiel #25
0
async def add_service(request):
    """
    Create a new service to run a specific plugin

    :Example:
             curl -X POST http://localhost:8081/foglamp/service -d '{"name": "DHT 11", "plugin": "dht11", "type": "south", "enabled": true}'
             curl -sX POST http://localhost:8081/foglamp/service -d '{"name": "Sine", "plugin": "sinusoid", "type": "south", "enabled": true, "config": {"dataPointsPerSec": {"value": "10"}}}' | jq
             curl -X POST http://localhost:8081/foglamp/service -d '{"name": "NotificationServer", "type": "notification", "enabled": true}' | jq

             curl -sX POST http://localhost:8081/foglamp/service?action=install -d '{"format":"repository", "name": "foglamp-service-notification"}'
             curl -sX POST http://localhost:8081/foglamp/service?action=install -d '{"format":"repository", "name": "foglamp-service-notification", "version":"1.6.0"}'
    """

    try:
        data = await request.json()
        if not isinstance(data, dict):
            raise ValueError('Data payload must be a valid JSON')

        name = data.get('name', None)
        plugin = data.get('plugin', None)
        service_type = data.get('type', None)
        enabled = data.get('enabled', None)
        config = data.get('config', None)

        if name is None:
            raise web.HTTPBadRequest(
                reason='Missing name property in payload.')
        if 'action' in request.query and request.query['action'] != '':
            if request.query['action'] == 'install':
                file_format = data.get('format', None)
                if file_format is None:
                    raise ValueError("format param is required")
                if file_format not in ["repository"]:
                    raise ValueError("Invalid format. Must be 'repository'")
                version = data.get('version', None)
                if version:
                    delimiter = '.'
                    if str(version).count(delimiter) != 2:
                        raise ValueError(
                            'Service semantic version is incorrect; it should be like X.Y.Z'
                        )

                services, log_path = common.fetch_available_packages("service")
                if name not in services:
                    raise KeyError(
                        '{} service is not available for the given repository or already installed'
                        .format(name))

                _platform = platform.platform()
                pkg_mgt = 'yum' if 'centos' in _platform or 'redhat' in _platform else 'apt'
                code, msg = await install.install_package_from_repo(
                    name, pkg_mgt, version)
                if code != 0:
                    raise ValueError(msg)

                message = "{} is successfully installed".format(name)
                return web.json_response({'message': message})
            else:
                raise web.HTTPBadRequest(reason='{} is not a valid action'.
                                         format(request.query['action']))
        if utils.check_reserved(name) is False:
            raise web.HTTPBadRequest(
                reason='Invalid name property in payload.')
        if utils.check_foglamp_reserved(name) is False:
            raise web.HTTPBadRequest(
                reason=
                "'{}' is reserved for FogLAMP and can not be used as service name!"
                .format(name))
        if service_type is None:
            raise web.HTTPBadRequest(
                reason='Missing type property in payload.')

        service_type = str(service_type).lower()
        if service_type == 'north':
            raise web.HTTPNotAcceptable(
                reason='north type is not supported for the time being.')
        if service_type not in ['south', 'notification']:
            raise web.HTTPBadRequest(
                reason='Only south and notification type are supported.')
        if plugin is None and service_type == 'south':
            raise web.HTTPBadRequest(
                reason='Missing plugin property for type south in payload.')
        if plugin and utils.check_reserved(plugin) is False:
            raise web.HTTPBadRequest(
                reason='Invalid plugin property in payload.')

        if enabled is not None:
            if enabled not in ['true', 'false', True, False]:
                raise web.HTTPBadRequest(
                    reason='Only "true", "false", true, false'
                    ' are allowed for value of enabled.')
        is_enabled = True if (
            (type(enabled) is str and enabled.lower() in ['true']) or
            ((type(enabled) is bool and enabled is True))) else False

        # Check if a valid plugin has been provided
        plugin_module_path, plugin_config, process_name, script = "", {}, "", ""
        if service_type == 'south':
            # "plugin_module_path" is fixed by design. It is MANDATORY to keep the plugin in the exactly similar named
            # folder, within the plugin_module_path.
            # if multiple plugin with same name are found, then python plugin import will be tried first
            plugin_module_path = "{}/python/foglamp/plugins/{}/{}".format(
                _FOGLAMP_ROOT, service_type, plugin)
            try:
                plugin_info = common.load_and_fetch_python_plugin_info(
                    plugin_module_path, plugin, service_type)
                plugin_config = plugin_info['config']
                if not plugin_config:
                    _logger.exception("Plugin %s import problem from path %s",
                                      plugin, plugin_module_path)
                    raise web.HTTPNotFound(
                        reason='Plugin "{}" import problem from path "{}".'.
                        format(plugin, plugin_module_path))
                process_name = 'south_c'
                script = '["services/south_c"]'
            except FileNotFoundError as ex:
                # Checking for C-type plugins
                plugin_config = load_c_plugin(plugin, service_type)
                if not plugin_config:
                    _logger.exception(
                        "Plugin %s import problem from path %s. %s", plugin,
                        plugin_module_path, str(ex))
                    raise web.HTTPNotFound(
                        reason='Plugin "{}" import problem from path "{}".'.
                        format(plugin, plugin_module_path))

                process_name = 'south_c'
                script = '["services/south_c"]'
            except TypeError as ex:
                _logger.exception(str(ex))
                raise web.HTTPBadRequest(reason=str(ex))
            except Exception as ex:
                _logger.exception("Failed to fetch plugin configuration. %s",
                                  str(ex))
                raise web.HTTPInternalServerError(
                    reason='Failed to fetch plugin configuration')
        elif service_type == 'notification':
            process_name = 'notification_c'
            script = '["services/notification_c"]'

        storage = connect.get_storage_async()
        config_mgr = ConfigurationManager(storage)

        # Check  whether category name already exists
        category_info = await config_mgr.get_category_all_items(
            category_name=name)
        if category_info is not None:
            raise web.HTTPBadRequest(
                reason="The '{}' category already exists".format(name))

        # Check that the schedule name is not already registered
        count = await check_schedules(storage, name)
        if count != 0:
            raise web.HTTPBadRequest(
                reason='A service with this name already exists.')

        # Check that the process name is not already registered
        count = await check_scheduled_processes(storage, process_name)
        if count == 0:
            # Now first create the scheduled process entry for the new service
            payload = PayloadBuilder().INSERT(name=process_name,
                                              script=script).payload()
            try:
                res = await storage.insert_into_tbl("scheduled_processes",
                                                    payload)
            except StorageServerError as ex:
                _logger.exception("Failed to create scheduled process. %s",
                                  ex.error)
                raise web.HTTPInternalServerError(
                    reason='Failed to create service.')
            except Exception as ex:
                _logger.exception("Failed to create scheduled process. %s",
                                  str(ex))
                raise web.HTTPInternalServerError(
                    reason='Failed to create service.')

        # check that notification service is not already registered, right now notification service LIMIT to 1
        if service_type == 'notification':
            res = await check_notification_schedule(storage)
            for ps in res['rows']:
                if 'notification_c' in ps['process_name']:
                    raise web.HTTPBadRequest(
                        reason='A Notification service schedule already exists.'
                    )
        elif service_type == 'south':
            try:
                # Create a configuration category from the configuration defined in the plugin
                category_desc = plugin_config['plugin']['description']
                await config_mgr.create_category(
                    category_name=name,
                    category_description=category_desc,
                    category_value=plugin_config,
                    keep_original_items=True)
                # Create the parent category for all South services
                await config_mgr.create_category("South", {},
                                                 "South microservices", True)
                await config_mgr.create_child_category("South", [name])

                # If config is in POST data, then update the value for each config item
                if config is not None:
                    if not isinstance(config, dict):
                        raise ValueError('Config must be a JSON object')
                    for k, v in config.items():
                        await config_mgr.set_category_item_value_entry(
                            name, k, v['value'])

            except Exception as ex:
                await config_mgr.delete_category_and_children_recursively(name)
                _logger.exception("Failed to create plugin configuration. %s",
                                  str(ex))
                raise web.HTTPInternalServerError(
                    reason='Failed to create plugin configuration.')

        # If all successful then lastly add a schedule to run the new service at startup
        try:
            schedule = StartUpSchedule()
            schedule.name = name
            schedule.process_name = process_name
            schedule.repeat = datetime.timedelta(0)
            schedule.exclusive = True
            #  if "enabled" is supplied, it gets activated in save_schedule() via is_enabled flag
            schedule.enabled = False

            # Save schedule
            await server.Server.scheduler.save_schedule(schedule, is_enabled)
            schedule = await server.Server.scheduler.get_schedule_by_name(name)
        except StorageServerError as ex:
            await config_mgr.delete_category_and_children_recursively(name)
            _logger.exception("Failed to create schedule. %s", ex.error)
            raise web.HTTPInternalServerError(
                reason='Failed to create service.')
        except Exception as ex:
            await config_mgr.delete_category_and_children_recursively(name)
            _logger.exception("Failed to create service. %s", str(ex))
            raise web.HTTPInternalServerError(
                reason='Failed to create service.')

    except ValueError as e:
        raise web.HTTPBadRequest(reason=str(e))
    except KeyError as ex:
        raise web.HTTPNotFound(reason=str(ex))
    else:
        return web.json_response({
            'name': name,
            'id': str(schedule.schedule_id)
        })
Beispiel #26
0
 def test_set_payload(self, test_input, expected):
     res = PayloadBuilder().SET(value=test_input).payload()
     assert expected == json.loads(res)
Beispiel #27
0
async def get_schedule(storage, schedule_name):
    payload = PayloadBuilder().SELECT(["id", "enabled"]).WHERE(
        ['schedule_name', '=', schedule_name]).payload()
    result = await storage.query_tbl_with_payload('schedules', payload)
    return result
Beispiel #28
0
 def test_update_set_where_payload(self, input_set, input_where,
                                   input_table, expected):
     res = PayloadBuilder().SET(value=input_set).WHERE(
         input_where).UPDATE_TABLE(input_table).payload()
     assert expected == json.loads(res)
 def test_conditions_payload(self, test_input, expected):
     res = PayloadBuilder().WHERE(test_input).payload()
     assert expected == json.loads(res)
Beispiel #30
0
 def test_select_all_payload(self):
     res = PayloadBuilder().SELECT().payload()
     expected = {}
     assert expected == json.loads(res)