def __init__(self): if DummyChild.instances is None: DummyChild.instances = list() DummyChild.instances.append(self) get_logger().debug('New instance') self._attribute = None
def _new_entry(self): """Creates new list item""" get_logger().debug('Adding new Inactive Object Entry') entry = IOCEntry() self.entries.append(entry) return entry
def try_activate(adt_object): """Activates the given object and returns CheckResults with the activation results. """ request = ADTObjectReferences() request.add_object(adt_object) resp = _send_activate(adt_object, request, activation_params(pre_audit_requested=True)) if 'application/vnd.sap.adt.inactivectsobjects.v1+xml' in resp.headers.get( 'Content-Type', ''): ioc = Marshal.deserialize(resp.text, IOCList()) get_logger().debug(ioc.entries) request = ADTObjectReferences([ entry.object.reference for entry in ioc.entries if entry.object is not None and entry.object.deleted == 'false' ]) resp = _send_activate(adt_object, request, activation_params(pre_audit_requested=False)) results = CheckResults() if resp.text: Marshal.deserialize(resp.text, results) return (results, resp)
def characters(self, content): if self.handler is None: return get_logger().debug('Trying to set text for the current handler: "%s"', content) self.handler.append_text(content)
def delete(self, recursive=False): """Deletes Request""" if recursive: self._delete_children() get_logger().info('Deleting CTS request: %s', self.number) self._connection.execute('DELETE', self.uri)
def _delete_children(self): """Deletes tasks of transport""" get_logger().info('Deleting tasks of transport: %s', self.number) for task in self.tasks: if task.is_released: continue task.delete(recursive=True)
def __init__(self, service, host, port, client, user, password, ssl, verify): """Parameters: - service: id of the odata service (e.g. UI5/ABAP_REPOSITORY_SRV) - host: string host name or IP of - port: string TCP/IP port for abap application server - client: string SAP client - user: string user name - password: string user password - ssl: boolean to switch between http and https - verify: boolean to switch SSL validation on/off """ if ssl: protocol = 'https' if port is None: port = '443' else: protocol = 'http' if port is None: port = '80' self._base_url = f'{protocol}://{host}:{port}/sap/opu/odata/{service}' self._query_args = f'sap-client={client}&saml2=disabled' self._user = user self._auth = HTTPBasicAuth(user, password) self._timeout = config_get('http_timeout') self._session = requests.Session() self._session.verify = verify self._session.auth = (user, password) # csrf token handling for all future "create" requests try: get_logger().info( 'Executing head request as part of CSRF authentication %s', self._base_url) req = requests.Request('HEAD', self._base_url, headers={'x-csrf-token': 'fetch'}) req = self._session.prepare_request(req) res = self._session.send(req, timeout=self._timeout) except requests.exceptions.ConnectTimeout as ex: raise TimedOutRequestError(req, self._timeout) from ex if res.status_code == 401: raise UnauthorizedError(req, res, self._user) if res.status_code >= 400: raise HTTPRequestError(req, res) token = res.headers.get('x-csrf-token', '') self._session.headers.update({'x-csrf-token': token}) # instance of the service self.client = pyodata.Client(self._base_url, self._session)
def _reassign_children(self, newowner): """Changes owner of child objects""" get_logger().info('Reassigning tasks of transport: %s', self.number) for task in self.tasks: if task.is_released: continue task.reassign(newowner, recursive=True)
def load_definitions(self, obj): """Examines annotations of the current object""" attributes = dict() for attr_name in obj.__class__.__ordered__: if attr_name.startswith('__'): continue attr = getattr(obj.__class__, attr_name) if isinstance(attr, XmlElementProperty): xml_path = f'{self.my_xpath}/{attr.name}' if not attr.deserialize: get_logger().debug( 'Found readonly XML element property: %s -> %s', attr_name, xml_path) continue if attr.kind == XmlElementKind.TEXT: get_logger().debug( 'Found Text XML element property: %s -> %s', attr_name, xml_path) self.elements[xml_path] = ElementHandler( xml_path, self.elements, factory=lambda: obj, textproperty=attr) continue get_logger().debug('Found XML element property: %s -> %s', attr_name, xml_path) factory = attr.factory if factory is None: factory = partial(attr.__get__, obj) if attr.fset is not None: factory = partial(factory_with_setter, factory, attr.__set__, obj) self.elements[xml_path] = ElementHandler( xml_path, self.elements, factory) elif isinstance(attr, XmlAttributeProperty): if not attr.deserialize: get_logger().debug( 'Found readonly XML attribute property: %s -> %s', attr_name, attr.name) continue get_logger().debug('Found XML attribute property: %s -> %s', attr_name, attr.name) attributes[attr.name] = attr return attributes
def run(self): """Creates the business catalog""" get_logger().info('Running the cleanup') for catalog in self._config['catalogs']: self._build_catalog(catalog) for group in self._config['groups']: self._buid_group(group, self._config['catalogs'])
def cleanup(self): """Removes existing catalogs and groups according to the configuration""" get_logger().info('Removing previously created catalogs') for catalog in self._config['catalogs']: self._service.delete_catalog(catalog['id']) get_logger().info('Removing previously created groups') for group in self._config['groups']: self._service.delete_group(group['id'])
def _delete_object(self, obj): """Remove the selected object from the task""" get_logger().info('Deleting object: %s %s %s', obj.pgmid, obj.type, obj.name) self._connection.execute( 'PUT', self.uri, body=f'''<?xml version="1.0" encoding="ASCII"?> <tm:root xmlns:tm="http://www.sap.com/cts/adt/tm" tm:number="{self._number}" tm:useraction="removeobject"> <tm:request> <tm:abap_object tm:name="{obj.name}" tm:obj_desc="{escape(obj.description)}" tm:pgmid="{obj.pgmid}" tm:type="{obj.type}" tm:position="{obj.position}"/> </tm:request> </tm:root>''')
def reassign(self, newowner, recursive=False): """Changes the request's owner""" if recursive: self._reassign_children(newowner) get_logger().info('Reassigning CTS request: %s', self.number) self._connection.execute('PUT', self.uri, body=f'''<?xml version="1.0" encoding="ASCII"?> <tm:root xmlns:tm="http://www.sap.com/cts/adt/tm" tm:number="{self._number}" tm:targetuser="******" tm:useraction="changeowner"/>''')
def _build_tree(self, root, obj, declared_ns): """Convert ADT Object members to XML elements""" if obj is None: return get_logger().debug('Building tree for %s (%s)', str(obj), root.name) for attr_name in obj.__class__.__ordered__: if attr_name.startswith('_'): continue attr = getattr(obj.__class__, attr_name) if isinstance(attr, XmlElementProperty): if not _attr_supports_version(attr, self.version): get_logger().debug( 'Skipping class attribute %s for not supported version %s', attr.name, self.version) continue child = getattr(obj, attr_name) get_logger().debug('Serializing Child Element %s (%s)', attr.name, attr_name) self._serialize_object_to_node(root, attr.name, child, declared_ns, attr.kind) elif isinstance(attr, XmlAttributeProperty): if not _attr_supports_version(attr, self.version): get_logger().debug( 'Skipping class attribute %s for not supported version %s', attr.name, self.version) continue value = getattr(obj, attr_name) if value is not None: root.add_attribute(attr.name, value)
def set_text(self): """Sets the text value""" get_logger().debug('Going to set text') if self.textproperty is None: if self._textvalue is not None and not self._textvalue.isspace(): # TODO: potentially programming error raise MarshallingError() get_logger().debug('The property is not a text node') return self.textproperty.__set__(self.obj, self._textvalue)
def create(connection, args): """Creates the requested BSP application. Important: Target ABAP system needs following setup * update trnspace set editflag = 'X' role = 'P' license = '' sscrflag = 'X' where namespace = '/0CUST/' or namespace = '/0SAP/'. * table /IWFND/C_CONFIG je 'GATEWAY_VIRUSCAN_PROFILE'='-' """ # load zipped application from filesystem with open(args.app, 'rb') as file: app_data_archive = file.read() # convert raw zipped data to base54 encoding app_data_b64 = base64.b64encode(app_data_archive) # check if application exists try: connection.client.entity_sets.Repositories.get_entity( Name=args.bsp).execute() raise ResourceAlreadyExistsError except pyodata.exceptions.HttpError as ex: if ex.response.status_code != 404: raise ex app_data = { 'Name': args.bsp, 'Package': args.package, 'ZipArchive': app_data_b64.decode("utf-8"), } create_request = connection.client \ .entity_sets \ .Repositories \ .create_entity() \ .custom('CodePage', 'UTF8') \ .custom('TransportRequest', args.corrnr) \ .custom('client', args.client) create_request.set(**app_data) try: create_request.execute() except pyodata.exceptions.HttpError as ex: res = json.loads(ex.response.text) get_logger().info(pprint.pformat(res)) raise ex get_logger().info('BSP application successfully created and uploaded')
def append_text(self, chunk): """Appends text chunk""" get_logger().debug('Going to append text') if self.textproperty is None: if not chunk.isspace(): # TODO: potentially programming error raise MarshallingError() return self._textvalue += chunk get_logger().debug('Set text to: %s', self._textvalue)
def delete(connection, args): """Get information about BSP application""" try: connection.client \ .entity_sets \ .Repositories \ .delete_entity(Name=args.bsp) \ .custom('TransportRequest', args.corrnr) \ .execute() except pyodata.exceptions.HttpError as ex: if ex.response.status_code != 404: raise ex get_logger().info('BSP application successfully removed')
def _buid_group(self, group, catalogs): get_logger().info('Creating group: %s', group['title']) self._service.create_group({ 'id': group['id'], 'title': group['title'] }) for tile in group['tiles']: get_logger().info('Adding tile: %s', tile['title']) try: catalog_tile = _get_catalog_tile(catalogs, tile['catalog_id'], tile['catalog_tile_id']) except CatalogTileError as ex: raise SAPCliError( f"Failed to add tile {tile['title']} to group {group['title']}" ) from ex self._service.add_tile_to_group( group_id=group['id'], catalog_id=tile['catalog_id'], tile_id=catalog_tile['instance_id'])
def set(self, attr_name, value): """Sets object's property value""" get_logger().debug('Going to set XML attribute property: %s', attr_name) if self.textproperty is not None: # TODO: potentially programming error raise MarshallingError() try: self.attributes[attr_name].__set__(self.obj, value) get_logger().debug('Set XML attribute property: %s', attr_name) except AttributeError as ex: get_logger().error('XML property %s: %s', attr_name, str(ex)) except KeyError: get_logger().debug('Not an XML attribute property: %s', attr_name)
def activate(adt_object): """Activates the given object""" request = ADTObjectReferences() request.add_object(adt_object) resp = _send_activate(adt_object, request, activation_params(pre_audit_requested=True)) if 'application/vnd.sap.adt.inactivectsobjects.v1+xml' in resp.headers.get( 'Content-Type', ''): ioc = Marshal.deserialize(resp.text, IOCList()) get_logger().debug(ioc.entries) request = ADTObjectReferences([ entry.object.reference for entry in ioc.entries if entry.object is not None and entry.object.deleted == 'false' ]) resp = _send_activate(adt_object, request, activation_params(pre_audit_requested=False)) if resp.text: raise SAPCliError( f'Could not activate the object {adt_object.name}: {resp.text}')
def clear_text(self): """Clear text value""" get_logger().debug('Going to clear text') if self.textproperty is None: get_logger().debug('Not a text property') return self._textvalue = '' get_logger().debug('Set the text property to None')
def _build_catalog(self, catalog): get_logger().info('Creating catalog: %s', catalog['title']) self._service.create_catalog({ 'domainId': catalog['id'], 'title': catalog['title'] }) for target_mapping in catalog['target_mappings']: get_logger().info('Creating target mapping: %s', target_mapping['title']) self._service.create_mapping( catalog['id'], { 'tileConfiguration': { 'semantic_object': target_mapping['semantic_object'], 'semantic_action': target_mapping['semantic_action'], 'display_title_text': target_mapping['title'], 'url': target_mapping['url'], 'ui5_component': target_mapping['ui5_component'] } }) for tile in catalog['tiles']: get_logger().info('Creating tile: %s', tile['title']) tile_reference = self._service.create_tile( catalog['id'], { 'id': tile['id'], 'tileConfiguration': { 'display_icon_url': tile['icon'], 'display_title_text': tile['title'], 'display_subtitle_text': tile.get('subtitle', ''), 'display_info_text': tile.get('info', ''), 'navigation_semantic_object': tile['semantic_object'], 'navigation_semantic_action': tile['semantic_action'], 'navigation_target_url': tile.get( 'url', f"#{tile['semantic_object']}-{tile['semantic_action']}" ), }, 'title': tile['title'] }) tile['instance_id'] = tile_reference.instanceId
def startElement(self, name, attrs): self.stack.append(self.current) self.current = f'{self.current}/{name}' get_logger().debug('Encountered XML element: %s', self.current) try: self.handler = self.elements[self.current] except KeyError: return get_logger().debug('Deserializing element: %s', self.current) # this loads handlers for children elements!! /o\ self.handler.new() self.handler.clear_text() for attr_name, value in attrs.items(): get_logger().debug('Encountered XML attribute: %s', attr_name) try: self.handler.set(attr_name, value) except KeyError: pass
def mod_log(): """ADT Module logger""" return get_logger()
def _delete_children(self): """Deletes objects of task""" get_logger().info('Deleting objects of task: %s', self.number) for obj in self.objects: self._delete_object(obj)
def mod_log(): """ACoverage Statements Module logger""" return get_logger()
def child_setter(self, value): get_logger().debug('Set instance') self._child_setter = value
def child_setter(self): get_logger().debug('Get instance') return self._child_setter
def mod_log(): """AUnit module logger""" return sap.get_logger()