Beispiel #1
0
def PluginsCmd(config: Config, source_id: str):
    builder = CommandBuilder('plugins', config.credentials)

    @builder.from_cls()
    class _PluginsCmd(CommandWithList):
        '''Plugins - manage source plugins'''
        def __init__(self, config: Config, source_id: str):
            self.config = config
            super().__init__()

            self.source_id = source_id
            self.client = PluginClient(
                api_host=self.config.credentials.api_host,
                auth_token=self.config.credentials.auth_token,
                target_org=config.org.id)

            self.defaults = {
                plugin.os: plugin.id
                for plugin in self.client.list(source_id=source_id,
                                               default_only=True)
            }

        def get_things(self):
            plugins = [
                p for p in self.client.list(source_id=self.source_id)
                if p.enabled
            ]
            return sorted(plugins,
                          key=lambda x: x.last_updated_timestamp,
                          reverse=True)

        def things_header(self):
            return [("Version", 20), ("OS", 20), ("Default", 7)]

        def format_thing(self, plugin: Plugin) -> str:
            version = plugin.display_version if plugin.display_version else plugin.version
            is_default = "●" if self.defaults.get(
                plugin.os) == plugin.id else ""

            return f"{version.rjust(20)} {plugin.os.value.rjust(20)} {colorama.Fore.RED}{is_default.center(7)}{colorama.Style.RESET_ALL}"

        @builder.empty_cmd()
        def _do_list(self):
            '''list available plugins'''
            return self._list()

        @builder.cmd(permissions=['admin:source:plugins:create'])
        def do_add(self, arg):
            '''add new source plugin'''
            PluginBuilder(self.config, self.source_id).from_user().build()

        @builder.cmd(permissions=['admin:source:plugins:update'])
        def do_default(self, idx):
            '''make plugin [idx] default'''
            selected: Plugin = self.get_thing_by_index(self.arg_as_idx(idx))

            self.client.set_default(selected.id)
            print("Default updated")

    return builder.build()(config, source_id)
Beispiel #2
0
def ScheduleCmd(config: Config, source: Source):
    builder = CommandBuilder('schedule', config.credentials)

    @builder.from_cls()
    class _SchedulesCmd(Command):
        '''Schedules - view and manage source execution schedules'''
        def __init__(self, config: Config, source: Source):
            self.config = config
            super().__init__()

            self.source = source
            self.client = SchedulerServiceClient(
                api_host=config.credentials.api_host,
                auth_token=config.credentials.auth_token,
                target_org=config.org.id)

        def emptyline(self):
            return self.do_help('')

        @builder.cmd(
            permissions=['admin:source:schedule:get', 'source:schedule:get'])
        def do_info(self, _arg):
            '''retrieve schedule details'''
            try:
                sched = self.client.get(self.source.id)
                print(sched.schedule_config)
            except:
                print("No schedule set")

        @builder.cmd(permissions=[
            'admin:source:schedule:delete', 'source:schedule:delete'
        ])
        def do_del(self, _arg):
            '''delete source schedule - disables automatic data collection'''
            if Builder.get_yes_no("Really delete schedule?"):
                self.client.delete(self.source.id)
                print(f"{source.display_name} schedule removed")

        @builder.cmd(permissions=[
            'admin:source:schedule:create', 'source:schedule:create',
            'admin:source:schedule:update', 'source:schedule:update'
        ])
        def do_set(self, _arg):
            '''Set source schedule'''
            update = False
            try:
                self.client.get(self.source.id)
                update = True
            except:
                pass

            SourceScheduleBuilder(
                self.config, self.source.id).from_user().build(update=update)

    return builder.build()(config, source)
Beispiel #3
0
def SchemasCmd(config: Config, source: Source):
    builder = CommandBuilder('schemas', config.credentials)

    @builder.from_cls()
    class _SchemasCmd(CommandWithList):
        '''Schemas - view and manage source configuration schemas'''

        def __init__(self, config: Config, source: Source):
            self.config = config
            super().__init__()

            self.source = source
            self.schema_client = SourceSchemaClient(
                api_host=config.credentials.api_host, auth_token=config.credentials.auth_token, target_org=config.org.id)

        def get_things(self):
            return self.schema_client.get(self.source.id)

        def things_header(self):
            return [("Schema", 20)]

        def format_thing(self, schemas: SourceSchemas) -> str:
            return schemas.info.description.rjust(20)

        @builder.empty_cmd()
        def _do_list(self):
            '''list source schemas'''
            return self._list()

        @builder.cmd(permissions=['admin:schema:read', 'schema:read'])
        def do_info(self, idx):
            '''retrieve schema details'''
            selected: SourceSchemas = self.get_thing_by_index(self.arg_as_idx(idx))
            pprint(selected.as_dict())

        @builder.cmd(permissions=['admin:source:update'])
        def do_del(self, idx):
            '''delete source schema'''
            selected: SourceSchemas = self.get_thing_by_index(self.arg_as_idx(idx))

            all_schemas = self.schema_client.get(self.source.id)
            updated = [SourceSchemaByName(info=schema.info,
                                          auth=schema.auth['title'],
                                          connect=schema.connect['title'],
                                          settings=schema.settings['title']) for schema in all_schemas if schema.info.description != selected.info.description]
            self.schema_client.update(
                self.source.id, SourceSchemaByNameArray(types=updated))

        @builder.cmd(permissions=['admin:source:update'])
        def do_add(self, arg):
            '''add source schemas'''
            SourceSchemaBuilder(config=self.config,
                                source_id=self.source.id).from_user().build()

    return builder.build()(config, source)
Beispiel #4
0
def RolesCmd(config: Config, user: User):
    builder = CommandBuilder('roles', credentials=config.credentials)

    @builder.from_cls()
    class _RolesCmd(CommandWithList):
        '''Roles - manage and interact with roles'''

        def __init__(self, config: Config, user: User):
            super().__init__()
            self.config = config
            self.user = user
            self.client = TenantClient(
                config.credentials.api_host, config.credentials.auth_token, target_org=config.org.id)

        def get_things(self):
            return sorted(self.client.roles(), key=lambda x: x.name)

        def things_header(self):
            return [("Name", 20), ("Description", 40), ("Active", 6)]

        def format_thing(self, role: Role) -> str:
            enabled = "●" if role.name in self.user.roles else ''
            return f"{role.name.rjust(20)} {role.description.rjust(40)} {colorama.Fore.RED}{enabled.center(6)}{colorama.Style.RESET_ALL}"

        @builder.empty_cmd()
        def _do_list(self):
            '''list org roles'''
            return self._list()

        @builder.cmd(permissions=['admin:roles:read', 'tenant:roles:read', 'roles:read'])
        def do_info(self, idx):
            '''show role details'''
            selected: Role = self.get_thing_by_index(self.arg_as_idx(idx))

            pprint(selected.as_dict())

        @builder.cmd(permissions=['org:user:write'])
        def do_add(self, idx):
            '''add role to user'''
            selected: Role = self.get_thing_by_index(self.arg_as_idx(idx))
            self.client.user_add_role(self.user.email, selected.name)
            print(f"Added {selected.name}")
            self.user = self.client.get_user(self.user.email)

        @builder.cmd(permissions=['org:user:write'])
        def do_del(self, idx):
            '''remove role from user'''
            selected: Role = self.get_thing_by_index(self.arg_as_idx(idx))
            self.client.user_delete_role(self.user.email, selected.name)
            print(f"Removed {selected.name}")
            self.user = self.client.get_user(self.user.email)

    return builder.build()(config, user)
Beispiel #5
0
def UsersCmd(config: Config):
    builder = CommandBuilder('users', credentials=config.credentials)

    @builder.from_cls()
    class _UsersCmd(CommandWithList):
        '''Users - manage and interact with users'''
        def __init__(self, config: Config):
            super().__init__()
            self.config = config
            self.client = TenantClient(config.credentials.api_host,
                                       config.credentials.auth_token,
                                       target_org=config.org.id)

        def default(self, line: str) -> Union[bool, CmdResponse]:
            try:
                idx = int(line)
                return self._do_select(idx)
            except IndexError as e:
                print(str(e))
                return False
            except ValueError:
                pass

            return super().default(line)

        @builder.empty_cmd()
        def _do_select(self, idx: int) -> CmdResponse:
            '''change scope into user [idx]'''

            selected = self.get_thing_by_index(idx)

            return NewScopeResponse(UserScope(self.config, selected))

        def get_things(self):
            return sorted(self.client.list_users(), key=lambda x: x.name)

        def things_header(self):
            return [("Name", 20), ("Email", 30)]

        def format_thing(self, user: User) -> str:
            return f"{user.nickname.rjust(20)} {user.email.rjust(30)}"

        @builder.empty_cmd()
        def _do_list(self):
            '''list org users'''
            return self._list()

        @builder.cmd(permissions=['org:user:read'])
        def do_info(self, idx):
            '''show user details'''
            selected: User = self.get_thing_by_index(self.arg_as_idx(idx))

            pprint(selected.as_dict())

        @builder.cmd(permissions=['org:user:write'])
        def do_add(self, _arg):
            '''add user to org'''
            AddUserBuilder(self.config).from_user().build()

        @builder.cmd(permissions=['org:user:delete'])
        def do_del(self, idx):
            '''remove user from org'''
            selected: User = self.get_thing_by_index(self.arg_as_idx(idx))
            if Builder.get_yes_no(
                    f"Really remove user from {self.config.org.org_name}?",
                    default_yes=False):
                self.client.delete_user(selected.email)

    return builder.build()(config)
Beispiel #6
0
def RunnersCmd(config: Config):
    builder = CommandBuilder('runners', config.credentials)

    @builder.from_cls()
    class _RunnersCmd(CommandWithList):
        '''Runners - manage runners'''
        def __init__(self, config: Config):
            self.config = config
            super().__init__()

            self.client = RunnerServiceClient(
                api_host=config.credentials.api_host,
                auth_token=config.credentials.auth_token,
                target_org=config.org.id)
            self.runners = None

        def get_things(self):
            epoch = datetime.datetime.utcfromtimestamp(0).replace(
                tzinfo=datetime.timezone.utc)
            return sorted(self.client.list(),
                          key=lambda x: x.last_checkin_time or epoch,
                          reverse=True)

        def things_header(self):
            return [("Name", 26), ("Last Checkin", 40)]

        def format_thing(self, runner: Runner) -> str:
            if runner.display_name:
                return f"{runner.display_name.rjust(26)} {str(runner.last_checkin_time).rjust(40)}"
            else:
                return f"{runner.hostname.rjust(26)} {str(runner.last_checkin_time).rjust(40)}"

        @builder.empty_cmd()
        def _do_list(self):
            '''list available runners'''
            return self._list()

        @builder.cmd(permissions=['admin:runner:get', 'runner:get'])
        def do_info(self, idx: int):
            '''retrieve runner details'''
            selected = self.get_thing_by_index(self.arg_as_idx(idx))
            pprint(selected.as_dict())

        @builder.cmd(permissions=['admin:runner:delete', 'runner:delete'])
        def do_del(self, idx: int):
            '''unregister runner'''
            selected = self.get_thing_by_index(self.arg_as_idx(idx))
            if Builder.get_yes_no(
                    f"Really delete runner {selected.display_name}?",
                    default_yes=False):
                self.client.delete(selected.runner_id)

        @builder.cmd(permissions=['admin:runner:download', 'runner:download'])
        def do_download(self, _arg):
            '''download runner binary'''
            current_os = platform.system().lower()
            runner_os = Builder.get_one_of("Which platform",
                                           ["linux", "windows", "darwin"],
                                           default=current_os)

            default_target = "~/Downloads/runner.exe" if runner_os == "windows" else "~/Downloads/runner"

            target = None
            while target is None:
                target = Builder.get_input(
                    f"Save binary to [{default_target}]",
                    required=False) or os.path.expanduser(default_target)

                if os.path.exists(target):
                    if not Builder.get_yes_no(f"{target} exists. Overwrite?",
                                              default_yes=False):
                        target = None

            runner_binary_bytes = self.client.download(runner_os)

            os.makedirs(os.path.basename(target), exist_ok=True)
            with open(target, "wb") as f:
                f.write(runner_binary_bytes)

            p = Path(target)
            p.chmod(p.stat().st_mode | stat.S_IXUSR)

            print(f"Runner {runner_os} binary saved to: {target}")

    return builder.build()(config)
Beispiel #7
0
def OrgsCmd(credentials: ApiCredentials):
    builder = CommandBuilder('orgs', credentials=credentials)

    @builder.from_cls()
    class _OrgsCmd(CommandWithList):
        '''Orgs - manage and interact with organizations and their configurations'''
        def __init__(self, credentials: ApiCredentials):
            super().__init__()
            self.credentials = credentials
            self.client = TenantClient(credentials.api_host,
                                       credentials.auth_token)

        def default(self, line: str) -> Union[bool, CmdResponse]:
            try:
                idx = int(line)
                return self._do_select(idx)
            except IndexError as e:
                print(str(e))
                return False
            except ValueError:
                pass

            return super().default(line)

        def things_header(self):
            return [("Org", 32), ("Id", 40)]

        def get_things(self):
            return sorted(self.client.org_list(), key=lambda x: x.org_name)

        def format_thing(self, org: Organization) -> str:
            return f"{org.org_name.rjust(32)} {org.id.rjust(40)}"

        @builder.empty_cmd()
        def _do_list(self):
            '''list available orgs'''
            return self._list()

        @builder.empty_cmd()
        def _do_select(self, idx: int) -> Union[bool, CmdResponse]:
            '''change scope into org [idx]'''

            selected = self.get_thing_by_index(idx)

            return NewScopeResponse(
                OrgScope(Config(credentials=self.credentials, org=selected)))

        @builder.cmd(permissions=['admin:orgs:write', 'tenant:orgs:write'])
        def do_add(self, _arg):
            '''add new org'''
            org = OrgBuilder(credentials=self.credentials).from_user().build()

        @builder.cmd(permissions=['admin:orgs:delete', 'tenant:orgs:delete'])
        def do_del(self, idx):
            '''delete org [idx]'''
            selected: Organization = self.get_thing_by_index(
                self.arg_as_idx(idx))
            assert selected.id

            if Builder.get_yes_no(f"Really delete {selected.org_name}?",
                                  default_yes=False):
                self.client.org_delete(selected.id)
                print(f"Deleted {selected.org_name}")

        @builder.cmd(permissions=['admin:orgs:account', 'orgs:account'])
        def do_token(self, idx):
            '''get service account token for [idx]'''
            selected: Organization = self.get_thing_by_index(
                self.arg_as_idx(idx))
            assert selected.id

            print(self.client.svc_token(selected.id))

        @builder.cmd(permissions=['admin:orgs:read', 'orgs:my:read'])
        def do_info(self, idx: int):
            '''retrieve organization details'''
            selected = self.get_thing_by_index(self.arg_as_idx(idx))
            pprint(selected.as_dict())

    return builder.build()(credentials)
Beispiel #8
0
def SourcesCmd(config: Config) -> CommandWithList:
    builder = CommandBuilder('sources', config.credentials)

    @builder.from_cls()
    class _SourcesCmd(CommandWithList):
        '''Sources - work with available integration sources available in the source catalog.'''

        def __init__(self, config: Config):
            self.config = config

            super().__init__()

            self.client = SourceCatalogClient(
                api_host=config.credentials.api_host, auth_token=config.credentials.auth_token, target_org=config.org.id)
            self.scheduler_client = SchedulerServiceClient(
                api_host=config.credentials.api_host, auth_token=config.credentials.auth_token, target_org=config.org.id)
            self.oauth_client = SourceOAuthClient(
                api_host=self.config.credentials.api_host, auth_token=self.config.credentials.auth_token, target_org=self.config.org.id)


        def default(self, line: str) -> Union[bool, CmdResponse]:
            try:
                idx = int(line)
                return self._do_select(idx)
            except IndexError as e:
                print(str(e))
                return False
            except ValueError:
                pass

            return super().default(line)

        def get_things(self):
            return self.client.list()

        def things_header(self):
            return [("Source", 40)]

        def format_thing(self, source: Source) -> str:
            return source.display_name.rjust(40)

        @builder.empty_cmd()
        def _do_list(self):
            '''list available sources'''
            return self._list()

        @builder.empty_cmd()
        def _do_select(self, idx: int) -> CmdResponse:
            '''change scope into source [idx]'''
            selected = self.get_thing_by_index(idx)

            return NewScopeResponse(SourceScope(self.config, selected))

        @builder.cmd(permissions=['admin:source:config:write', 'source:config:write'])
        def do_config(self, idx):
            '''configure source [idx]'''
            selected: Source = self.get_thing_by_index(self.arg_as_idx(idx))
            builder = source_config = SourceConfigBuilder(self.config, selected.id)
            source_config = builder.from_user().build()
            if source_config:
                assert source_config.id

                if builder.schema.auth['title'] == 'oauth2':
                    url = self.oauth_client.initiate(source_config_id=source_config.id)
                    print("Browse to the following URL to initiate the OAuth workflow:")
                    print(url)

                try:
                    self.scheduler_client.execute(source_config_id=source_config.id)
                except Exception as e:
                    print(f"Unable to schedule immediate execution: {e}")

        @builder.cmd(permissions=['admin:source:create'])
        def do_add(self, _arg):
            '''add new source'''
            print("Source Configuration")
            source = SourceBuilder(config=self.config).from_user().build()
            if source:
                print("Source Schema Configuration")
                schema = SourceSchemaBuilder(config=self.config,
                                             source_id=source.id).from_user().build()
                if schema:
                    print("Source Schedule")
                    SourceScheduleBuilder(config=self.config,
                                          source_id=source.id).from_user().build()

    return builder.build()(config)
Beispiel #9
0
def SourceConfigsCmd(config: Config, source: Optional[Source] = None):
    builder = CommandBuilder('configs', config.credentials)

    @builder.from_cls()
    class SourceConfigsCmd(CommandWithList):
        '''Configs - manage source configs'''
        def __init__(self, config: Config, source: Optional[Source] = None):
            self.config = config
            super().__init__()

            self.source = source
            self.client = SourceConfigClient(
                api_host=config.credentials.api_host,
                auth_token=config.credentials.auth_token,
                target_org=config.org.id)
            self.scheduler_client = SchedulerServiceClient(
                api_host=config.credentials.api_host,
                auth_token=config.credentials.auth_token,
                target_org=config.org.id)

            catalog_client = SourceCatalogClient(
                api_host=config.credentials.api_host,
                auth_token=config.credentials.auth_token,
                target_org=config.org.id)
            self.sources_by_id = {
                self.source.id: self.source
            } if self.source else {
                source.id: source
                for source in catalog_client.list()
            }

        def get_things(self):
            def get_timestamp(x: SourceConfig) -> datetime:
                assert x.last_updated_timestamp
                return x.last_updated_timestamp

            return sorted(self.client.list(
                source_id=self.source.id if self.source else None),
                          key=get_timestamp,
                          reverse=True)

        def things_header(self):
            return [("ID", 36), ("Source", 40)]

        def format_thing(self, config: SourceConfig) -> str:
            source = self.sources_by_id.get(config.source_id)
            return f"{config.id.rjust(36)} {source.display_name.rjust(40) if source else 'UNKNOWN'.rjust(40)}"

        @builder.empty_cmd()
        def _do_list(self):
            '''list source configs'''
            return self._list()

        @builder.cmd(
            permissions=['admin:source:config:read', 'source:config:read'])
        def do_info(self, idx):
            '''retrieve details for config [idx]'''

            selected: SourceConfig = self.get_thing_by_index(
                self.arg_as_idx(idx))

            pprint(selected.as_dict())

        @builder.cmd(
            permissions=['admin:source:audit:read', 'source:audit:read'])
        def do_audit(self, idx_n):
            '''retrieve last N execution audit logs for config [idx]'''

            idx, _, n = idx_n.partition(' ')

            n = int(n) if n else 10

            selected: SourceConfig = self.get_thing_by_index(
                self.arg_as_idx(idx))

            client = SourceAuditClient(
                api_host=self.config.credentials.api_host,
                auth_token=self.config.credentials.auth_token,
                target_org=self.config.org.id)

            for audit in client.list("execution",
                                     source_config_id=selected.id,
                                     per_page=n):
                pprint(audit.as_dict(), width=240)

        @builder.cmd(
            permissions=['admin:source:config:write', 'source:config:write'])
        def do_oauth(self, idx):
            '''initiate OAuth2 workflow for config [idx]'''

            selected: SourceConfig = self.get_thing_by_index(
                self.arg_as_idx(idx))
            assert selected.id

            if selected.auth and selected.auth.schema != 'oauth2':
                raise Exception("Not an OAuth2 config")

            client = SourceOAuthClient(
                api_host=self.config.credentials.api_host,
                auth_token=self.config.credentials.auth_token,
                target_org=self.config.org.id)

            url = client.initiate(source_config_id=selected.id)
            print(
                "Browse to the following URL to initiate the OAuth workflow:")
            print(url)

        @builder.cmd(
            permissions=['admin:source:config:delete', 'source:config:delete'])
        def do_del(self, idx):
            '''delete config [idx]'''
            selected: SourceConfig = self.get_thing_by_index(
                self.arg_as_idx(idx))
            assert selected.id

            if Builder.get_yes_no(f"Really delete {selected.id}?",
                                  default_yes=False):
                self.client.delete(selected.id)
                print(f"Deleted {selected.id}")

        @builder.cmd(permissions=['admin:source:schedule:execute'])
        def do_exec(self, idx):
            '''execute config [idx]'''
            selected: SourceConfig = self.get_thing_by_index(
                self.arg_as_idx(idx))
            assert selected.id

            print(self.scheduler_client.execute(source_config_id=selected.id))

    return builder.build()(config, source)