def get_connections(self, *, provider=None, sort=None, skip=None, limit=None): """Returns all the connections Args: provider (list[str]): Type or list of types to filter for sort (str): Field by which the results should be sorted. Ascending by default, descending if prefixed by - skip (int): Number of results to skip from the start of the data set. Skip is to be used with the limit parameter for paging limit (int): How many results should be returned. limit is to be used with the skip parameter for paging """ query_params = { 'sort': sort, 'skip': skip, 'limit': limit } provider = PySenseUtils.make_iterable(provider) resp_json = self.connector.rest_call('get', 'api/v1/connection', query_params=query_params) ret_arr = [] for connection in resp_json: connection = PySenseConnection.Connection(self, connection) if len(provider) > 0: if connection.get_provider() in provider: ret_arr.append(connection) else: ret_arr.append(connection) return ret_arr
def remove_shares(self, shares): """Unshare a cube to groups and users To unshare a cube we have to: - Query for the whom the cube is currently shared with - Delete the users/groups we want to unshare with - Re upload the reduced share Args: shares (list[Group,User]): Users and groups to unshare the cube to """ curr_shares_arr = self.get_shares_json() curr_id_arr = [] for share in curr_shares_arr: curr_id_arr.append(share['partyId']) for share in PySenseUtils.make_iterable(shares): share_id = share.get_id() if share_id is None: raise PySenseException.PySenseException( 'No id found for {}'.format(share)) elif share_id in curr_id_arr: index = curr_id_arr.index(share_id) del curr_shares_arr[index] del curr_id_arr[index] self.py_client.connector.rest_call( 'put', 'api/elasticubes/{}/{}/permissions'.format( self.server_address, self.get_title(url_encoded=True)), json_payload=curr_shares_arr)
def delete_connections(self, connections): """Deletes the given PySense connections Args: connections (list[Connection]): The connections to delete """ for connection in PySenseUtils.make_iterable(connections): self.connector.rest_call('delete', 'api/v1/connection/{}'.format(connection.get_oid()))
def delete_users(self, users): """Deletes the specified users Args: users: Users to delete """ for user in PySenseUtils.make_iterable(users): self.connector.rest_call('delete', 'api/v1/users/{}'.format(user.get_id()))
def delete_groups(self, groups): """Delete groups. Args: groups (list[Group]): Groups to delete """ for group in PySenseUtils.make_iterable(groups): self.connector.rest_call('delete', 'api/groups/{}'.format(group.get_id()))
def add_share(self, shares, rule, subscribe, *, share_cube=True, admin_access=None): """Share a dashboard to a new group or user. If dashboard is already shared with user or group, nothing happens By default gives query permission to the cube as well. Set share_cubes to false to not update cube shares Args: shares (list[Group,User]): One to many PySense Groups or Users rule (str): The permission of the user on the dashboard (view, edit, etc) subscribe (bool): Whether to subscribe the user to reports share_cube (bool): (Optional) If set to false user will not get dashboard results. admin_access (bool): (Optional) Set to true if logged in as admin and getting unowned dashboard """ query_params = {'adminAccess': admin_access} curr_shares = self.get_shares_json(admin_access=admin_access) for share in PySenseUtils.make_iterable(shares): share_id = share.get_id() for curr_share in curr_shares['sharesTo']: if share_id == curr_share['shareId']: share_id = None if share_id is not None: if isinstance(share, PySenseUser.User): curr_shares['sharesTo'].append({ 'shareId': share.get_id(), 'type': 'user', 'rule': rule, 'subscribe': subscribe }) elif isinstance(share, PySenseGroup.Group): curr_shares['sharesTo'].append({ 'shareId': share.get_id(), 'type': 'group', 'rule': rule, 'subscribe': subscribe }) self.py_client.connector.rest_call('post', 'api/shares/dashboard/{}'.format( self.get_oid()), json_payload=curr_shares, query_params=query_params) if share_cube: data_source = self.get_datasource() data_source.add_share(shares)
def delete_widget(self, widgets): """Deletes widgets from its dashboard. Args: widgets (list[Widget]): Widgets to delete """ for widget in PySenseUtils.make_iterable(widgets): self.py_client.connector.rest_call('delete', 'api/v1/dashboards/{}/widgets/{}' .format(self.get_oid(), widget.get_oid())) self._reset()
def remove_user(self, users): """Remove users from group Args: users (list[User]): Users to remove from the group """ payload = [] for user in PySenseUtils.make_iterable(users): payload.append(user.get_id()) self.py_client.connector.rest_call('delete', 'api/groups/{}/users'.format(self.get_id()), json_payload=payload)
def delete_blox_actions(self, actions): """Deletes the blox actions Args: actions (list[BloxAction]): Actions to delete """ for action in PySenseUtils.make_iterable(actions): json_payload = {"type": action.get_type()} self.connector.rest_call('post', 'api/v1/deleteCustomAction/Blox', json_payload=json_payload)
def delete_data_models(self, data_models): """Deletes the given data models Args: data_models: One to many data models to delete """ PySenseUtils.validate_version(self, SisenseVersion.Version.LINUX, 'delete_data_model') for data_model in PySenseUtils.make_iterable(data_models): self.connector.rest_call( 'delete', 'api/v2/datamodels/{}'.format(data_model.get_oid()))
def add_user(self, users): """Adds users to group. Args: users (list[User]): The users to add to the group """ payload = [] for user in PySenseUtils.make_iterable(users): payload.append(user.get_id()) self.py_client.connector.rest_call('post', 'api/groups/{}/users'.format(self.get_id()), json_payload=payload)
def add_share(self, shares, *, can_edit=False): """Share a cube to new groups and users By default will give query access. Set can_edit to True for editor access. Args: shares (list[Group,User]): Users and groups to share the cube to can_edit (bool): (Optional) True for edit privileges """ shares = PySenseUtils.make_iterable(shares) curr_shares_arr = self.get_shares_json() rule = 'r' if can_edit is False else 'w' curr_id_arr = [] for share in curr_shares_arr: party_id = share['partyId'] curr_id_arr.append(party_id) del share['partyId'] share['party'] = party_id for share in shares: share_id = share.get_id() if share_id is None: raise PySenseException.PySenseException( 'No id found for {}'.format(share)) elif share_id in curr_id_arr: index = curr_id_arr.index(share_id) curr_shares_arr[index]['permission'] = rule elif isinstance(share, PySenseUser.User): curr_shares_arr.append({ 'party': share.get_id(), 'type': 'user', 'permission': rule }) elif isinstance(share, PySenseGroup.Group): curr_shares_arr.append({ 'party': share.get_id(), 'type': 'group', 'rule': rule }) else: raise PySenseException.PySenseException( 'Add Share expected User or group, got {}'.format( type(share))) self.py_client.connector.rest_call( 'put', 'api/elasticubes/{}/{}/permissions'.format( self.server_address, self.get_title(url_encoded=True)), json_payload=curr_shares_arr)
def delete_folders(self, folders): """Delete given folders Args: folders (list[Folder]): Folders to delete """ folder_arr = [] for folder in PySenseUtils.make_iterable(folders): folder_arr.append(folder.get_oid()) query_params = {"folderIds": ','.join(folder_arr)} self.connector.rest_call('delete', 'api/v1/folders/bulk', query_params=query_params)
def add_groups(self, names): """Add groups with given names. Args: names (str): The names of the new groups Returns: list[Group]: The new groups """ ret_arr = [] for name in PySenseUtils.make_iterable(names): payload = {'name': name} resp_json = self.connector.rest_call('post', 'api/v1/groups', json_payload=payload) ret_arr.append(PySenseGroup.Group(self, resp_json)) return ret_arr
def update(self, *, email=None, user_name=None, first_name=None, last_name=None, role=None, groups=None, preferences=None): """Updates given fields for user object. Args: email (str): (Optional) Value to update email to user_name (str): (Optional) Value to update username to first_name (str): (Optional) Value to update firstName to last_name (str): (Optional) Value to update lastName to role (Role): (Optional) New role for user groups (list[Group]): (Optional) New set of groups for user preferences (JSON): (Optional) Preferences to be updated for user """ user_groups = groups if groups is not None else self.get_groups() group_arr = [] for group in PySenseUtils.make_iterable(user_groups): group_arr.append(group.get_oid()) user_json = { 'email': email if email else self.get_email(), 'userName': user_name if user_name else self.get_user_name(), 'firstName': first_name if first_name else self.get_first_name(), 'lastName': last_name if last_name else self.get_last_name(), 'roleId': self.py_client.get_role_id(role) if role else self.get_role_id(), 'groups': group_arr, 'preferences': preferences if preferences else self.get_preferences() } resp_json = self.py_client.connector.rest_call( 'patch', 'api/v1/users/{}'.format(self.get_id()), json_payload=user_json) self._reset(resp_json)
def add_dashboards(self, dashboards): """Import given dashboards. Args: dashboards (list[Dashboard]): Dashboards to import to Sisense Returns: list[Dashboard]: The new dashboards """ ret_arr = [] for dashboard in PySenseUtils.make_iterable(dashboards): resp = self.connector.rest_call('post', 'api/v1/dashboards', json_payload=dashboard.json) ret_arr.append(PySenseDashboard.Dashboard(self, resp)) return ret_arr
def add_user(self, email, role, *, user_name=None, first_name=None, last_name=None, groups=[], preferences={}, ui_settings={}, password=None): """Creates a user in Sisense. Args: email (str): email address for user role (Role): SisenseRole enum for the role of the user user_name (str): (Optional) User user name. Email used if None first_name (str): (Optional) User first name last_name (str): (Optional) User last name groups (str): (Optional) The groups to add the user to preferences (str): (Optional) User preferences ui_settings (JSON): (Optional) User ui settings password (str): (Optional) The password to set for the user Returns: User: Newly created user object """ user_obj = { 'email': email, 'username': user_name if user_name is not None else email, 'roleId': self.get_role_id(role) } group_ids = [] for group in PySenseUtils.make_iterable(groups): group_ids.append(group.get_id()) if len(group_ids) > 0: user_obj['groups'] = group_ids if first_name is not None: user_obj['firstName'] = first_name if last_name is not None: user_obj['lastName'] = last_name if preferences is not None: user_obj['preferences'] = preferences if ui_settings is not None: user_obj['uiSettings'] = ui_settings if password is not None: user_obj['password'] = password resp_json = self.connector.rest_call('post', 'api/v1/users', json_payload=user_obj) return PySenseUser.User(self, resp_json)
def delete_dashboards(self, dashboards, *, admin_access=None): """Delete dashboards. Args: dashboards (list[Dashboard]): Dashboards to delete admin_access (bool): (Optional) Set to true if logged in as admin and deleting unowned dashboard """ for dashboard in PySenseUtils.make_iterable(dashboards): if admin_access is True: query_params = {'adminAccess': admin_access} self.connector.rest_call('delete', 'api/dashboards/{}'.format( dashboard.get_oid()), query_params=query_params) else: self.connector.rest_call( 'delete', 'api/v1/dashboards/{}'.format(dashboard.get_oid()))
def get_groups_by_name(self, group_names): """Returns an array of groups matching the given names Args: group_names (list[str]): Group names to look for Returns: list[Group]: Groups with the given names """ if group_names is None: return [] server_groups = self.get_groups() ret = [] group_names = PySenseUtils.make_iterable(group_names) for group in server_groups: if group.get_name() in group_names: ret.append(group) return ret
def export_dashboards(self, dashboards, path, *, admin_access=None): """Get dashboard as dash file. Args: dashboards (list[Dashboard]): One to many dashboards to back up to dash file path (str): Path to save location of dash file admin_access (bool): (Optional) Set to true if logged in as admin and exporting unowned dashboard Returns: str: The path of the created file """ query_params = {'dashboardIds': [], 'adminAccess': admin_access} for dashboard in PySenseUtils.make_iterable(dashboards): query_params['dashboardIds'].append(dashboard.get_oid()) self.connector.rest_call('get', 'api/v1/dashboards/export', path=path, query_params=query_params) return path
def remove_shares(self, shares, *, admin_access=None): """Unshare a dashboard to a list of groups and users Args: shares (list[Group,User]): Groups and users to unshare the dashboard with admin_access (bool): (Optional) Set to true if logged in as admin and getting unowned dashboard """ query_params = { 'adminAccess': admin_access } share_ids_to_delete = [] for shares in PySenseUtils.make_iterable(shares): share_ids_to_delete.append(shares.get_id()) current_shares = self.get_shares_json(admin_access=admin_access) for share_id in share_ids_to_delete: for i, shares in enumerate(current_shares['sharesTo']): if shares['shareId'] == share_id: del current_shares['sharesTo'][i] self.py_client.connector.rest_call('post', 'api/shares/dashboard/{}'.format(self.get_oid()), json_payload=current_shares, query_params=query_params)
def add_data_security_rule(self, table, column, data_type, *, shares=None, members=None, server_address=None, exclusionary=False, all_members=None): """Define a data security rule Args: table (str): The table to apply security on column (str): The column to apply security on data_type (str): The data type of the column shares (list[Group,User]): (Optional) The users or groups to assign the security rule to. If none, will be 'everyone else' rule. members (list[str]): (Optional) An array of values which users should have access to If left blank, user will get 'Nothing'. server_address (str): (Optional) The server address of the ElastiCube. Set this to your server ip if this method fails without it set. Use 'Set' for Elasticube Set. Required for elasticube sets. exclusionary (bool): (Optional) Set to True if exclusionary rule all_members (bool): (Optional) Set to True to set 'Everything' rule Returns: Rule: The new security rule """ server_address = server_address if server_address else self.server_address rule_json = [{ "column": column, "datatype": data_type, "table": table, "elasticube": self.get_title(), "server": server_address, "exclusionary": exclusionary, "allMembers": all_members }] shares_json = [] if shares is None: # Default rule rule_json[0]['shares'] = [{"type": "default"}] else: for party in PySenseUtils.make_iterable(shares): if isinstance(party, PySenseUser.User): shares_json.append({ 'party': party.get_id(), 'type': 'user' }) elif isinstance(party, PySenseGroup.Group): shares_json.append({ 'party': party.get_id(), 'type': 'group' }) else: raise PySenseException.PySenseException( '{} is not a user or a group object'.format(party)) rule_json[0]['shares'] = shares_json member_arr = [] if members is None: rule_json[0]['members'] = [] rule_json[0][ 'allMembers'] = False if all_members is None else all_members else: rule_json[0]['allMembers'] = None for member in members: member_arr.append(str(member)) rule_json[0]['members'] = member_arr resp_json = self.py_client.connector.rest_call( 'post', 'api/elasticubes/{}/{}/datasecurity'.format( server_address, self.get_title(url_encoded=True)), json_payload=rule_json) return PySenseRule.Rule(self.py_client, resp_json[0])
def get_users(self, *, user_name=None, email=None, first_name=None, last_name=None, role=None, group=None, active=None, origin=None, ids=None, fields=[], sort=None, skip=None, limit=None, expand=None): """Returns a list of users. Results can be filtered by parameters such as username and email. The expandable fields for the user object are groups, adgroups and role. Args: user_name (str): (Optional) Username to filter by email (str): (Optional) Email to filter by first_name (str): (Optional) First name to filter by last_name (str): (Optional) Last name to filter by role (Role): (Optional) SisenseRole enum for the role of the user to filter by group (Group): (Optional) Group to filter by active (bool): (Optional) User state to filter by (true for active users, false for inactive users) origin (str): (Optional) User origin to filter by (ad for active directory or sisense) ids (list[str]): (Optional) User ids to get fields (list[str]): (Optional) An array of fields to return for each document. Fields can also define which fields to exclude by prefixing field names with - sort (str): (Optional) Field by which the results should be sorted. Ascending by default, descending if prefixed by - skip (int): (Optional) Number of results to skip from the start of the data set. Skip is to be used with the limit parameter for paging limit (int): (Optional) How many results should be returned. limit is to be used with the skip parameter for paging expand (list[str]): (Optional) List of fields that should be expanded May be nested using the resource.subResource format Returns: list[User]: Users found """ fields = PySenseUtils.make_iterable(fields) # Ensure we get the fields we need to manage the user even if fields is set fields.extend( ['_id', 'lastLogin', 'groups', 'email', 'userName', 'firstName', 'lastName', 'roleId', 'preferences'] ) fields = list(dict.fromkeys(fields)) query_params = { 'userName': user_name, 'email': email, 'firstName': first_name, 'lastName': last_name, 'role': self.get_role_id(role), 'group': None if group is None else group.get_id(), 'active': active, 'origin': origin, 'ids': ids, 'fields': fields, 'sort': sort, 'skip': skip, 'limit': limit, 'expand': expand } ret_arr = [] resp_json = self.connector.rest_call('get', 'api/v1/users', query_params=query_params) for user in resp_json: ret_arr.append((PySenseUser.User(self, user))) return ret_arr
def update_rule(self, *, table=None, column=None, data_type=None, shares='', members='', exclusionary='', all_members=''): """Updates the current rule. Any arguments given will replace the current value and update the rule in place Args: shares (list[User,Group]): (Optional) Array of users and groups to share the rule with table (str): (Optional) Table of the data security rule column (str): (Optional) Column of the data security rule data_type (str): (Optional) Data security rule data type members (list[str]): (Optional) The values to specify in the rule. If blank, will use nothing exclusionary (bool): (Optional) Set to true to make an exclusionary rule all_members (bool): (Optional) Set to true for a rule to allow user to see all values """ rule_json = { "column": column if column is not None else self.get_column(), "datatype": data_type if data_type is not None else self.get_data_type(), "table": table if table is not None else self.get_table(), "exclusionary": exclusionary if exclusionary != '' else self.get_exclusionary(), "allMembers": all_members if all_members != '' else self.get_all_members(), } shares_json = [] if shares != '': for party in PySenseUtils.make_iterable(shares): if isinstance(party, PySenseUser.User): shares_json.append({ 'party': party.get_id(), 'type': 'user' }) elif isinstance(party, PySenseGroup.Group): shares_json.append({ 'party': party.get_id(), 'type': 'group' }) rule_json['shares'] = shares_json else: rule_json['shares'] = self.get_shares_json() if members != '': if members is None: rule_json['members'] = [] rule_json[ 'allMembers'] = False if all_members == '' else all_members else: member_arr = [] for member in PySenseUtils.make_iterable(members): member_arr.append(str(member)) rule_json['members'] = member_arr rule_json['allMembers'] = None else: rule_json['members'] = self.get_members() resp_json = self.py_client.connector.rest_call( 'put', 'api/elasticubes/datasecurity/{}'.format(self.get_id()), json_payload=rule_json) self._reset(resp_json)
Sample script for building data models in sequence. Linux only To use this script update the following values: - wait_time_seconds: How often to poll for the current build status - build_type: The build type to perform (schema_changes, by_table, full, publish) Sample Config: https://github.com/nathangiusti/PySense/blob/master/Snippets/SampleConfig.yaml """ import time from PySense import PySense from PySense import PySenseUtils config_file_location = 'path//SampleConfig.yaml' wait_time_seconds = 5 build_type = 'full' py_client = PySense.authenticate_by_file(config_file_location) data_models = py_client.get_data_models() for data_model in PySenseUtils.make_iterable(data_models): build_task = data_model.start_build(build_type) print('Building data model {}'.format(data_model.get_title())) while build_task.get_status() not in ['done', 'failed']: time.sleep(wait_time_seconds) print('{} build status: {}'.format(data_model.get_title(), build_task.get_status()))