Esempio n. 1
0
def ispf_in_out(request):
    user = username
    if hasattr(request, 'param'):
        user = request.param

    em = Emulator(hostname, model=2, oversize=(24, 80))
    ispf = ISPF(em, username=user, password=password)
    d = ispf.em.display
    d('6', key=keys.ENTER)
    d(text=f"ALTLIB ACTIVATE APPL(CLIST) DA('{rtes[rte]['clist']}')",
      key=keys.ENTER)
    d('%KOCLIST', key=keys.ENTER)
    assert d.find('OCALIST - INVOCATION MENU')

    appl = d.find_by_label('OBVTAM APPL ===>')
    appl(text=applid, key=keys.NEWLINE)
    d(cics_job)
    option = d.find_by_label('OPTION  ===>')
    option('2', key=keys.ENTER)

    d(user, keys.NEWLINE)
    d(password, keys.ENTER)

    assert d.find('ZMENU    VTS')
    yield d
    d(key=keys.PF3)
    d('X', key=keys.ENTER)
    d('X', key=keys.ENTER)
    ispf.logoff()
def tso_in_out(request):
    copy_clist('tso')
    user = username
    if hasattr(request, 'param'):
        user = request.param

    em = Emulator(hostname, model=2, oversize=(24, 80))
    ispf = ISPF(em, username=user, password=password)
    try:
        d = ispf.em.display
        d(key=keys.PF3)
        d(text=f"ALTLIB ACTIVATE APPL(CLIST) DA('{rtes[rte]['clist']}')",
          key=keys.ENTER)
        d(text='%KOI', key=keys.ENTER)
        assert d.find('LOGGING ONTO OMEGAMON/IMS VTAM APPLICATION UNDER TSO')
        d(key=keys.ENTER)

        d(user, keys.NEWLINE)
        d(password, keys.ENTER)

        assert d.find('ZMENU    VTT     OI-II')
        yield d
        d(key=keys.PF3)
        d('X', key=keys.ENTER)
        d('ispf', key=keys.ENTER)
    finally:
        ispf.logoff()
def ispf():
    em = Emulator(hostname, model=2, oversize=(62, 160))
    ispf = ISPF(em, username=username, password=password)
    sdsf = ispf.start('s.log')
    d = sdsf.emulator.display()
    yield d
    ispf.logoff()
def test_ispf_logon(rte_setup):
    """
    After https://jira.rocketsoftware.com/browse/OMBS-936
    we get TSO mode, actually
    :return:
    """
    rte = rte_setup
    em = Emulator(rtes[rte]['hostname'], model=2, oversize=(24, 80))
    ispf = ISPF(em, username=username, password=password)
    d = ispf.em.display
    d(key=keys.PF3)
    assert d.find('READY')
    d(text="ALTLIB ACTIVATE APPL(CLIST) DA('ITM.ITE.QA.CLIST')",
      key=keys.ENTER)
    d('KOMSPFSI', key=keys.ENTER)
    assert d.find('KOMSPFSI\n READY')
    d('ispf', key=keys.ENTER)
    assert d.find('ISPF Primary Option Menu')
    d('6', key=keys.ENTER)
    d(text="ALTLIB ACTIVATE APPL(CLIST) DA('ITM.ITE.QA.CLIST')",
      key=keys.ENTER)
    d('TSO KOMSPFSX', key=keys.ENTER)
    assert d.find('Please press ENTER to begin')
    d(key=keys.ENTER)
    assert d.find('ZMENU    TSO     OM/DEX')
    d(key=keys.PF3)
    d('X', key=keys.ENTER)
    ispf.logoff()
def test_no_informational_message_during_start(rte):
    # parm-487
    em = Emulator(hostname, model=2, oversize=(24, 80))
    ispf = ISPF(em, username=username, password=password)
    tkancus = f"{rtes[rte]['hlq']}.TKANCUS".upper()
    try:
        d = ispf.em.display
        d('3.4').enter()
        d.find_by_label('Dsname Level . . .')('', keys.ERASEEOF)(tkancus).enter()
        d.find(f'        {tkancus}')('ex').enter()
        assert not d.find('For informational purposes only')
        assert d.find('KCIPQPGW')
    finally:
        ispf.logoff()
Esempio n. 6
0
    def logon(self):
        if self.ispf is None:
            emulator = Emulator(self.exec_host, model=2, oversize=(62, 160))
            try:
                self.ispf = ISPF(emulator=emulator,
                                 target=self.exec_host,
                                 model=2,
                                 username=self.username,
                                 password=self.password)
                display = self.ispf.em.display
            except:
                emulator.close()
                raise ParmException('LOGON problem')
            display.wait(10, 'ISPF Primary Option Menu')
            display.find_by_label('===>')('3.4').enter()
            gbl_hlq = ''
            try:
                gbl_hlq = rtes[self.rte.lower()]['gbl_hlq']
            except:
                gbl_hlq = self.hlq
            tkancus = f'{gbl_hlq}.TKANCUS'.upper()
            display.find_by_label('Dsname Level . . .')(
                '', keys.ERASEEOF)(tkancus).enter()
            display.find(f'        {tkancus}')('ex').enter()
            display.find_by_label('===>')('3').enter()
            if display.find('KCIP@TLV'):
                display.find_by_label('GBL_TARGET_HILEV:')(
                    '', keys.ERASEEOF)(gbl_hlq).enter()
            # there are 2 3270 fields for GBL_USER_JCL (no idea why), so find_by_label doesn't work
            display.find('GBL_USER_JCL:')('')
            display.cursor = display.cursor[0], display.cursor[1] + 16
            display('', keys.ERASEEOF)(f'{self.hlq}.PARMGEN.JCL')
            display.find_by_label('RTE_PLIB_HILEV:')('',
                                                     keys.ERASEEOF)(self.hlq)
            display.find_by_label('RTE_NAME:')('', keys.ERASEEOF)(
                self.rte).enter()

            if self.is_new:
                # if not display.find('You have asked to configure a new RTE profile.'):
                #   raise ParmException('Incorrect panel')
                display('').enter()
            if not display.find('KCIPQPGB'):
                raise ParmException('Incorrect panel')
            else:
                self.d = display
def tso_in_out(request, rte_setup):
    rte = rte_setup
    user = username
    if hasattr(request, 'param'):
        user = request.param

    em = Emulator(rtes[rte]['hostname'], model=2, oversize=(24, 80))
    ispf = ISPF(em, username=user, password=password)
    d = ispf.em.display
    d(key=keys.PF3)
    d(text=f"ex '{rtes[rte]['rte_hlq']}.RKANSAMU(KOMCLSTE)'", key=keys.ENTER)
    assert d.find('Please press ENTER to begin')
    d(key=keys.ENTER)
    assert d.find('ZMENU    TSO     OM/DEX')
    yield d
    d(key=keys.PF3)
    d('X', key=keys.ENTER)
    d('ispf', key=keys.ENTER)
    ispf.logoff()
def test_ispf_logon_with_komspf_is_disabled(rte_setup):
    """
    After https://jira.rocketsoftware.com/browse/OMBS-936
    full ISPF is disabled
    :return:
    """
    rte = rte_setup
    em = Emulator(rtes[rte]['hostname'], model=2, oversize=(24, 80))
    ispf = ISPF(em, username=username, password=password)
    d = ispf.em.display
    d('6', key=keys.ENTER)
    d(text="ALTLIB ACTIVATE APPL(CLIST) DA('ITM.ITE.QA.CLIST')",
      key=keys.ENTER)
    d('komspf', key=keys.ENTER)
    d('3', key=keys.ENTER)
    if d.find('KOMSPF - KEY ASSIGNMENT PANEL'):
        d(key=keys.ENTER)
    assert d.find('OB1230 Full ISPF mode is not supported')
    d(key=keys.ENTER)
    d('x', key=keys.ENTER)
    ispf.logoff()
Esempio n. 9
0
def tso_in_out(request):
    user = username
    if hasattr(request, 'param'):
        user = request.param

    em = Emulator(hostname, model=2, oversize=(24, 80))
    ispf = ISPF(em, username=user, password=password)
    d = ispf.em.display
    try:
        d(key=keys.PF3)
        d(text=f"ALTLIB ACTIVATE APPL(CLIST) DA('{rtes[rte]['clist']}')",
          key=keys.ENTER)
        d(text='%KOCLIST', key=keys.ENTER)

        d(user, keys.NEWLINE)
        d(password, keys.ENTER)

        assert d.find('ZMENU    VTT')
        yield d
        d(key=keys.PF3)
        d('X', key=keys.ENTER)
        d('ispf', key=keys.ENTER)
    finally:
        ispf.logoff()
Esempio n. 10
0
def test_all_products_available_in_jobgen(rte):
    # parm-487
    em = Emulator(hostname, model=2, oversize=(62, 160))
    ispf = ISPF(em, username=username, password=password)
    tkancus = f"{rtes[rte]['hlq']}.TKANCUS".upper()
    try:
        d = ispf.em.display
        d('3.4').enter()
        d.find_by_label('Dsname Level . . .')('', keys.ERASEEOF)(tkancus).enter()
        d.find(f'        {tkancus}')('ex').enter()
        assert d.find('KCIPQPGW')
        d('2').enter()
        if d.find('KCIP@TLV'):
            d(rtes[rte]['rte_hlq'][:-5]).enter()
        assert d.find('KCIPJG00')
        d(f'{username}.PARM.TEST.TMP').enter()
        # collect products from first screen
        all_products = str(d)
        # go to the next page
        d('', keys.PF8)
        all_products = all_products + str(d)
        assert all((prod in all_products for prod in products.split('\n')))
    finally:
        ispf.logoff()
Esempio n. 11
0
def test_run_omegamon_z_os_tso_KOMCLSTE_without_abend():
    '''
    https://jira.rocketsoftware.com/browse/OMBS-1457

    Omegamon z/OS TSO KOMCLSTE does not have abend S0C4-04 KOBAS510 after running.
    It is reproduced only on ite4.
    '''
    em = Emulator('rsd4', model=2, oversize=(24, 80))
    ispf = ISPF(em, username=username, password=password)
    rte = 'ite4'
    try:
        d = ispf.em.display
        d.find_by_label('===>')('=xall').enter()
        d.find('READY')
        abend = 'OB0933 OMEGAMON resource cleanup initiated for abend S0C4  RC=00000004'
        d(f"exec '{rtes[rte]['rte_hlq']}.RKANSAMU(KOMCLSTE)'").enter()
        assert not d.find(abend)
        d('', key=keys.PF3)
        d.find('READY')
        d(f"exec '{rtes[rte]['rte_hlq']}.RKANSAMU(KOMCLIST)'").enter()
        assert not d.find(abend)
    finally:
        ispf.em.disconnect()
        ispf.em.close()
Esempio n. 12
0
def ispf(request):
    em = Emulator(hostname, model=2, oversize=(62, 160))
    ispf = ISPF(em, username=username, password=password)
    yield ispf
    ispf.logoff()
Esempio n. 13
0
def ispf(request):
    em = request.param(target=target)
    ispf = ISPF(em, username=username, password=password)
    yield ispf
    ispf.logoff()
Esempio n. 14
0
class Parmgen(ParmBase):
    def __init__(self,
                 username: str,
                 password: str,
                 hlq: str,
                 rte: str,
                 is_new: bool = False,
                 rte_model: str = '',
                 rte_products: List[str] = None,
                 rte_type: int = None):
        """
        :param username: TSO username
        :param password: TSO password
        :param hlq: hlq of the csi, e.g. itm.itd
        :param rte: rte name
        :param is_new: new or old
        """
        self.username = username.upper()
        self.password = password
        self.hlq = hlq.upper()
        self.rte = rte.upper()
        self.step_results = {}
        self.is_new = is_new
        self.original_config = ''
        self.variables_config = ''
        self.rte_type = rte_type if not None else rtes[rte]['type']
        self.time = datetime.datetime.now().strftime('%Y/%m/%d')
        self.z = zOSMFConnector(self.exec_host, username, password)
        self.jobname = None
        self.step_results: Dict[str:Dict[str:int]] = {}
        self.ispf = None
        self.d = None
        self.all_jobs = set()
        self.changed_parameters = []
        self.rte_model = rte_model
        self.middle_hlq = self.hlq.split('.')[1]
        if rte_products is None:
            self.rte_products = []
        else:
            self.rte_products = rte_products

        self.CONFIG_FOR_PRODUCTS = {
            'KC5': self.update_config_for_kc5,
            'KDS': self.update_config_for_kds,
            'KD5': self.update_config_for_kd5,
            'KGW': self.update_config_for_kgw,
            'KI5': self.update_config_for_ki5,
            'KJJ': self.update_config_for_kjj,
            'KMQ': self.update_config_for_kmq,
            'KM5': self.update_config_for_km5,
            'KN3': self.update_config_for_kn3,
            'KOB': self.update_config_for_kob,
            'KQI': self.update_config_for_kqi,
            'KS3': self.update_config_for_ks3,
        }

    def relocate_libs(self):
        """
        Relocate some libs to make space bigger and prevent E37-04
        :return:
        """
        libs = []
        for lib in self.LIBS_FOR_RELOCATE.keys():
            if self.rte_type == RteType.SHARED and lib in self.BASE_LIBS:
                add_lib = f"{self.hlq}.BASE.{lib}\n     {self.LIBS_FOR_RELOCATE[lib]}"
                libs.append(add_lib)
            else:
                add_lib = f"{self.hlq}.{self.rte}.{lib}\n     {self.LIBS_FOR_RELOCATE[lib]}"
            libs.append(add_lib)
        libs = '\n'.join(libs)
        job = self.z.submit(
            self.REALLOC_JCL.replace('{hlq}',
                                     self.hlq).replace('{libs}', libs))

    def check_on_screen(self, text, exception_text):
        if not self.d.find(text):
            raise ParmException(exception_text)

    def delete_another_rte(self, rte_to_delete: str) -> bool:
        """
        Make sure, we do it after "logon".
        We go 1 screen back, use ? to list all RTEs, use D to start deletion.
        Then we add wait step to the job, submit it and, exit from pargen, check results.
        Wait is needed to have time for exit, otherwise RKANSAMU lib is locked by us.
        :param rte_to_delete:
        :return:
        """
        rte_to_delete = rte_to_delete.upper()
        if self.rte == rte_to_delete:
            raise ParmException(
                'You are trying to delete current RTE, this is impossible!')
        d = self.d
        self.check_on_screen('KCIPQPGB', 'Incorrect panel')
        d(key=keys.PF3)
        self.check_on_screen('KCIPQPGA', 'Incorrect panel')
        d.find_by_label('RTE_NAME:')('', keys.ERASEEOF)('?').enter()
        d.find_by_label(rte_to_delete, label_pos=LABEL_RIGHT)('d').enter()
        self.check_on_screen('WARNING! WARNING!', 'No expected message')
        d.enter()
        # parially created RTE is deleted right away, w/o job
        if d.find('KCIR@DEL: Function:    Delete an RTE.'):
            d.enter()
            d(key=keys.PF3)
            d(key=keys.PF3)
            return True

        wait_step = [
            "//WAITXMIN   EXEC PGM=BPXBATCH,REGION=0M,",
            "//  PARM='sh sleep 15s'",
            "//STDIN    DD DUMMY",
            "//STDOUT   DD SYSOUT=*",
            "//STDERR   DD SYSOUT=*",
            "/*",
        ]
        # we replace comments with this additional step
        start_row_chars = '000020 //*'
        # by any reason, maybe we already updated this job
        if d.find(start_row_chars):
            y1, x1 = get_text_position(start_row_chars, d=d)
            x1 = x1 + len(start_row_chars) - 3
            for row in range(0, len(wait_step)):
                d.cursor = y1 + row, x1
                d('', keys.ERASEEOF)(wait_step[row])
        if not d.find('//WAITXMIN'):
            raise ParmException('Delete job is invalid')
        # get current jobname
        self.jobname = d.find(regex=r'(?<=//)\w+(?= JOB)').visible_only
        exist_list_jobs = self.z.list_jobs(prefix=self.jobname,
                                           owner=self.username)

        d.find_by_label('===>')('sub').enter()
        if not d.find(regex=rf'JOB\s+\w+\(\w+\)\s+SUBMITTED'):
            logger.info(d)
            raise ParmException('Submit error')
        d.enter()
        d.find_by_label('===>')('cancel').enter()
        if d.find('Data set has been changed'):
            d.enter()
        # exiting from parmgen
        d(key=keys.PF3)
        d(key=keys.PF3)
        d(key=keys.PF3)

        self.set_step_results('delete_rte', exist_list_jobs, 0)
        d.find_by_label('===>').enter()
        self.check_on_screen('MAXCC=0000', 'Job fails')
        d.enter()

    def update_config_for_rte(self):
        params = {'RTE_X_STC_INAPF_INCLUDE_FLAG': 'Y'}
        if self.rte_model in self.VARS_MODELS:
            params['RTE_XKAN_HILEV'] = f'{self.hlq}.{self.rte}.&SYSPLEX.'
        else:
            params['RTE_XKAN_HILEV'] = f'{self.hlq}.{self.rte}.RSPLEXL4'
        self.change_parameters(params)

        # update variables
        if self.rte_model in self.VARS_MODELS:
            self.change_parameters_in_dataset(
                self.z, f'{self.hlq}.PARMGEN.JCL({self.rte})',
                {'RTE_USS_RTEDIR': f'/proj/omivt/{self.middle_hlq.lower()}'})
        # update $GBL$USR
        glbusr = f'''GBL_DSN_SYS1_PARMLIB         ITM.{self.middle_hlq}.ROCKET.PARMLIB  
GBL_DSN_SYS1_SAXREXEC        ITM.{self.middle_hlq}.ROCKET.SAXREXEC 
GBL_DSN_SYS1_PROCLIB         ITM.{self.middle_hlq}.ROCKET.PROCLIB  
GBL_DSN_SYS1_VTAMLIB         ITM.{self.middle_hlq}.ROCKET.VTAMLIB  
GBL_DSN_SYS1_VTAMLST         ITM.{self.middle_hlq}.ROCKET.VTAMLST  
GBL_USS_TKANJAR_PATH "/proj/omivt/{self.middle_hlq.lower()}/usr/lpp/kan/bin/IBM"
GBL_HFS_JAVA_DIR1 "/rsusr/java/IBM/J7.1"  
GBL_DSN_DB2_LOADLIB_V11      "RSRTE.DSN.VB10.SDSNLOAD"   
GBL_DSN_DB2_LOADLIB_V12      "RSRTE.DSN.VC10.SDSNLOAD"   
GBL_DSN_DB2_RUNLIB_V11       "RSRTE.DSN.VB10.RUNLIB.LOAD" 
GBL_DSN_DB2_RUNLIB_V12       "RSRTE.DSN.VC10.RUNLIB.LOAD" 
GBL_DSN_DB2_DSNEXIT          "IDS4.SDSNEXIT"              
'''
        self.append_lines_into_dataset(
            self.z, f'{self.hlq}.{self.rte}.WCONFIG($GBL$USR)', glbusr)

    def update_config_for_kc5(self):
        pass

    def update_config_for_kds(self):
        pass

    def update_config_for_kd5(self):
        params = {'KD2_DB01_DB2_VER': '12'}
        self.change_parameters(params)

    def update_config_for_kgw(self):
        pass

    def update_config_for_ki5(self):
        lines = f'''KI2_I1                            BEGIN          
KI2_I101_ROW                      01             
KI2_I101_CLASSIC_IMSID            IFK1
KI2_I101_CLASSIC_MPREFIX          M0  
KI2_I101_CLASSIC_GLOBAL           00  
KI2_I101_CLASSIC_STC        {self.rte}OI0 
KI2_I101_CLASSIC_VTAM_NODE  {self.rte}OI0N             
KI2_I101_CLASSIC_VTAM_APPL_LOGON  {self.rte}OI0        
KI2_I101_CLASSIC_IMS_RESLIB IMS.IFK1.SDFSRESL    
KI2_I101_CLASSIC_LROWS            999            
KI2_I101_CLASSIC_USER_PROFILE     /C             
KI2_I101_CLASSIC_CTRL_UNIT_ADDR   XXXX           
KI2_I102_ROW                      02             
KI2_I102_CLASSIC_IMSID            IEK1
KI2_I102_CLASSIC_MPREFIX          M1  
KI2_I102_CLASSIC_GLOBAL           00  
KI2_I102_CLASSIC_STC        {self.rte}OI1 
KI2_I102_CLASSIC_VTAM_NODE  {self.rte}OI1N             
KI2_I102_CLASSIC_VTAM_APPL_LOGON  {self.rte}OI1        
KI2_I102_CLASSIC_IMS_RESLIB IMS.IEK1.SDFSRESL    
KI2_I102_CLASSIC_LROWS            999            
KI2_I102_CLASSIC_USER_PROFILE     /C             
KI2_I102_CLASSIC_CTRL_UNIT_ADDR   XXXX           
KI2_I1                            END            '''
        self.append_parameters(lines,
                               '**KI2_I1                            END')

    def update_config_for_kjj(self):
        pass

    def update_config_for_kmq(self):
        pass

    def update_config_for_km5(self):
        params = {'GBL_SYSPLEX_NAME_XCFPLEXGROUP': f'{self.rte}RSD4'}
        if self.rte_model in self.VARS_MODELS:
            params[
                'KM5_PDS_RKM5PLX_PLEXDATA_HILEV'] = f'{self.hlq}.{self.rte}.&SYSPLEX.'
        else:
            params[
                'KM5_PDS_RKM5PLX_PLEXDATA_HILEV'] = f'{self.hlq}.{self.rte}.RSPLEXL4'
        self.change_parameters(params)

    def update_config_for_kn3(self):
        params = {
            'KN3_TCPX01_SYS_NAME': '$$$$ ',
            'KN3_TCPX01_TCP_STC': '$$$$$$$$',
            'KN3_TCPX01_OVRD_ZERT': 'Y',
        }
        self.change_parameters(params)

    def update_config_for_kob(self):
        pass

    def update_config_for_kqi(self):
        params = {
            'KQI_XML_XIMBNAME_MON_BRKR_NAME': 'Q191BRK',
            'KQI_XML_XIMBDIR1': '/u/ibstc/q191brk',
            'KQI_HFS_HFSROOT_DIR1': f'/proj/omivt/{self.middle_hlq.lower()}',
        }
        self.change_parameters(params)

    def update_config_for_ks3(self):
        params = {
            'KS3_AS_LISTENER_ADDR': '"192.168.54.121"',
            'KS3_NODEJS_HOME': '/rsusr/cnj/IBM/node-v6.14.4-os390-s390x',
        }
        self.change_parameters(params)

    def logon(self):
        if self.ispf is None:
            emulator = Emulator(self.exec_host, model=2, oversize=(62, 160))
            try:
                self.ispf = ISPF(emulator=emulator,
                                 target=self.exec_host,
                                 model=2,
                                 username=self.username,
                                 password=self.password)
                display = self.ispf.em.display
            except:
                emulator.close()
                raise ParmException('LOGON problem')
            display.wait(10, 'ISPF Primary Option Menu')
            display.find_by_label('===>')('3.4').enter()
            gbl_hlq = ''
            try:
                gbl_hlq = rtes[self.rte.lower()]['gbl_hlq']
            except:
                gbl_hlq = self.hlq
            tkancus = f'{gbl_hlq}.TKANCUS'.upper()
            display.find_by_label('Dsname Level . . .')(
                '', keys.ERASEEOF)(tkancus).enter()
            display.find(f'        {tkancus}')('ex').enter()
            display.find_by_label('===>')('3').enter()
            if display.find('KCIP@TLV'):
                display.find_by_label('GBL_TARGET_HILEV:')(
                    '', keys.ERASEEOF)(gbl_hlq).enter()
            # there are 2 3270 fields for GBL_USER_JCL (no idea why), so find_by_label doesn't work
            display.find('GBL_USER_JCL:')('')
            display.cursor = display.cursor[0], display.cursor[1] + 16
            display('', keys.ERASEEOF)(f'{self.hlq}.PARMGEN.JCL')
            display.find_by_label('RTE_PLIB_HILEV:')('',
                                                     keys.ERASEEOF)(self.hlq)
            display.find_by_label('RTE_NAME:')('', keys.ERASEEOF)(
                self.rte).enter()

            if self.is_new:
                # if not display.find('You have asked to configure a new RTE profile.'):
                #   raise ParmException('Incorrect panel')
                display('').enter()
            if not display.find('KCIPQPGB'):
                raise ParmException('Incorrect panel')
            else:
                self.d = display

    def logoff(self):
        logger.info(f'{self.rte}: {self.step_results}')
        if self.ispf is not None:
            self.ispf.logoff()
            self.ispf = None
            self.d = None

    def before(self):
        if not self.is_new:
            self.z.del_ds(f'{self.hlq}.{self.rte}.WCONFIG(KOB$PENV)')

    def get_step_result(self):
        return self.step_results

    def set_step_results(self, func, exist_list_jobs, rc):
        list_jobs = self.z.list_jobs(prefix=self.jobname, owner=self.username)
        for job in exist_list_jobs:
            list_jobs.pop(job, None)
        while any(job['status'] != 'OUTPUT' for job in list_jobs.values()):
            time.sleep(5)
            list_jobs = self.z.list_jobs(prefix=self.jobname,
                                         owner=self.username)
            for job in exist_list_jobs:
                list_jobs.pop(job, None)
        current_jobs = set(list_jobs.keys()) - self.all_jobs
        self.all_jobs = set(list_jobs.keys())
        for job in current_jobs:
            rc_code = re.search(r'\d+', list_jobs[job]['retcode'])[0]
            if int(rc_code) <= rc:
                self.step_results[func] = {
                    job: list_jobs[job]['retcode']
                    for job in current_jobs
                }
            elif 'step_4_7' in func and rc_code == '0256':
                self.step_results[func] = {
                    job: list_jobs[job]['retcode']
                    for job in current_jobs
                }
            else:
                raise ParmException(f'RC code {rc_code} in {job}')

    def submit_and_check(self, func, rc: int):
        """
        :param func: step name
        :param rc: max rc
        :return:
        """
        d = self.d
        if self.jobname is None:
            self.jobname = d.find(regex=r'(?<=//)\w+(?= JOB)').visible_only
        exist_list_jobs = self.z.list_jobs(prefix=self.jobname,
                                           owner=self.username)
        d.find_by_label('===>')('sub').enter()
        # wait some time to make sure, job is really submitted
        time.sleep(15)
        if not d.find(regex=rf'JOB\s+{self.jobname}\(\w+\)\s+SUBMITTED'):
            logger.info(d)
            raise ParmException('Submit error')
        self.set_step_results(func, exist_list_jobs, rc)
        d.enter()
        d.enter()
        d(key=keys.PF3)
        self.check_on_screen('KCIP@PGP', 'Incorrect panel')

    def step_1_set_up(self):
        self.jobname = f"KCIJ{random.randint(1, 9999):04d}"
        self.before()
        d = self.d
        d.find_by_label('===>')('1').enter()
        if d.find('KCIP@MSG'):
            d.enter()
        self.check_on_screen('KCIPQPG1', 'Incorrect panel')
        if self.is_new:
            d.find_by_label('==>')('?')
            d.enter()
            self.check_on_screen('KCIPQMDL', 'Incorrect panel')
            d.find_by_label(self.rte_model, label_pos=LABEL_RIGHT)('s').enter()
        else:
            # clear path to config
            d.find_by_label('==>')(
                '',
                keys.ERASEEOF)(f'{self.hlq}.{self.rte}.WCONFIG({self.rte})')
        if d.find('==> _______\n==> _______'):
            # jobcard is empty, press enter to fill it in
            d.enter()
        d.find_all_by_label('==>')[1](f'//{self.jobname}').enter()
        self.check_on_screen('KCIP@PG2', 'Incorrect panel')
        d.enter()
        self.check_on_screen('KCIP@PG3', 'Incorrect panel')
        if self.is_new:
            if self.rte_type == RteType.SHARED:
                d.find_by_label('RTE_X_HILEV_SHARING:')('', keys.ERASEEOF)(
                    self.hlq)
                d.find_by_label('RTE_SHARE:')('', keys.ERASEEOF)('BASE')
            d.find_by_label('RTE_X_SECURITY_EXIT_LIB:')(
                '', keys.ERASEEOF)(f'{self.hlq}.{self.rte}.RKANSAMU')
            d.find_by_label('RTE_VTAM_APPLID_PREFIX:')(
                '', keys.ERASEEOF)(f'{self.rte}')
            d.find_by_label('RTE_STC_PREFIX:')('',
                                               keys.ERASEEOF)(f'{self.rte}')
        d.enter()
        self.check_on_screen('KCIP@PGI', 'Incorrect panel')
        if self.is_new:
            # clear products selection
            y1, _ = get_text_position('Kpp  Component', d=d)
            y2, x2 = get_text_position('End of data', d=d)
            for y in range(y1 + 2, y2):
                d.cursor = y, x2
                d(' ')
            # choose products
            for product in self.rte_products:
                d.find_by_label(product, label_pos=LABEL_RIGHT)('/')
        d.enter()
        d('Y').enter()
        if d.find(
                'KCIP@BAK IMPORTANT - REFRESH THE LPAR RTE USER AND IBM PROFILES'
        ):
            d.find_by_label('==>')(self.rte).enter()
        self.submit_and_check('step_1_set_up', rc=0)
        d(key=keys.PF3)
        self.check_on_screen('KCIPQPGB', 'Incorrect panel')
        if d.find(regex=r'KCIJPCFG\s+RC=(\s+)0{5}(\s+)' + self.time):
            self.step_results['step_1_set_up']['result'] = True
        else:
            self.step_results['step_1_set_up']['result'] = False
        if 'KS3' in self.rte_products:
            self.CONFIG_FOR_PRODUCTS['KS3']()

    def submit_step(self, steps, workspace, jobname, rc):
        d = self.d
        func = f'step_{steps[0]}_{steps[1]}'
        for step in steps:
            d.find_by_label('===>')(str(step)).enter()
        if d.find('KCIP@PGP'):
            d.enter()
        if d.find('KCIP@SEC'):
            d(key=keys.PF3)
        self.submit_and_check(func, rc)
        d(key=keys.PF3)
        self.check_on_screen(workspace, 'Incorrect panel')
        if jobname in ['KCIJPW1R', 'KCIJPW2R']:
            # need to zoom to get details for this step
            d('12').enter()
        if (str(steps[0]) + '_' + str(steps[1]) != '3_1' and self.rte_model in self.VARS_MODELS) \
                or self.rte_model not in self.VARS_MODELS:
            self.find_step_result(steps, jobname, rc)

    @private
    def find_step_result(self, steps, jobname, rc):
        d = self.d
        func = f'step_{steps[0]}_{steps[1]}'
        try:
            time.sleep(10)
            rc_code = d.find(regex=r'(?<=' + jobname.replace('$', '\\$') +
                             r').*?(?=' + self.time + r')').visible_only
            rc_code = re.search(r'\d+', rc_code)[0]
            if int(rc_code) <= rc:
                self.step_results[func]['result'] = True
            else:
                self.step_results[func]['result'] = False
        except:
            logger.info(d)
            raise ParmException('Job result is not found')
        finally:
            if jobname in ['KCIJPW1R', 'KCIJPW2R']:
                d(key=keys.PF3)
            if (jobname != '$PARSEDV' and self.rte_model in self.VARS_MODELS
                ) or self.rte_model not in self.VARS_MODELS:
                d(key=keys.PF3)

    def change_parameters(self,
                          params: Dict[str, str],
                          variables: Dict[str, str] = None,
                          dataset: str = None):
        """
        :param params: key=value pair to update in wconfig(<rte>)
        :param variables: key=value pair to update in variables config
        :param dataset: variables config
        :return:
        """
        if variables:
            self.change_parameters_in_dataset(self.z, dataset, variables)
        self.change_parameters_in_dataset(
            self.z, f'{self.hlq}.{self.rte}.WCONFIG({self.rte})', params)

    def remove_parameters(self,
                          removed_params: Dict[str, List[str]],
                          dataset: str = None):
        """
        :param removed_params: dict of two keys - list: 'parameters' and 'masks_params', and values: all parameters
         to remove of wconfig(<rte>)
        :param dataset: variables config
        :return:
        """
        self.change_parameters_in_dataset(
            self.z,
            dataset=f'{self.hlq}.{self.rte}.WCONFIG({self.rte})',
            params={},
            removed_params=removed_params['parameters'],
            masks_params=removed_params['masks_params'])

    def append_parameters(self,
                          params: Union[str, List[str]],
                          start_line: str = None):
        """
        :param params: List of lines to add into  wconfig(<rte>)
        :param start_line: after which line we need to add params or to the end
        :return:
        """
        self.append_lines_into_dataset(
            self.z, f'{self.hlq}.{self.rte}.WCONFIG({self.rte})', params,
            start_line)

    @private
    def go_to_params_clone_panel(self, product_code, section, base_section_id,
                                 target_section_id):
        d = self.d
        d(key=keys.PF16)
        d.find('KCIP@PM2')
        d.find_by_label('Repeating section (sc) =')(section)
        d.find_by_label('Base section ID   (ID) =')(base_section_id)
        d.find_by_label('Target section ID (ID) =')(target_section_id)
        d.find_by_label('Include comments       =')('Y')
        d.find_by_label('Product code      (pp) =')(product_code).enter()

    def save_config(self, dataset: str = None):
        if dataset:
            self.variables_config = self.z.read_ds(dataset)
        self.original_config = self.z.read_ds(
            f'{self.hlq}.{self.rte}.WCONFIG({self.rte})')
        return self.original_config, self.variables_config

    def restore_config(self, dataset: str = None):
        if dataset:
            self.z.write_ds(dataset, self.original_config)
        self.z.write_ds(f'{self.hlq}.{self.rte}.WCONFIG({self.rte})',
                        self.original_config)
        return self.original_config, self.variables_config

    def get_config(self, dataset: str = None):
        if dataset:
            config_file = self.z.read_ds(dataset)
        else:
            config_file = self.z.read_ds(
                f'{self.hlq}.{self.rte}.WCONFIG({self.rte})')
        return config_file

    def include_parameters(self,
                           product_code,
                           section,
                           base_section_id: str = '01',
                           target_section_id: str = '02'):
        click_count = 0
        if not self.d:
            self.logon()
        else:
            while not self.d.find('KCIPQPGB') and click_count < 10:
                self.d(key=keys.PF3)
                click_count += 1
        d = self.d
        if d.find('KCIPQPGB'):
            d.find_by_label('===>')('2').enter()
            d.find_by_label('===>')('1').enter()
            d.enter()
            self.go_to_params_clone_panel(product_code, section,
                                          base_section_id, target_section_id)
            if not d.find(product_code + '_' + section + target_section_id +
                          '_'):
                raise ParmException('Parameters did not included in config')
            d(key=keys.PF3)
            d(key=keys.PF3)
        else:
            raise ParmException('Could not logon to primary panel')

    def step_2_customize(self):
        d = self.d
        d.find_by_label('===>')('2').enter()
        d.find_by_label('===>')('1').enter()
        d.enter()
        d(key=keys.PF3)
        d(key=keys.PF3)
        # if new, we need to update several configs
        if self.is_new:
            self.update_config_for_rte()
            for product in self.rte_products:
                self.CONFIG_FOR_PRODUCTS[product]()

    def step_3_1_parse(self):
        self.submit_step(steps=(3, 1),
                         workspace='KCIP@PR1',
                         jobname='$PARSE',
                         rc=4)

    def step_3_parse_with_variables(self):
        self.submit_step(steps=(3, 1),
                         workspace='KCIP@PR1',
                         jobname='$PARSESV',
                         rc=4)
        self.submit_step(steps=(3, 2),
                         workspace='KCIP@PR1',
                         jobname='$PARSEDV',
                         rc=4)
        self.find_step_result(steps=(3, 1), jobname='$PARSESV', rc=4)

    def step_4_1_composite_sub(self):
        self.submit_step(steps=(4, 1),
                         workspace='KCIP@SUB',
                         jobname='KCIJPSUB',
                         rc=0)

    def step_4_2_allocate_ds(self):
        self.submit_step(steps=(4, 2),
                         workspace='KCIP@SUB',
                         jobname='KCIJPALO',
                         rc=2)

    def step_4_3_copy_smpe_members(self):
        self.relocate_libs()
        self.submit_step(steps=(4, 3),
                         workspace='KCIP@SUB',
                         jobname='KCIJPLOD',
                         rc=4)

    def step_4_4_run_product(self):
        # compress RKANMODU library first
        self.z.submit(
            self.COMPRESS_JCL.replace('#DS#',
                                      f'{self.hlq}.{self.rte}.RKANMODU'))
        self.submit_step(steps=(4, 4),
                         workspace='KCIP@SUB',
                         jobname='KCIJPSEC',
                         rc=0)

    def step_4_5_update_var_name(self):
        self.submit_step(steps=(4, 5),
                         workspace='KCIP@SUB',
                         jobname='KCIJPUPV',
                         rc=4)

    def step_4_6_create_uss(self):
        self.submit_step(steps=(4, 6),
                         workspace='KCIP@SUB',
                         jobname='KCIJPUSP',
                         rc=0)

    def step_4_7_copy_uss(self):
        self.submit_step(steps=(4, 7),
                         workspace='KCIP@SUB',
                         jobname='KCIJPUSS',
                         rc=0)

    def step_4_8_copy_runtime_members_to_sys1(self):
        self.submit_step(steps=(4, 8),
                         workspace='KCIP@SUB',
                         jobname='KCIJPSYS',
                         rc=0)

    def step_4_9_run_post_smpe(self):
        self.submit_step(steps=(4, 9),
                         workspace='KCIP@SUB',
                         jobname='KCIJPLNK',
                         rc=0)

    def step_4_10_verify_jobs(self):
        # this job can abend because of B37 on TEMP datasets but we can't control them, so set rc=20 as acceptable
        self.submit_step(steps=(4, 10),
                         workspace='KCIP@SUB',
                         jobname='KCIJPIVP',
                         rc=20)

    def step_4_11_backup_rk_libs(self):
        self.submit_step(steps=(4, 11),
                         workspace='KCIP@SUB',
                         jobname='KCIJPCPR',
                         rc=0)

    def step_4_12_copy_replace_files_from_wk(self):
        self.submit_step(steps=(4, 12, 1),
                         workspace='KCIP@SUB',
                         jobname='KCIJPW2R',
                         rc=0)

    def step_4_12_empty_rk_ds_and_copy(self):
        self.submit_step(steps=(4, 12, 2),
                         workspace='KCIP@SUB',
                         jobname='KCIJPW1R',
                         rc=0)

    def full_update(self, change_params: bool = False):
        logger.info(f'Full update of {self.rte}')
        if not change_params:
            self.step_1_set_up()
        if self.is_new:
            self.step_2_customize()
        if self.rte_model in self.VARS_MODELS:
            self.step_3_parse_with_variables()
        else:
            self.step_3_1_parse()
        self.step_4_2_allocate_ds()
        self.step_4_3_copy_smpe_members()
        self.step_4_4_run_product()
        if self.rte_model in self.VARS_MODELS:
            self.step_4_5_update_var_name()
        self.step_4_6_create_uss()
        self.step_4_7_copy_uss()
        self.step_4_8_copy_runtime_members_to_sys1()
        self.step_4_9_run_post_smpe()
        self.step_4_10_verify_jobs()
        self.step_4_11_backup_rk_libs()
        self.step_4_12_copy_replace_files_from_wk()
        self.step_4_12_empty_rk_ds_and_copy()
        return self.result()

    def partial_update(self) -> bool:
        logger.info(f'Partial update of {self.rte}')
        self.step_1_set_up()
        self.step_3_1_parse()
        self.step_4_2_allocate_ds()
        self.step_4_4_run_product()
        self.step_4_6_create_uss()
        self.step_4_7_copy_uss()
        self.step_4_8_copy_runtime_members_to_sys1()
        self.step_4_9_run_post_smpe()
        self.step_4_11_backup_rk_libs()
        return self.result()

    def result(self) -> bool:
        return all(v['result'] for v in self.step_results.values())