def ssl_storages_from_arguments(connection, args): """Helper function to build list of storages from cli arguments""" identities = [] for storage in args.storage: if storage in (CLIENT_ANONYMOUS, CLIENT_STANDART): identities.append(IDENTITY_MAPPING[storage]) else: raise SAPCliError(f'Unknown storage: {storage}') for identity in args.identity: try: identities.append(Identity(*identity.split('/'))) except (ValueError, TypeError): # pylint: disable=raise-missing-from raise SAPCliError(f'Invalid identity format: {identity}') ssl_storages = [] for identity in identities: ssl_storage = SSLCertStorage(connection, identity.pse_context, identity.pse_applic) ssl_storages.append(ssl_storage) return ssl_storages
def lock(self): """Locks the object""" if self._lock is not None: raise SAPCliError(f'Object {self.uri}: already locked') resp = self._connection.execute( 'POST', self.uri, params=lock_params(LOCK_ACCESS_MODE_MODIFY), headers={ 'X-sap-adt-sessiontype': 'stateful', 'Accept': ', '.join([ 'application/vnd.sap.as+xml;charset=UTF-8;dataname=com.sap.adt.lock.result;q=0.8', 'application/vnd.sap.as+xml;charset=UTF-8;dataname=com.sap.adt.lock.result2;q=0.9' ]) }) if 'dataname=com.sap.adt.lock.Result' not in resp.headers[ 'Content-Type']: raise SAPCliError( f'Object {self.uri}: lock response does not have lock result\n' + resp.text) mod_log().debug(resp.text) # TODO: check encoding self._lock = re.match('.*<LOCK_HANDLE>(.*)</LOCK_HANDLE>.*', resp.text)[1] mod_log().debug('LockHandle=%s', self._lock)
def mimetype_to_version(mime): """Converts Object MIME type to a version string""" if not mime.startswith('application/vnd.sap.'): return None smcln = mime.rfind(';') if smcln != -1: ver = mime[smcln + 1:] if ver.startswith('version='): return ver.split('=')[1] plus = mime.rfind('+') if plus == -1: raise SAPCliError('not a version + xml mime: ' + mime) dot = mime.rfind('.', 0, plus) if dot == -1: raise SAPCliError('not a version + xml mime: ' + mime) ver = mime[dot + 2:plus] if ver.isdigit(): return ver return '0'
def run(connection, args): """Prints it out based on command line configuration. Exceptions: - SAPCliError: - when the given type does not belong to the type white list """ types = {'program': sap.adt.Program, 'class': sap.adt.Class, 'package': sap.adt.Package} try: typ = types[args.type] except KeyError: raise SAPCliError(f'Unknown type: {args.type}') aunit = sap.adt.AUnit(connection) obj = typ(connection, args.name) response = aunit.execute(obj) run_results = sap.adt.aunit.parse_run_results(response.text) if args.output == 'human': return print_results_to_stream(run_results, sys.stdout) if args.output == 'raw': return print_raw(response.text, run_results) if args.output == 'junit4': return print_junit4(run_results, args, sys.stdout) raise SAPCliError(f'Unsupported output type: {args.output}')
def putcertificate(connection, args): """Uploads X.509 Base64 certificates into SAP to enable SSL peer verification of remote servers Exceptions: - SAPCliError: - when the given storage does not belong to the storage white list - when identity argument has invalid format """ identities = [] for storage in args.storage: if storage in (CLIENT_ANONYMOUS, CLIENT_STANDART): identities.append(IDENTITY_MAPPING[storage]) else: raise SAPCliError(f'Unknown storage: {storage}') for identity in args.identity: try: identities.append(Identity(*identity.split('/'))) except (ValueError, TypeError): # pylint: disable=raise-missing-from raise SAPCliError('Invalid identity format') ssl_storages = [] for identity in identities: ssl_storage = SSLCertStorage(connection, identity.pse_context, identity.pse_applic) if not ssl_storage.exists(): ssl_storage.create( alg=args.algorithm, keylen=args.key_length, dn=args.dn ) logging.debug('SSL Storage is OK: %s', ssl_storage) ssl_storages.append(ssl_storage) for file_path in args.paths: logging.info('Processing the file: %s', file_path) with open(file_path, 'rb') as cert_file: cert_contents = cert_file.read() for ssl_storage in ssl_storages: logging.info('Adding the file: %s to %s', file_path, ssl_storage) logging.info(ssl_storage.put_certificate(cert_contents)) logging.info('Notifying ICM ... ') notify_icm_changed_pse(connection) for updated_storage in ssl_storages: logging.info('Certificates of %s:', str(updated_storage)) for cert in iter_storage_certificates(updated_storage): logging.info('* %s', cert['EV_SUBJECT'])
def run(connection, args): """Prints it out based on command line configuration. Exceptions: - SAPCliError: - when the given type does not belong to the type white list """ types = { 'program': sap.adt.Program, 'class': sap.adt.Class, 'package': sap.adt.Package, 'transport': TransportObjectSelector } try: typ = types[args.type] except KeyError: raise SAPCliError(f'Unknown type: {args.type}') obj = typ(connection, args.name) sets = sap.adt.objects.ADTObjectSets() if args.type == 'transport': testable = obj.get_testable_objects(args.as4user) if not testable: sap.cli.core.printerr('No testable objects found') return 1 for tr_obj in testable: sets.include_object(tr_obj) else: sets.include_object(obj) aunit = sap.adt.AUnit(connection) response = aunit.execute(sets) run_results = sap.adt.aunit.parse_run_results(response.text) if args.output == 'human': return print_results_to_stream(run_results, sys.stdout) if args.output == 'raw': return print_raw(response.text, run_results) if args.output == 'junit4': return print_junit4(run_results, args, sys.stdout) if args.output == 'sonar': return print_sonar(run_results, args, sys.stdout) raise SAPCliError(f'Unsupported output type: {args.output}')
def print_acoverage_output(args, acoverage_response, root_node, statement_responses): """Prints ACoverage output in selected format and console""" if args.coverage_output not in ('raw', 'human', 'jacoco'): raise SAPCliError(f'Unsupported output type: {args.coverage_output}') coverage_file = None if args.coverage_filepath: # pylint: disable=consider-using-with coverage_file = open(args.coverage_filepath, 'w+', encoding='utf8') console = sap.cli.core.PrintConsole(out_file=coverage_file, err_file=coverage_file) else: console = sap.cli.core.get_console() if args.coverage_output == 'raw': print_acoverage_raw(acoverage_response.text, console) elif args.coverage_output == 'human': print_acoverage_human(root_node, console) elif args.coverage_output == 'jacoco': print_acoverage_jacoco(root_node, statement_responses, args, console) if coverage_file is not None: coverage_file.close()
def iso_code_to_sap_code(iso_code: str) -> str: """Coverts ISO codes to one letter SAP language codes""" try: return next((entry[1] for entry in CODE_LIST if entry[0] == iso_code)) except StopIteration: raise SAPCliError(f'Not found ISO Code: {iso_code}')
def run(connection, args): """Prints it out based on command line configuration. Exceptions: - SAPCliError: - when the given type does not belong to the type white list """ types = {'program': sap.adt.Program, 'class': sap.adt.Class, 'package': sap.adt.Package} try: typ = types[args.type] except KeyError: raise SAPCliError(f'Unknown type: {args.type}') objects = sap.adt.objects.ADTObjectSets() objects.include_object(typ(connection, args.name)) if args.variant is None: settings = sap.adt.atc.fetch_customizing(connection) args.variant = settings.system_check_variant mod_log().info('Variant: %s', args.variant) checks = sap.adt.atc.ChecksRunner(connection, args.variant) results = checks.run_for(objects, max_verdicts=args.max_verdicts) return print_worklist_to_stream(results.worklist, sys.stdout, error_level=args.error_level)
def get_testable_objects(self, user=None): """Returns the list of all objects which can potentially have Unit tests and are included in the give transport. """ types = { 'PROG': sap.adt.Program, 'CLAS': sap.adt.Class, 'FUGR': sap.adt.FunctionGroup } mod_log().info('Fetching the transport or task %s', self._number) workbench = sap.adt.cts.Workbench(self._connection) transport = workbench.fetch_transport_request(self._number, user=user) if transport is None: raise SAPCliError(f'The transport was not found: {self._number}') result = [] for task in transport.tasks: for abap_object in task.objects: mod_log().debug('? %s %s', abap_object.type, abap_object.name) try: # TODO: get rid of the need to create the instances! result.append(types[abap_object.type](self._connection, abap_object.name)) mod_log().info('+ %s %s', abap_object.type, abap_object.name) except KeyError: pass return result
def release(connection, args): """Releases the CTS request of the passed type and number.""" try: factory = { 'transport': partial(WorkbenchTransport, None), 'task': partial(WorkbenchTask, None, None) }[args.type] except KeyError as ex: raise SAPCliError( f'Internal error: unknown request type: {args.type}') from ex else: request = factory(connection, args.number) if args.recursive: sap.cli.core.printout( f'Fetching details of {args.number} because of recursive execution' ) request.fetch() sap.cli.core.printout(f'Releasing {args.number}') report = request.release(recursive=args.recursive) sap.cli.core.printout(str(report)) return 0
def get_declaration(self, handler): """Returns the command declaration for the handler""" try: return self.declarations[handler.__name__] except KeyError as ex: raise SAPCliError( f'No such Command Declaration: {handler.__name__}') from ex
def get_uri_for_type(self, mimetype): """Mimic ADTObjectType's implementation""" if mimetype != 'text/plain': raise SAPCliError( f'Class Source code can be only of "text/plain": {mimetype}') return self.source_uri
def get_uri_for_type(self, mimetype): """Returns and an ADT URL fragment for the given MIME type. """ try: return '/' + self._typeuris[mimetype] except KeyError: raise SAPCliError( 'Object {type} does not support plain \'text\' format')
def open_editor(self, instance, lock_handle, corrnr=None): """Returns a new instance of Editor for this object type and raises SAPCliError if the object type does not allow modifications. """ if self._editor_factory is None: raise SAPCliError( f'Object {self._code}: modifications are not supported') return self._editor_factory(instance, lock_handle, corrnr=corrnr)
def sap_code_to_iso_code(sap_code: str) -> str: """Coverts one letter SAP language codes to ISO codes. Raises sap.errors.SAPCliError if the give sap_code is not identified. """ try: return next((entry[0] for entry in CODE_LIST if entry[1] == sap_code)) except StopIteration: raise SAPCliError(f'Not found SAP Language Code: {sap_code}')
def release(connection, args): """Releases the CTS request of the passed type and number.""" try: factory = {'transport': partial(WorkbenchTransport, None), 'task': partial(WorkbenchTask, None, None)}[args.type] except KeyError: raise SAPCliError(f'Internal error: unknown request type: {args.type}') else: request = factory(connection, args.number) request.release()
def add_command(self, handler, name=None): """Adds a new command""" fname = handler.__name__ if fname in self.declarations: raise SAPCliError(f'Handler already registered: {fname}') cmd = CommandDeclaration(handler, name if name is not None else fname) self.declarations[fname] = cmd return cmd
def unlock(self): """Locks the object""" if self._lock is None: raise SAPCliError(f'Object {self.uri}: not locked') self._connection.execute('POST', self.uri, params=unlock_params(self._lock), headers={ 'X-sap-adt-sessiontype': 'stateful', }) self._lock = None
def find_mime_version(connection, objtype): """Returns the supported/required MIME version of the given objtype by the given connection. """ mimes = connection.get_collection_types(objtype.basepath, objtype.mimetype) seri_mime = next((mime for mime in mimes if mime in objtype.all_mimetypes), None) if seri_mime is None: raise SAPCliError('Not supported mimes: {} not in {}'.format( ';'.join(mimes), ';'.join(objtype.all_mimetypes))) version = mimetype_to_version(seri_mime) return (seri_mime, version)
def serialize(self): """Creates a text representation""" mimes = self._connection.get_collection_types(self.objtype.basepath, self.objtype.mimetype) seri_mime = next( (mime for mime in mimes if mime in self.objtype.all_mimetypes), None) if seri_mime is None: raise SAPCliError('Not supported mimes: {} not in {}'.format( ';'.join(mimes), ';'.join(self.objtype.all_mimetypes))) version = mimetype_to_version(seri_mime) marshal = sap.adt.marshalling.Marshal(object_schema_version=version) return (marshal.serialize(self), seri_mime)
def print_acoverage_output(args, acoverage_response, root_node, statement_responses): """Prints ACoverage output in selected format and stream""" if args.coverage_output not in ('raw', 'human', 'jacoco'): raise SAPCliError(f'Unsupported output type: {args.coverage_output}') stream = open(args.coverage_filepath, 'w+') if args.coverage_filepath else sys.stdout if args.coverage_output == 'raw': print_acoverage_raw(acoverage_response.text, stream) elif args.coverage_output == 'human': print_acoverage_human(root_node, stream) elif args.coverage_output == 'jacoco': print_acoverage_jacoco(root_node, statement_responses, args, stream) if args.coverage_filepath: stream.close()
def activate(self): """Activate the object""" # pylint: disable=no-member request = f'''<?xml version="1.0" encoding="UTF-8"?> <adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core"> <adtcore:objectReference adtcore:uri="/{self.connection.uri}/{self.uri}" adtcore:name="{self.name.upper()}"/> </adtcore:objectReferences>''' resp = self._connection.execute('POST', 'activation', params=activation_params(), headers={ 'Accept': 'application/xml', 'Content-Type': 'application/xml' }, body=request) if resp.text: raise SAPCliError( f'Could not activate the object {self.name}: {resp.text}')
def listcertificates(connection, args): """Lists X.509 Base64 certificates currently installed in SAP system Exceptions: - SAPCliError: - when the given storage does not belong to the storage white list - when identity argument has invalid format """ ssl_storages = ssl_storages_from_arguments(connection, args) for ssl_storage in ssl_storages: if not ssl_storage.exists(): raise SAPCliError( f'Storage for identity {ssl_storage.identity} does not exist') for cert in ssl_storage.get_certificates(): cert = ssl_storage.parse_certificate(cert) printout('*', cert['EV_SUBJECT'])
def print_aunit_output(args, aunit_response, aunit_parsed_response): """Prints AUnit output in selected format and stream""" result = None run_results = aunit_parsed_response.run_results if args.output == 'human': result = print_aunit_human(run_results, sys.stdout) elif args.output == 'raw': result = print_aunit_raw(aunit_response.text, run_results, sys.stdout) elif args.output == 'junit4': result = print_aunit_junit4(run_results, args, sys.stdout) elif args.output == 'sonar': result = print_aunit_sonar(run_results, args, sys.stdout) else: raise SAPCliError(f'Unsupported output type: {args.output}') return result
def create(connection, args): """Create CTS request""" try: factory = { 'transport': partial(WorkbenchTransport, None), 'task': partial(WorkbenchTask, None, None) }[args.type] except KeyError as ex: raise SAPCliError( f'Internal error: unknown request type: {args.type}') from ex else: request = factory(connection, None, owner=connection.user, description=args.description, target=args.target) response = request.create() sap.cli.core.printout(response.number) return 0
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 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 find_service(self, service_name=None, service_version=None): """Returns a first service matching the given parameters. If any parameter is None, the parameter is not considered for comparison. """ if service_name and service_version: return next((item for item in self.services if item.definition.name == service_name and item.version == service_version), None) if service_name is not None: return next((item for item in self.services if item.definition.name == service_name), None) if service_version is not None: return next( (item for item in self.services if item.version == service_version), None) raise SAPCliError( "You must specify either Service Name or Service Version or both")
def dumpcertificates(connection, args): """Dumps X.509 Base64 certificates currently installed in SAP system Exceptions: - SAPCliError: - when the given storage does not belong to the storage white list - when identity argument has invalid format """ ssl_storages = ssl_storages_from_arguments(connection, args) for ssl_storage in ssl_storages: if not ssl_storage.exists(): raise SAPCliError( f'Storage for identity {ssl_storage.identity} does not exist') for cert in ssl_storage.get_certificates(): c_b64 = base64.b64encode(cert) printout('-----BEGIN CERTIFICATE-----') printout(c_b64.decode('ascii')) printout('-----END CERTIFICATE-----')