Example #1
0
    def test_forward(self):
        """
        Test the `ipalib.rpc.xmlclient.forward` method.
        """
        class user_add(Command):
            pass

        o, _api, _home = self.instance('Backend', user_add, in_server=False)
        args = (binary_bytes, utf8_bytes, unicode_str)
        kw = dict(one=binary_bytes, two=utf8_bytes, three=unicode_str)
        params = [args, kw]
        result = (unicode_str, binary_bytes, utf8_bytes)
        conn = DummyClass(
            (
                'user_add',
                rpc.xml_wrap(params, API_VERSION),
                {},
                rpc.xml_wrap(result, API_VERSION),
            ),
            (
                'user_add',
                rpc.xml_wrap(params, API_VERSION),
                {},
                Fault(3007, u"'four' is required"),  # RequirementError
            ),
            (
                'user_add',
                rpc.xml_wrap(params, API_VERSION),
                {},
                Fault(700, u'no such error'),  # There is no error 700
            ),

        )

        # Create connection for the current thread
        setattr(context, o.id, Connection(conn, lambda: None))
        context.xmlclient = Connection(conn, lambda: None)

        # Test with a successful return value:
        assert o.forward('user_add', *args, **kw) == result

        # Test with an errno the client knows:
        e = raises(errors.RequirementError, o.forward, 'user_add', *args, **kw)
        assert_equal(e.args[0], u"'four' is required")

        # Test with an errno the client doesn't know
        e = raises(errors.UnknownError, o.forward, 'user_add', *args, **kw)
        assert_equal(e.code, 700)
        assert_equal(e.error, u'no such error')

        assert context.xmlclient.conn._calledall() is True
Example #2
0
    def forward(self, name, *args, **kw):
        """
        Forward call to command named ``name`` over XML-RPC.

        This method will encode and forward an XML-RPC request, and will then
        decode and return the corresponding XML-RPC response.

        :param command: The name of the command being forwarded.
        :param args: Positional arguments to pass to remote command.
        :param kw: Keyword arguments to pass to remote command.
        """
        server = getattr(context, 'request_url', None)
        self.log.info("Forwarding '%s' to %s server '%s'", name, self.protocol,
                      server)
        command = getattr(self.conn, name)
        params = [args, kw]
        try:
            return self._call_command(command, params)
        except Fault as e:
            e = decode_fault(e)
            self.debug('Caught fault %d from server %s: %s', e.faultCode,
                       server, e.faultString)
            if e.faultCode in errors_by_code:
                error = errors_by_code[e.faultCode]
                raise error(message=e.faultString)
            raise UnknownError(
                code=e.faultCode,
                error=e.faultString,
                server=server,
            )
        except SSLError as e:
            raise NetworkError(uri=server, error=str(e))
        except ProtocolError as e:
            # By catching a 401 here we can detect the case where we have
            # a single IPA server and the session is invalid. Otherwise
            # we always have to do a ping().
            session_cookie = getattr(context, 'session_cookie', None)
            if session_cookie and e.errcode == 401:
                # Unauthorized. Remove the session and try again.
                delattr(context, 'session_cookie')
                try:
                    principal = getattr(context, 'principal', None)
                    delete_persistent_client_session_data(principal)
                except Exception as e:
                    # This shouldn't happen if we have a session but it isn't fatal.
                    pass

                # Create a new serverproxy with the non-session URI
                serverproxy = self.create_connection(
                    os.environ.get('KRB5CCNAME'), self.env.verbose,
                    self.env.fallback, self.env.delegate)
                setattr(context, self.id,
                        Connection(serverproxy, self.disconnect))
                return self.forward(name, *args, **kw)
            raise NetworkError(uri=server, error=e.errmsg)
        except socket.error as e:
            raise NetworkError(uri=server, error=str(e))
        except (OverflowError, TypeError) as e:
            raise XMLRPCMarshallError(error=str(e))
Example #3
0
    def test_forward(self):
        """
        Test the `ipalib.rpc.xmlclient.forward` method.
        """
        class user_add(Command):
            pass

        # Test that ValueError is raised when forwarding a command that is not
        # in api.Command:
        (o, api, home) = self.instance('Backend', in_server=False)
        e = raises(ValueError, o.forward, 'user_add')
        assert str(e) == '%s.forward(): %r not in api.Command' % ('xmlclient',
                                                                  'user_add')

        (o, api, home) = self.instance('Backend', user_add, in_server=False)
        args = (binary_bytes, utf8_bytes, unicode_str)
        kw = dict(one=binary_bytes, two=utf8_bytes, three=unicode_str)
        params = [args, kw]
        result = (unicode_str, binary_bytes, utf8_bytes)
        conn = DummyClass(
            (
                'user_add',
                rpc.xml_wrap(params),
                {},
                rpc.xml_wrap(result),
            ),
            (
                'user_add',
                rpc.xml_wrap(params),
                {},
                Fault(3007, u"'four' is required"),  # RequirementError
            ),
            (
                'user_add',
                rpc.xml_wrap(params),
                {},
                Fault(700, u'no such error'),  # There is no error 700
            ),
        )
        context.xmlclient = Connection(conn, lambda: None)

        # Test with a successful return value:
        assert o.forward('user_add', *args, **kw) == result

        # Test with an errno the client knows:
        e = raises(errors.RequirementError, o.forward, 'user_add', *args, **kw)
        assert_equal(e.args[0], u"'four' is required")

        # Test with an errno the client doesn't know
        e = raises(errors.UnknownError, o.forward, 'user_add', *args, **kw)
        assert_equal(e.code, 700)
        assert_equal(e.error, u'no such error')

        assert context.xmlclient.conn._calledall() is True
Example #4
0
 def connect(self, *args, **kw):
     """
     Create thread-local connection.
     """
     if hasattr(context, self.id):
         raise Exception("{0} is already connected ({1} in {2})".format(
             self.name, self.id,
             threading.currentThread().getName()))
     conn = self.create_connection(*args, **kw)
     setattr(context, self.id, Connection(conn, self.disconnect))
     assert self.conn is conn
     logger.debug('Created connection context.%s', self.id)
Example #5
0
    def test_conn(self):
        """
        Test the `ipalib.backend.Connectible.conn` property.
        """
        msg = 'no context.%s in thread %r'

        class example(self.cls):
            pass

        for klass in (self.cls, example):
            o = klass(shared_instance=True)
            e = raises(AttributeError, getattr, o, 'conn')
            assert str(e) == msg % (klass.__name__,
                                    threading.currentThread().getName())
            conn = Connection('The connection.', Disconnect())
            setattr(context, klass.__name__, conn)
            assert o.conn is conn.conn
            delattr(context, klass.__name__)
Example #6
0
    def test_conn(self):
        """
        Test the `ipalib.backend.Connectible.conn` property.
        """
        api = 'the api instance'
        msg = '{0} is not connected ({1} in {2})'

        class example(self.cls):
            pass

        for klass in (self.cls, example):
            o = klass(api, shared_instance=True)
            e = raises(AttributeError, getattr, o, 'conn')
            assert str(e) == msg.format(klass.__name__, o.id,
                                        threading.currentThread().getName())
            conn = Connection('The connection.', Disconnect())
            setattr(context, klass.__name__, conn)
            assert o.conn is conn.conn
            delattr(context, klass.__name__)
Example #7
0
    def test_execute(self):
        """
        Test the `ipalib.backend.Executioner.execute` method.
        """
        (api, home) = create_test_api(in_server=True)

        class echo(Command):
            takes_args = ('arg1', 'arg2+')
            takes_options = ('option1?', 'option2?')

            def execute(self, *args, **options):
                assert type(args[1]) is tuple
                return dict(result=args + (options, ))

        api.register(echo)

        class good(Command):
            def execute(self, **options):
                raise errors.ValidationError(
                    name='nurse',
                    error=u'Not naughty!',
                )

        api.register(good)

        class bad(Command):
            def execute(self, **options):
                raise ValueError('This is private.')

        api.register(bad)

        class with_name(Command):
            """
            Test that a kwarg named 'name' can be used.
            """
            takes_options = 'name'

            def execute(self, **options):
                return dict(result=options['name'].upper())

        api.register(with_name)

        api.finalize()
        o = self.cls()
        o.set_api(api)
        o.finalize()

        # Test that CommandError is raised:
        conn = Connection('The connection.', Disconnect('someconn'))
        context.someconn = conn
        print str(context.__dict__.keys())
        e = raises(errors.CommandError, o.execute, 'nope')
        assert e.name == 'nope'
        assert conn.disconnect.called is True  # Make sure destroy_context() was called
        print str(context.__dict__.keys())
        assert context.__dict__.keys() == []

        # Test with echo command:
        arg1 = unicode_str
        arg2 = (u'Hello', unicode_str, u'world!')
        args = (arg1, ) + arg2
        options = dict(option1=u'How are you?',
                       option2=unicode_str,
                       version=API_VERSION)

        conn = Connection('The connection.', Disconnect('someconn'))
        context.someconn = conn
        print o.execute('echo', arg1, arg2, **options)
        print dict(result=(arg1, arg2, options))
        assert o.execute('echo', arg1, arg2,
                         **options) == dict(result=(arg1, arg2, options))
        assert conn.disconnect.called is True  # Make sure destroy_context() was called
        assert context.__dict__.keys() == []

        conn = Connection('The connection.', Disconnect('someconn'))
        context.someconn = conn
        assert o.execute('echo', *args,
                         **options) == dict(result=(arg1, arg2, options))
        assert conn.disconnect.called is True  # Make sure destroy_context() was called
        assert context.__dict__.keys() == []

        # Test with good command:
        conn = Connection('The connection.', Disconnect('someconn'))
        context.someconn = conn
        e = raises(errors.ValidationError, o.execute, 'good')
        assert e.name == 'nurse'
        assert e.error == u'Not naughty!'
        assert conn.disconnect.called is True  # Make sure destroy_context() was called
        assert context.__dict__.keys() == []

        # Test with bad command:
        conn = Connection('The connection.', Disconnect('someconn'))
        context.someconn = conn
        e = raises(errors.InternalError, o.execute, 'bad')
        assert conn.disconnect.called is True  # Make sure destroy_context() was called
        assert context.__dict__.keys() == []

        # Test with option 'name':
        conn = Connection('The connection.', Disconnect('someconn'))
        context.someconn = conn
        expected = dict(result=u'TEST')
        assert expected == o.execute('with_name',
                                     name=u'test',
                                     version=API_VERSION)
Example #8
0
                # is an existing connection we need to save the NSS dbdir so
                # we can skip an unnecessary NSS_Initialize() and avoid
                # NSS_Shutdown issues.
                serverproxy = self.create_connection(
                    os.environ.get('KRB5CCNAME'), self.env.verbose,
                    self.env.fallback, self.env.delegate)

                dbdir = None
                current_conn = getattr(context, self.id, None)
                if current_conn is not None:
                    dbdir = getattr(current_conn.conn._ServerProxy__transport,
                                    'dbdir', None)
                    if dbdir is not None:
                        self.debug('Using dbdir %s' % dbdir)
                setattr(context, self.id,
                        Connection(serverproxy, self.disconnect))
                if dbdir is not None:
                    current_conn = getattr(context, self.id, None)
                    current_conn.conn._ServerProxy__transport.dbdir = dbdir
                return self.forward(name, *args, **kw)
            raise NetworkError(uri=server, error=e.errmsg)
        except socket.error, e:
            raise NetworkError(uri=server, error=str(e))
        except (OverflowError, TypeError), e:
            raise XMLRPCMarshallError(error=str(e))


class xmlclient(RPCClient):
    session_path = '/ipa/session/xml'
    server_proxy_class = ServerProxy
    protocol = 'xml'