Exemplo n.º 1
0
    def cb_init(self, tctx):
        if self.maapi is None:
            self.maapi = Maapi()
        self.trans = self.maapi.attach(tctx)

        name = 'th-{0}'.format(tctx.th)
        wsock = take_worker_socket(self.daemon, name, self._make_key(tctx))
        try:
            init_cb = getattr(self, 'init', None)
            if callable(init_cb):
                init_cb(tctx)

            # Associate worker socket with the transaction
            trans_set_fd(tctx, wsock)

        except Exception as e:
            return_worker_socket(self.daemon, self._make_key(tctx))
            raise
Exemplo n.º 2
0
    def cb_action(self, uinfo, name, kp, input, output):

        def iterate(keypath, op, old_value, new_value):
            if op == ncs.MOP_DELETED and len(keypath) > 2 and kp_value(keypath[0]) == 'commit-queue':
                # /ncs:services/cq-notify-test:c-queue-test1/vrf{cust4}/plan/commit-queue
                self.log.info("Commit-queue completed for notifier {}, service instance {}.".format(
                    input.kicker_id,
                    kp_value(keypath[2])
                ))
                send_rest_notification(service=kp_value(keypath[2]), notifier=input.kicker_id)
                return ncs.ITER_STOP
            else:
                return ncs.ITER_RECURSE

        def send_rest_notification(**kwargs):
            # Retrieve configured REST parameters
            with ncs.maapi.single_read_trans(uinfo.username, "system") as read_t:
                rest_params = ncs.maagic.get_node(read_t, kp).rest
                uri = rest_params.uri
                source_data = rest_params.payload
                rest_user = rest_params.username
                read_t.maapi.install_crypto_keys()
                rest_pass = _ncs.decrypt(rest_params.password)

            # Process source_data through jinja2
            jinja_env = jinja2.Environment(autoescape=True, trim_blocks=True, lstrip_blocks=True)
            data = jinja_env.from_string(source_data).render(kwargs)

            # Send REST notification
            try:
                response = requests.post(url=uri, auth=(rest_user, rest_pass), data=data)
                response.raise_for_status()
                self.log.info("REST notification sent successfully: status code {}.".format(response.status_code))
            except requests.exceptions.RequestException as e:
                self.log.error("REST notification failed: {}".format(e))

        with Maapi() as m:
            try:
                t = m.attach(input.tid)
                t.diff_iterate(iterate, ncs.ITER_WANT_P_CONTAINER)
            finally:
                m.detach(input.tid)
Exemplo n.º 3
0
    def cb_action(self, uinfo, name, kp, input, output):

        def iterate(keypath, op, old_value, new_value):
            if op == ncs.MOP_CREATED and len(keypath) > 3 and str(keypath[0]) == 'request':
                # /loopback:external-resource-manager/id-pool{pool-1}/allocation{XR-0-1}/request
                allocation_id = kp_value(keypath[1])
                pool_name = kp_value(keypath[3])

                assigned_id = id_allocator.allocate(allocation_id, pool_name)
                if assigned_id is None:
                    self.log.error('Resource pool {} exhausted'.format(pool_name))
                else:
                    with ncs.maapi.single_write_trans(uinfo.username, "system", db=ncs.OPERATIONAL) as write_t:
                        ncs.maagic.get_node(write_t, keypath)._parent.response.assigned_id = assigned_id
                        write_t.apply()

                    self.log.info('Allocated: {}, {}, value: {}'.format(pool_name, allocation_id, assigned_id))

            elif op == ncs.MOP_DELETED and len(keypath) > 2 and str(keypath[1]) == 'allocation':
                # /loopback:external-resource-manager/id-pool{pool-1}/allocation{XR-0-1}
                allocation_id = kp_value(keypath[0])
                pool_name = kp_value(keypath[2])

                diff_size = id_allocator.deallocate(allocation_id, pool_name)
                self.log.info('De-allocated: {}, {}, {} changes'.format(pool_name, allocation_id, diff_size))

            else:
                return ncs.ITER_RECURSE

            return ncs.ITER_STOP

        self.log.info('Action input: kicker-id: {}, path: {}, tid: {}'.format(input.kicker_id, input.path, input.tid))
        id_allocator = FileAllocator(Config.ID_POOL)
        with Maapi() as m:
            try:
                t = m.attach(input.tid)
                t.diff_iterate(iterate, ncs.ITER_WANT_P_CONTAINER)
            finally:
                m.detach(input.tid)
Exemplo n.º 4
0
class Validation(object):
    """
    Convenience class for custom validation callbacks

    1) Create a custom validation class extending Validation
    Your custom validation class needs to implement the validate method. Optionally it can have init and stop
    methods, which get called at the beginning and end of the transaction validation phase.

    class CustomValidation(Validation):
        def validate(self, tctx, kp, newval, root):
            self.log.info('validate a called')
            return ncs.CONFD_OK

        def init(self, tctx):
            self.log.info('custom init a called')

        def stop(self, tctx):
            self.log.info('custom stop a called')

    2) Decorate your application class with custom_validators and register your custom validation class:
    The decorator allows calling self.register_validation within the setup method in a similar way as the builtin
    register_service and register_action methods.

    @Validation.custom_validators
    class Main(ncs.application.Application):
        def setup(self):
            ...
            self.register_validation('custom-validate-a', CustomValidation)
            ...
    """
    @staticmethod
    def custom_validators(cls):

        if not issubclass(cls, ncs.application.Application):
            raise TypeError(
                'custom_validators can only decorate ncs.application.Application subclasses'
            )

        original_init = cls.__init__
        original_setup = cls.setup
        original_teardown = cls.teardown

        def __init__(self, *args, **kwargs):
            original_init(self, *args, **kwargs)
            self._daemons = []

        def setup(self):
            r = original_setup(self)

            for daemon in self._daemons:
                daemon.start()

            return r

        def teardown(self):
            r = original_teardown(self)

            for daemon in self._daemons:
                daemon.finish()

            return r

        def register_validation(self, validation_point, validation_cls):
            daemon = Daemon('ncs-dp-{0}-{1}:{2}'.format(
                os.getpid(), self._ncs_pname, validation_point),
                            log=self.log)
            v = validation_cls(daemon, validation_point)
            register_trans_validate_cb(daemon.ctx(), v)
            register_valpoint_cb(daemon.ctx(), validation_point, v)
            self._daemons.append(daemon)

        cls.__init__ = __init__
        cls.setup = setup
        cls.teardown = teardown
        cls.register_validation = register_validation

        return cls

    def __init__(self, daemon, validation_point):
        self.validation_point = validation_point
        self.log = daemon.log
        self.maapi = None
        self.trans = None
        self.daemon = daemon

    def cb_init(self, tctx):
        if self.maapi is None:
            self.maapi = Maapi()
        self.trans = self.maapi.attach(tctx)

        name = 'th-{0}'.format(tctx.th)
        wsock = take_worker_socket(self.daemon, name, self._make_key(tctx))
        try:
            init_cb = getattr(self, 'init', None)
            if callable(init_cb):
                init_cb(tctx)

            # Associate worker socket with the transaction
            trans_set_fd(tctx, wsock)

        except Exception as e:
            return_worker_socket(self.daemon, self._make_key(tctx))
            raise

    def cb_stop(self, tctx):
        try:
            stop_cb = getattr(self, 'stop', None)
            if callable(stop_cb):
                stop_cb(tctx)

        finally:
            try:
                self.maapi.detach(tctx)
            except Exception as e:
                pass

            self.trans = None
            return_worker_socket(self.daemon, self._make_key(tctx))

    def cb_validate(self, tctx, kp, newval):
        validate_cb = getattr(self, 'validate', None)
        if callable(validate_cb):
            root = ncs.maagic.get_root(self.trans, shared=False)
            return validate_cb(tctx, kp, newval, root)

        raise NotImplementedError()

    def _make_key(self, tctx):
        return '{0}-{1}'.format(id(self), tctx.th)