Esempio n. 1
0
    def _connect(self):
        url = self._get_http_ipmi_host() + self.URL_LOGIN

        cookies = self._get_console_cookies()
        headers = self._get_console_headers()
        data = self._get_console_data()

        self._session = requests.session()

        for count in range(5):
            text = self._post(url, data, cookies, headers).text
            parsed, retryable = self._parse_response(text)
            if not parsed and retryable and count < 4:
                log.info('Will retry after {} seconds'.format(count))
                time.sleep(count)
            else:
                break

        if not parsed:
            log.error('Failed to create session')
            sys.exit(10)

        session_token = parsed[0]['SESSION_COOKIE']
        if session_token == 'Failure_Session_Creation':
            log.error('Probably reached session limit')
            sys.exit(10)

        CSRF_token = parsed[0]['CSRFTOKEN']

        self.session_token = {'SessionCookie': session_token}
        self.CSRF_token = {'CSRFTOKEN': CSRF_token}
Esempio n. 2
0
    def session(self) -> SessionAPI:
        """
        Return a sessions to the MaaS server. Subsequent calls reuse the same
        connection
        """
        if self._session:
            return self._session

        log.info(f'Connecting to {self.api_url}')
        _, self._session = SessionAPI.connect(self.api_url,
                                              apikey=self.api_key)

        return self._session
Esempio n. 3
0
 def diagnostics(self):
     jobqueue_view = 'racadm jobqueue view -i {}'
     output = self._ssh('racadm techsupreport collect')
     jid = self._find_jid(output)
     log.info('Sleeping for 3 minutes to collect the TSR report')
     time.sleep(180)
     view_output = self._ssh(jobqueue_view.format(jid))
     self._confirm_job(view_output)
     output = self._ssh('racadm techsupreport export -l {}'.format(
         self.nfs_share))
     jid = self._find_jid(output)
     view_output = self._ssh(jobqueue_view.format(jid))
     self._confirm_job(view_output)
Esempio n. 4
0
    def ssh(self):
        status_command = ['chassis', 'power', 'status']
        if self.parsed_args.wait:
            if 'off' in self._execute(status_command, output=True):
                log.info('Waiting for machine to turn on...')

            while (1):
                if 'off' not in self._execute(status_command, output=True):
                    break

        host = self.oob_info['asset_tag']
        if not host:
            raise OobError('Cannot perform ssh without an asset tag')
        call(['ssh', host])
Esempio n. 5
0
    def refresh_firmware(self):
        custom_fields = {}
        firmwares = self._get_image_info()

        psus = []
        for firmware in firmwares:
            device_id = DEV_ID[firmware['DEV_TYPE']]
            version = firmware['CURIMG_VER']
            if device_id == 'BIOS':
                custom_fields['BIOS'] = version
            elif device_id == 'TSM':
                custom_fields['TSM'] = version
            elif device_id == 'PSU':
                psus.append('{}/{}: {}'.format(firmware['SLOT_NO'],
                                               firmware['DEV_IDENTIFIER'],
                                               version))

        custom_fields['PSU'] = ', '.join(sorted(psus))

        log.info('Patching custom fields: {}'.format(custom_fields))
        if not self.dcim.set_custom_fields(self.oob_info, custom_fields):
            log.error('Failed to refresh DCIM firmware versions')
Esempio n. 6
0
    def take_action(self, parsed_args):
        try:
            fetcher = firmware_fetchers[parsed_args.model]

        except KeyError as e:
            log.error('Unsupported device type: {}'.format(e))
            sys.exit(-1)

        result, downloads = fetcher().get()

        columns = ['component', 'name', 'version', 'date']
        values = [[item[col] for col in columns] for item in result]

        if parsed_args.download_to is None:
            return columns, values

        try:
            os.makedirs(parsed_args.download_to, exist_ok=True)
        except OSError as e:
            log.error('Could not create download directory: {}'.format(e))
            sys.exit(-1)

        for url in downloads:
            name = url[url.rfind('/') + 1:]
            file_name = os.path.join(parsed_args.download_to, name)
            log.info('Downloading {} to {}'.format(url, file_name))
            try:
                with open(file_name, 'wb') as fout:
                    fout.write(urllib.request.urlopen(url).read())
            except (urllib.error.URLError, OSError) as e:
                log.error('Failed: {}'.format(e))

            if parsed_args.innoextract and name.endswith('.exe'):
                log.info('Extracting with innoextract')
                self._execute_cmd(
                    ['innoextract', file_name, '-d', parsed_args.download_to])

        return columns, values
Esempio n. 7
0
    def factory_reset(self):
        args = self.parsed_args

        if not args.force:
            response = input('Factory reset? [y/N] ')
            if response != 'y':
                log.info('Aborted')
                return

        self._connect()
        log.info('Setting preserve config')
        r = self._get_rpc('setpreservecfg',
                          params={
                              'PRSRV_CFG': '0,0,0,0,0,0,0,0,0,0,0,',
                              'PRSRV_CFG_CNT': '11',
                              'PRSRV_SELECT': '0,1,2,3,4,5,6,7,8,9,10,',
                          })
        log.debug(r)

        log.info('Starting factory reset')
        r = self._get_rpc('setfactorydefaults')
        log.debug(r)

        log.info('Factory reset process started')
        if args.wait:
            begin = datetime.utcnow()
            while datetime.utcnow() < begin + timedelta(minutes=args.timeout):
                try:
                    url = self._get_http_ipmi_host() + self.URL_VALIDATE

                    answer = self._post(url, None, self.session_token,
                                        self.CSRF_token)
                    if answer.status_code == 200:
                        log.info('Done.')
                        return
                    log.debug(answer)
                except (requests.exceptions.ReadTimeout,
                        requests.exceptions.ConnectionError,
                        ConnectionResetError, BrokenPipeError):
                    log.info('In progress')

                time.sleep(10)
Esempio n. 8
0
    def firmware_upgrade_rpc(self):
        args = self.parsed_args
        handle = None

        if 1 in args.stages:
            log.info('Enter FW update mode')
            r = self._get_rpc('getenterfwupdatemode', params={'FWUPMODE': 1})
            log.debug(r)
            if r and 'HANDLE' in r[0]:
                handle = r[0]['HANDLE']
                log.info('Enter FW update mode: OK')
            else:
                log.fatal('Cannot enter FW update mode')
                sys.exit(-1)

        log.info('Update session handle: {}'.format(handle))

        if 2 in args.stages:
            handle = handle or args.handle
            log.info('Rearm firmware update timer')
            r = self._get_rpc('rearmfwupdatetimer',
                              params={'SESSION_ID': handle})
            log.debug(r)

            if r[0]['NEWSESSIONID'] == handle:
                log.info('Rearm firmware update timer: OK')

        if 3 in args.stages:
            handle = handle or args.handle
            if not hasattr(self, 'CSRF_token'):
                self._connect()

            log.info('Uploading firmware bundle')

            ipmi = self.oob_info['ipmi']
            url = ipmi + '/file_upload_firmware.html'
            r = requests.post(
                url,
                verify=False,
                cookies=self.session_token,
                headers=self.CSRF_token,
                files={'bundle?FWUPSessionid={}'.format(handle): args.bundle})

            log.debug(r.status_code)
            if r.status_code == 200:
                log.info('Uploading firmware bundle: OK')

        if 4 in args.stages:
            log.info('Get Bundle Upload Status')
            r = self._get_rpc('getbundleupldstatus')
            log.debug(r)

            if r == []:
                log.info('Get Bundle Upload Status: OK')

        if 5 in args.stages:
            log.info('Validate Bundle')
            r = self._get_rpc('validatebundle',
                              params={'BUNDLENAME': 'bundle_bkp.bdl'})
            log.debug(r)
            if r[0]['STATUS'] == 0:
                log.info('Validate Bundle: OK')

        if 6 in args.stages:
            log.info('Replace Bundle')
            r = self._get_rpc('replacebundlebkp')
            log.debug(r)
            if r[0]['STATUS'] == 0:
                log.info('Replace Bundle: OK')

        if 7 in args.stages:
            log.info('Checking for new firmware')
            r = self._get_rpc('getimageinfo')
            log.debug(r)

            def has_update(x):
                new, cur = x['NEWIMG_VER'], x['CURIMG_VER']
                try:
                    return version_tuple(new) > version_tuple(cur)
                except (TypeError, ValueError):
                    return new > cur

            to_update = next(filter(has_update, r), None)
            if to_update is None:
                log.info('No updates available')
                return
            else:
                log.info('Available update: {}'.format(to_update))

        if 8 in args.stages and to_update:
            handle = handle or args.handle
            log.info('Choose component update')
            r = self._get_rpc('setupdatecomp',
                              params={
                                  'UPDATE_FLAG': to_update['DEV_TYPE'],
                                  'UPDATE_CNT': 1,
                                  'FW_DEVICE_TYPE': to_update['DEV_TYPE'],
                                  'SLOT_NO': to_update['SLOT_NO'],
                                  'DEV_IDENTIFIER':
                                  to_update['DEV_IDENTIFIER'],
                                  'SESSION_ID': handle,
                              })
            log.debug(r)
            if r == []:
                log.info('Choose component update: OK')

        log.info('Firmware upgrade process started')

        if 9 in args.stages:
            begin = datetime.utcnow()
            while datetime.utcnow() < begin + timedelta(minutes=args.timeout):
                try:
                    r = self._get_rpc('getcompupdatestatus')
                    log.debug(r)
                    dev = next((x for x in r if self._matching(x, to_update)),
                               None)
                    log.debug(dev)
                    progress = (dev or {}).get('UPDATE_PERCENTAGE')
                    if progress is None:
                        log.info('Update in progress')
                    else:
                        log.info('Update progress: {}%'.format(progress))
                        if progress == 100:
                            log.info('Update complete!')
                            break
                except (ConnectionResetError, BrokenPipeError):
                    log.info('Update in progress')

                time.sleep(10)

        if 10 in args.stages:
            handle = handle or args.handle
            log.info('Exit FW update mode')
            r = self._get_rpc('getexitfwupdatemode',
                              params={
                                  'MODE': 0,
                                  'RNDNO': handle
                              })
            log.debug(r)
            if r == []:
                log.info('Exit FW update mode: OK')

        log.info('Done!')
Esempio n. 9
0
 def refresh_ipmi_address(self):
     addr = self._get_ipmi_address()
     custom_fields = {'IPMI': addr}
     log.info('Patching custom fields: {}'.format(custom_fields))
     if not self.dcim.set_custom_fields(self.oob_info, custom_fields):
         log.error('Failed to refresh IPMI')