Ejemplo n.º 1
0
    def __init__(self, tmpdir):
        # type: (LocalPath) -> None
        self.settings = Settings()
        self.settings.database = db_url(tmpdir)
        self.plugins = PluginProxy([])

        # Reinitialize the global plugin proxy with an empty set of plugins in case a previous test
        # initialized plugins.  This can go away once a plugin proxy is injected into everything
        # that needs it instead of maintained as a global.
        set_global_plugin_proxy(self.plugins)

        self.initialize_database()
        self.session = SessionFactory(self.settings).create_session()
        self.graph = GroupGraph()
        session_factory = SingletonSessionFactory(self.session)
        self.repository_factory = GraphRepositoryFactory(
            self.settings, self.plugins, session_factory, self.graph)
        self.sql_repository_factory = SQLRepositoryFactory(
            self.settings, self.plugins, session_factory)
        self.service_factory = ServiceFactory(self.settings, self.plugins,
                                              self.repository_factory)
        self.usecase_factory = UseCaseFactory(self.settings, self.plugins,
                                              self.service_factory)
        self._transaction_service = self.service_factory.create_transaction_service(
        )
Ejemplo n.º 2
0
 def __init__(self, tmpdir):
     # type: (LocalPath) -> None
     self.session = self.create_session(tmpdir)
     self.graph = GroupGraph()
     self.settings = Settings({"database": db_url(tmpdir)})
     self.repository_factory = GraphRepositoryFactory(
         self.settings, self.session, self.graph)
     self.service_factory = ServiceFactory(self.repository_factory)
     self.usecase_factory = UseCaseFactory(self.service_factory)
     self._transaction_service = self.service_factory.create_transaction_service(
     )
Ejemplo n.º 3
0
    def __init__(self, tmpdir):
        # type: (LocalPath) -> None
        self.settings = Settings()
        self.settings.database = db_url(tmpdir)
        self.plugins = PluginProxy([])
        self.graph = GroupGraph()

        # Reinitialize the global plugin proxy with an empty set of plugins in case a previous test
        # initialized plugins.  This can go away once a plugin proxy is injected into everything
        # that needs it instead of maintained as a global.
        set_global_plugin_proxy(self.plugins)

        self.initialize_database()
        self.open_database()
Ejemplo n.º 4
0
def shell_command(args):
    session = make_session()
    graph = GroupGraph.from_db(session)
    pp = pprint

    try:
        from IPython import embed
    except ImportError:
        code.interact(local={"session": session, "graph": graph, "pp": pp})
    else:
        embed()
Ejemplo n.º 5
0
def shell_command(args, settings, session_factory):
    # type: (Namespace, CtlSettings, SessionFactory) -> None
    session = session_factory.create_session()
    graph = GroupGraph.from_db(session)
    pp = pprint

    try:
        from IPython import embed
    except ImportError:
        code.interact(local={"session": session, "graph": graph, "pp": pp})
    else:
        embed()
Ejemplo n.º 6
0
def shell_command(args):
    session = make_session()
    graph = GroupGraph.from_db(session)
    pp = pprint

    try:
        from IPython import embed
    except ImportError:
        code.interact(local={
            "session": session,
            "graph": graph,
            "pp": pp,
        })
    else:
        embed()
Ejemplo n.º 7
0
    def __init__(self, tmpdir):
        # type: (LocalPath) -> None
        self.settings = Settings()
        self.settings.database = db_url(tmpdir)
        self.plugin_proxy = PluginProxy([])

        # Reinitialize the global plugin proxy with an empty set of plugins in case a previous test
        # initialized plugins.  This can go away once a plugin proxy is injected into everything
        # that needs it instead of maintained as a global.
        set_global_plugin_proxy(self.plugin_proxy)

        self.initialize_database()
        self.session = SessionFactory(self.settings).create_session()
        self.graph = GroupGraph()
        self.repository_factory = GraphRepositoryFactory(
            self.settings, self.plugin_proxy, SingletonSessionFactory(self.session), self.graph
        )
        self.service_factory = ServiceFactory(self.repository_factory)
        self.usecase_factory = UseCaseFactory(self.settings, self.service_factory)
        self._transaction_service = self.service_factory.create_transaction_service()
Ejemplo n.º 8
0
class SetupTest(object):
    """Set up the environment for a test.

    Most actions should be done inside of a transaction, created via the transaction() method and
    used as a context handler.  This will ensure that the test setup is committed to the database
    before the test starts running.

    Attributes:
        settings: Settings object for tests (only the database is configured)
        graph: Underlying graph (not refreshed from the database automatically!)
        session: The underlying database session
        plugin_proxy: The plugin proxy used for the tests
        repository_factory: Factory for repository objects
        service_factory: Factory for service objects
        usecase_factory: Factory for usecase objects
    """

    def __init__(self, tmpdir):
        # type: (LocalPath) -> None
        self.settings = Settings()
        self.settings.database = db_url(tmpdir)
        self.plugin_proxy = PluginProxy([])

        # Reinitialize the global plugin proxy with an empty set of plugins in case a previous test
        # initialized plugins.  This can go away once a plugin proxy is injected into everything
        # that needs it instead of maintained as a global.
        set_global_plugin_proxy(self.plugin_proxy)

        self.initialize_database()
        self.session = SessionFactory(self.settings).create_session()
        self.graph = GroupGraph()
        self.repository_factory = GraphRepositoryFactory(
            self.settings, self.plugin_proxy, SingletonSessionFactory(self.session), self.graph
        )
        self.service_factory = ServiceFactory(self.repository_factory)
        self.usecase_factory = UseCaseFactory(self.settings, self.service_factory)
        self._transaction_service = self.service_factory.create_transaction_service()

    def initialize_database(self):
        # type: () -> Session
        schema_repository = SchemaRepository(self.settings)

        # If using a persistent database, clear the database first.
        if "MEROU_TEST_DATABASE" in os.environ:
            schema_repository.drop_schema()

        # Create the database schema.
        schema_repository.initialize_schema()

    def close(self):
        # type: () -> None
        self.session.close()

    @contextmanager
    def transaction(self):
        # type: () -> Iterator[None]
        with self._transaction_service.transaction():
            yield
        self.graph.update_from_db(self.session)

    def create_group(self, name, description="", join_policy=GroupJoinPolicy.CAN_ASK):
        # type: (str, str, GroupJoinPolicy) -> None
        """Create a group, does nothing if it already exists."""
        group_service = self.service_factory.create_group_service()
        if not group_service.group_exists(name):
            group_service.create_group(name, description, join_policy)

    def create_permission(
        self, name, description="", audited=False, enabled=True, created_on=None
    ):
        # type: (str, str, bool, bool, Optional[datetime]) -> None
        """Create a permission, does nothing if it already exists."""
        permission_repository = self.repository_factory.create_permission_repository()
        if not permission_repository.get_permission(name):
            permission_repository.create_permission(
                name, description, audited, enabled, created_on
            )

    def create_user(self, name):
        # type: (str) -> None
        """Create a user, does nothing if it already exists."""
        if User.get(self.session, name=name):
            return
        user = User(username=name)
        user.add(self.session)

    def add_group_to_group(self, member, group, expiration=None):
        # type: (str, str, Optional[datetime]) -> None
        self.create_group(member)
        self.create_group(group)
        member_obj = Group.get(self.session, name=member)
        assert member_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        edge = GroupEdge(
            group_id=group_obj.id,
            member_type=OBJ_TYPES["Group"],
            member_pk=member_obj.id,
            expiration=expiration,
            active=True,
            _role=GROUP_EDGE_ROLES.index("member"),
        )
        edge.add(self.session)

    def add_user_to_group(self, user, group, role="member", expiration=None):
        # type: (str, str, str, Optional[datetime]) -> None
        self.create_user(user)
        self.create_group(group)
        user_obj = User.get(self.session, name=user)
        assert user_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        edge = GroupEdge(
            group_id=group_obj.id,
            member_type=OBJ_TYPES["User"],
            member_pk=user_obj.id,
            expiration=expiration,
            active=True,
            _role=GROUP_EDGE_ROLES.index(role),
        )
        edge.add(self.session)

    def grant_permission_to_group(self, permission, argument, group):
        # type: (str, str, str) -> None
        self.create_group(group)
        self.create_permission(permission)
        group_service = self.service_factory.create_group_service()
        group_service.grant_permission_to_group(permission, argument, group)

    def revoke_permission_from_group(self, permission, argument, group):
        # type: (str, str, str) -> None
        permission_obj = Permission.get(self.session, name=permission)
        assert permission_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        self.session.query(PermissionMap).filter(
            PermissionMap.permission_id == permission_obj.id,
            PermissionMap.group_id == group_obj.id,
            PermissionMap.argument == argument,
        ).delete()

    def create_group_request(self, user, group, role="member"):
        # type: (str, str, str) -> None
        self.create_user(user)
        self.create_group(group)

        user_obj = User.get(self.session, name=user)
        assert user_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj

        # Note: despite the function name, this only creates the request. The flow here is
        # convoluted enough that it seems best to preserve exact behavior for testing.
        group_obj.add_member(
            requester=user_obj, user_or_group=user_obj, reason="", status="pending", role=role
        )

    def create_service_account(self, service_account, owner, description="", machine_set=""):
        # type: (str, str, str, str) -> None
        self.create_group(owner)
        group_obj = Group.get(self.session, name=owner)
        assert group_obj

        if User.get(self.session, name=service_account):
            return
        user = User(username=service_account)
        user.add(self.session)
        service_account_obj = ServiceAccount(
            user_id=user.id, description=description, machine_set=machine_set
        )
        service_account_obj.add(self.session)
        user.is_service_account = True

        self.session.flush()
        owner_map = GroupServiceAccount(
            group_id=group_obj.id, service_account_id=service_account_obj.id
        )
        owner_map.add(self.session)

    def grant_permission_to_service_account(self, permission, argument, service_account):
        # type: (str, str, str) -> None
        self.create_permission(permission)
        permission_obj = Permission.get(self.session, name=permission)
        assert permission_obj
        user_obj = User.get(self.session, name=service_account)
        assert user_obj, "Must create the service account first"
        assert user_obj.is_service_account
        grant = ServiceAccountPermissionMap(
            permission_id=permission_obj.id,
            service_account_id=user_obj.service_account.id,
            argument=argument,
        )
        grant.add(self.session)

    def disable_user(self, user):
        # type: (str) -> None
        user_repository = self.repository_factory.create_user_repository()
        user_repository.disable_user(user)

    def disable_group(self, group):
        # type: (str) -> None
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        group_obj.enabled = False

    def disable_service_account(self, service_account):
        # type: (str) -> None
        service_obj = ServiceAccount.get(self.session, name=service_account)
        assert service_obj
        service_obj.user.enabled = False
        service_obj.owner.delete(self.session)
        permissions = self.session.query(ServiceAccountPermissionMap).filter_by(
            service_account_id=service_obj.id
        )
        for permission in permissions:
            permission.delete(self.session)

    def create_role_user(self, role_user, description="", join_policy=GroupJoinPolicy.CAN_ASK):
        # type: (str, str, GroupJoinPolicy) -> None
        """Create an old-style role user.

        This concept is obsolete and all code related to it will be deleted once all remaining
        legacy role users have been converted to service accounts.  This method should be used only
        for tests to maintain backward compatibility until that happens.
        """
        user = User(username=role_user, role_user=True)
        user.add(self.session)
        self.create_group(role_user, description, join_policy)
        self.add_user_to_group(role_user, role_user)
Ejemplo n.º 9
0
class SetupTest(object):
    """Set up the environment for a test.

    Most actions should be done inside of a transaction, created via the transaction() method and
    used as a context handler.  This will ensure that the test setup is committed to the database
    before the test starts running.

    Attributes:
        settings: Settings object for tests (only the database is configured)
        graph: Underlying graph (not refreshed from the database automatically!)
        session: The underlying database session
        plugins: The plugin proxy used for the tests
        repository_factory: Factory for repository objects
        sql_repository_factory: Factory that returns only SQL repository objects (no graph)
        service_factory: Factory for service objects
        usecase_factory: Factory for usecase objects
    """
    def __init__(self, tmpdir):
        # type: (LocalPath) -> None
        self.settings = Settings()
        self.settings.database = db_url(tmpdir)
        self.plugins = PluginProxy([])

        # Reinitialize the global plugin proxy with an empty set of plugins in case a previous test
        # initialized plugins.  This can go away once a plugin proxy is injected into everything
        # that needs it instead of maintained as a global.
        set_global_plugin_proxy(self.plugins)

        self.initialize_database()
        self.session = SessionFactory(self.settings).create_session()
        self.graph = GroupGraph()
        session_factory = SingletonSessionFactory(self.session)
        self.repository_factory = GraphRepositoryFactory(
            self.settings, self.plugins, session_factory, self.graph)
        self.sql_repository_factory = SQLRepositoryFactory(
            self.settings, self.plugins, session_factory)
        self.service_factory = ServiceFactory(self.settings, self.plugins,
                                              self.repository_factory)
        self.usecase_factory = UseCaseFactory(self.settings, self.plugins,
                                              self.service_factory)
        self._transaction_service = self.service_factory.create_transaction_service(
        )

    def initialize_database(self):
        # type: () -> Session
        schema_repository = SchemaRepository(self.settings)

        # If using a persistent database, clear the database first.
        if "MEROU_TEST_DATABASE" in os.environ:
            schema_repository.drop_schema()

        # Create the database schema.
        schema_repository.initialize_schema()

    def close(self):
        # type: () -> None
        self.session.close()

    @contextmanager
    def transaction(self):
        # type: () -> Iterator[None]
        with self._transaction_service.transaction():
            yield
        self.graph.update_from_db(self.session)

    def create_group(self,
                     name,
                     description="",
                     join_policy=GroupJoinPolicy.CAN_ASK):
        # type: (str, str, GroupJoinPolicy) -> None
        """Create a group, does nothing if it already exists."""
        group_service = self.service_factory.create_group_service()
        if not group_service.group_exists(name):
            group_service.create_group(name, description, join_policy)

    def create_permission(self,
                          name,
                          description="",
                          audited=False,
                          enabled=True,
                          created_on=None):
        # type: (str, str, bool, bool, Optional[datetime]) -> None
        """Create a permission, does nothing if it already exists."""
        permission_repository = self.repository_factory.create_permission_repository(
        )
        if not permission_repository.get_permission(name):
            permission_repository.create_permission(name, description, audited,
                                                    enabled, created_on)

    def create_user(self, name):
        # type: (str) -> None
        """Create a user, does nothing if it already exists."""
        if User.get(self.session, name=name):
            return
        user = User(username=name)
        user.add(self.session)

    def add_group_to_group(self, member, group, expiration=None):
        # type: (str, str, Optional[datetime]) -> None
        self.create_group(member)
        self.create_group(group)
        member_obj = Group.get(self.session, name=member)
        assert member_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        edge = GroupEdge(
            group_id=group_obj.id,
            member_type=OBJ_TYPES["Group"],
            member_pk=member_obj.id,
            expiration=expiration,
            active=True,
            _role=GROUP_EDGE_ROLES.index("member"),
        )
        edge.add(self.session)

    def add_user_to_group(self, user, group, role="member", expiration=None):
        # type: (str, str, str, Optional[datetime]) -> None
        self.create_user(user)
        self.create_group(group)
        user_obj = User.get(self.session, name=user)
        assert user_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        edge = GroupEdge(
            group_id=group_obj.id,
            member_type=OBJ_TYPES["User"],
            member_pk=user_obj.id,
            expiration=expiration,
            active=True,
            _role=GROUP_EDGE_ROLES.index(role),
        )
        edge.add(self.session)

    def grant_permission_to_group(self, permission, argument, group):
        # type: (str, str, str) -> None
        self.create_group(group)
        self.create_permission(permission)
        group_service = self.service_factory.create_group_service()
        group_service.grant_permission_to_group(permission, argument, group)

    def revoke_permission_from_group(self, permission, argument, group):
        # type: (str, str, str) -> None
        permission_obj = Permission.get(self.session, name=permission)
        assert permission_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        self.session.query(PermissionMap).filter(
            PermissionMap.permission_id == permission_obj.id,
            PermissionMap.group_id == group_obj.id,
            PermissionMap.argument == argument,
        ).delete()

    def create_group_request(self, user, group, role="member"):
        # type: (str, str, str) -> None
        self.create_user(user)
        self.create_group(group)

        user_obj = User.get(self.session, name=user)
        assert user_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj

        # Note: despite the function name, this only creates the request. The flow here is
        # convoluted enough that it seems best to preserve exact behavior for testing.
        group_obj.add_member(requester=user_obj,
                             user_or_group=user_obj,
                             reason="",
                             status="pending",
                             role=role)

    def create_service_account(self,
                               service_account,
                               owner,
                               machine_set="",
                               description=""):
        # type: (str, str, str, str) -> None
        self.create_group(owner)
        service_account_repository = self.repository_factory.create_service_account_repository(
        )
        service_account_repository.create_service_account(
            service_account, owner, machine_set, description)

    def grant_permission_to_service_account(self, permission, argument,
                                            service_account):
        # type: (str, str, str) -> None
        self.create_permission(permission)
        permission_obj = Permission.get(self.session, name=permission)
        assert permission_obj
        user_obj = User.get(self.session, name=service_account)
        assert user_obj, "Must create the service account first"
        assert user_obj.is_service_account
        grant = ServiceAccountPermissionMap(
            permission_id=permission_obj.id,
            service_account_id=user_obj.service_account.id,
            argument=argument,
        )
        grant.add(self.session)

    def add_metadata_to_user(self, key, value, user):
        # type: (str, str, str) -> None
        sql_user = User.get(self.session, name=user)
        assert sql_user
        metadata = UserMetadata(user_id=sql_user.id,
                                data_key=key,
                                data_value=value)
        metadata.add(self.session)

    def add_public_key_to_user(self, key, user):
        # type: (str, str) -> None
        sql_user = User.get(self.session, name=user)
        assert sql_user
        public_key = SSHKey(key, strict=True)
        public_key.parse()
        sql_public_key = PublicKey(
            user_id=sql_user.id,
            public_key=public_key.keydata.strip(),
            fingerprint=public_key.hash_md5().replace("MD5:", ""),
            fingerprint_sha256=public_key.hash_sha256().replace("SHA256:", ""),
            key_size=public_key.bits,
            key_type=public_key.key_type,
            comment=public_key.comment,
        )
        sql_public_key.add(self.session)

    def disable_user(self, user):
        # type: (str) -> None
        user_repository = self.repository_factory.create_user_repository()
        user_repository.disable_user(user)

    def disable_group(self, group):
        # type: (str) -> None
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        group_obj.enabled = False

    def disable_service_account(self, service_account):
        # type: (str) -> None
        service_obj = ServiceAccount.get(self.session, name=service_account)
        assert service_obj
        service_obj.user.enabled = False
        service_obj.owner.delete(self.session)
        permissions = self.session.query(
            ServiceAccountPermissionMap).filter_by(
                service_account_id=service_obj.id)
        for permission in permissions:
            permission.delete(self.session)

    def create_role_user(self,
                         role_user,
                         description="",
                         join_policy=GroupJoinPolicy.CAN_ASK):
        # type: (str, str, GroupJoinPolicy) -> None
        """Create an old-style role user.

        This concept is obsolete and all code related to it will be deleted once all remaining
        legacy role users have been converted to service accounts.  This method should be used only
        for tests to maintain backward compatibility until that happens.
        """
        user = User(username=role_user, role_user=True)
        user.add(self.session)
        self.create_group(role_user, description, join_policy)
        self.add_user_to_group(role_user, role_user)
Ejemplo n.º 10
0
def graph(session):
    return GroupGraph.from_db(session)
Ejemplo n.º 11
0
class SetupTest(object):
    """Set up the environment for a test.

    Most actions should be done inside of a transaction, created via the transaction() method and
    used as a context handler.  This will ensure that the test setup is committed to the database
    before the test starts running.

    Attributes:
        graph: Underlying graph (not refreshed from the database automatically!)
        repository_factory: Factory for repository objects
        session: The underlying database session
        service_factory: Factory for service objects
        usecase_factory: Factory for usecase objects
    """
    def __init__(self, tmpdir):
        # type: (LocalPath) -> None
        self.session = self.create_session(tmpdir)
        self.graph = GroupGraph()
        self.settings = Settings({"database": db_url(tmpdir)})
        self.repository_factory = GraphRepositoryFactory(
            self.settings, self.session, self.graph)
        self.service_factory = ServiceFactory(self.repository_factory)
        self.usecase_factory = UseCaseFactory(self.service_factory)
        self._transaction_service = self.service_factory.create_transaction_service(
        )

    def create_session(self, tmpdir):
        # type: (LocalPath) -> Session
        db_engine = get_db_engine(db_url(tmpdir))

        # If using a persistent database, clear the database first.
        if "MEROU_TEST_DATABASE" in os.environ:
            Model.metadata.drop_all(db_engine)

        # Create the database schema and the corresponding session.
        Model.metadata.create_all(db_engine)
        Session.configure(bind=db_engine)
        return Session()

    def close(self):
        # type: () -> None
        self.session.close()

    @contextmanager
    def transaction(self):
        # type: () -> Iterator[None]
        with self._transaction_service.transaction():
            yield
        self.graph.update_from_db(self.session)

    def create_group(self, name):
        # type: (str) -> None
        """Create a group, does nothing if it already exists."""
        if Group.get(self.session, name=name):
            return
        group = Group(groupname=name)
        group.add(self.session)

    def create_permission(self,
                          name,
                          description="",
                          audited=False,
                          enabled=True,
                          created_on=None):
        # type: (str, str, bool, bool, Optional[datetime]) -> None
        """Create a permission, does nothing if it already exists.

        Avoid milliseconds in the creation timestamp since they behave differently in SQLite (which
        preserves them) and MySQL (which drops them).
        """
        if Permission.get(self.session, name=name):
            return
        if not created_on:
            created_on = datetime.utcfromtimestamp(int(time()))
        permission = Permission(
            name=name,
            description=description,
            _audited=audited,
            enabled=enabled,
            created_on=created_on,
        )
        permission.add(self.session)

    def create_user(self, name):
        # type: (str) -> None
        """Create a user, does nothing if it already exists."""
        if User.get(self.session, name=name):
            return
        user = User(username=name)
        user.add(self.session)

    def add_group_to_group(self, member, group):
        # type: (str, str) -> None
        self.create_group(member)
        self.create_group(group)
        member_obj = Group.get(self.session, name=member)
        assert member_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        edge = GroupEdge(
            group_id=group_obj.id,
            member_type=OBJ_TYPES["Group"],
            member_pk=member_obj.id,
            active=True,
            _role=GROUP_EDGE_ROLES.index("member"),
        )
        edge.add(self.session)

    def add_user_to_group(self, user, group, role="member"):
        # type: (str, str, str) -> None
        self.create_user(user)
        self.create_group(group)
        user_obj = User.get(self.session, name=user)
        assert user_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        edge = GroupEdge(
            group_id=group_obj.id,
            member_type=OBJ_TYPES["User"],
            member_pk=user_obj.id,
            active=True,
            _role=GROUP_EDGE_ROLES.index(role),
        )
        edge.add(self.session)

    def grant_permission_to_group(self, permission, argument, group):
        # type: (str, str, str) -> None
        self.create_group(group)
        self.create_permission(permission)
        permission_obj = Permission.get(self.session, name=permission)
        assert permission_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        grant = PermissionMap(permission_id=permission_obj.id,
                              group_id=group_obj.id,
                              argument=argument)
        grant.add(self.session)

    def create_group_request(self, user, group, role="member"):
        # type: (str, str, str) -> None
        self.create_user(user)
        self.create_group(group)

        user_obj = User.get(self.session, name=user)
        assert user_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj

        # Note: despite the function name, this only creates the request. The flow here is
        # convoluted enough that it seems best to preserve exact behavior for testing.
        group_obj.add_member(requester=user_obj,
                             user_or_group=user_obj,
                             reason="",
                             status="pending",
                             role=role)