Пример #1
0
 def _parse_array_spec(self, arrayspec):
     controller = None
     if arrayspec.disks:
         for disk in list(arrayspec.disks) + list(arrayspec.hotspares):
             if controller is None:
                 controller = disk.id[0]
             if controller != disk.id[0]:
                 raise pygexc.UnsupportedFunctionality(
                     'Cannot span arrays across controllers')
         raidmap = self._raid_number_map(controller)
         if not raidmap:
             raise pygexc.InvalidParameterValue(
                 'There are no available drives for a new array')
         requestedlevel = str(arrayspec.raid).lower()
         if requestedlevel not in raidmap:
             raise pygexc.InvalidParameterValue(
                 'Requested RAID "{0}" not available on this '
                 'system with currently available drives'.format(
                     requestedlevel))
         rdinfo = raidmap[str(arrayspec.raid).lower()]
         rdlvl = str(rdinfo[0])
         defspan = 1 if rdinfo[1] == 1 else 2
         spancount = defspan if arrayspec.spans is None else arrayspec.spans
         drivesperspan = str(len(arrayspec.disks) // int(spancount))
         hotspares = arrayspec.hotspares
         drives = arrayspec.disks
         if hotspares:
             hstr = '|'.join([str(x.id[1]) for x in hotspares]) + '|'
         else:
             hstr = ''
         drvstr = '|'.join([str(x.id[1]) for x in drives]) + '|'
         pth = '/api/function/raid_conf?params=raidlink_CheckConfisValid'
         args = [
             pth, controller, rdlvl, spancount, drivesperspan, drvstr, hstr
         ]
         url = ','.join([str(x) for x in args])
         rsp = self.wc.grab_json_response(url)
         if rsp['items'][0]['errcode'] == 16:
             raise pygexc.InvalidParameterValue('Incorrect number of disks')
         elif rsp['items'][0]['errcode'] != 0:
             raise pygexc.InvalidParameterValue(
                 'Invalid configuration: {0}'.format(
                     rsp['items'][0]['errcode']))
         return {
             'capacity': rsp['items'][0]['freeCapacity'],
             'controller': controller,
             'drives': drvstr,
             'hotspares': hstr,
             'raidlevel': rdlvl,
             'spans': spancount,
             'perspan': drivesperspan,
         }
     else:
         pass  # TODO: adding new volume to existing array would be here
Пример #2
0
 def set_ntp_server(self, server, index=0):
     if self.has_tsm:
         if not (0 <= index <= 1):
             raise pygexc.InvalidParameterValue("Index must be 0 or 1")
         cmddata = bytearray((1 + index, ))
         cmddata += server.ljust(128, '\x00')
         self.ipmicmd.xraw_command(netfn=0x32, command=0xa8, data=cmddata)
         return True
     elif self.is_fpc:
         if not 0 <= index <= 2:
             raise pygexc.InvalidParameterValue(
                 'SMM supports indexes 0 through 2')
         self.smmhandler.set_ntp_server(server, index)
         return True
     return None
Пример #3
0
 def decode_pet(self, specifictrap, petdata):
     if isinstance(specifictrap, int):
         specifictrap = struct.unpack('4B', struct.pack('>I', specifictrap))
     if len(specifictrap) != 4:
         raise pygexc.InvalidParameterValue(
             'specifictrap should be integer number or 4 byte array')
     specifictrap = bytearray(specifictrap)
     sensor_type = specifictrap[1]
     event_type = specifictrap[2]
     # Event Offset is in first event data byte, so no need to fetch it here
     # evtoffset = specifictrap[3] & 0b1111
     deassertion = (specifictrap[3] & 0b10000000) == 0b10000000
     # alertseverity = petdata[26]
     sensorid = petdata[28]
     event_data = petdata[31:34]
     event = {}
     seqnum = struct.unpack_from('>H', buffer(petdata[16:18]))[0]
     ltimestamp = struct.unpack_from('>I', buffer(petdata[18:22]))[0]
     petack = bytearray(
         struct.pack('<HIBBBBBB', seqnum, ltimestamp, petdata[25],
                     petdata[27], sensorid, *event_data))
     try:
         self._ipmicmd.xraw_command(netfn=4, command=0x17, data=petack)
     except pygexc.IpmiException:  # Ignore failure to ack for now
         pass
     self._populate_event(deassertion, event, event_data, event_type,
                          sensor_type, sensorid)
     event['timecode'] = ltimestamp
     _fix_sel_time((event, ), self._ipmicmd)
     return event
Пример #4
0
 def set_power(self, powerstate, wait=False):
     if powerstate == 'boot':
         oldpowerstate = self.get_power()['powerstate']
         powerstate = 'on' if oldpowerstate == 'off' else 'reset'
     reqpowerstate = powerstate
     if powerstate not in powerstates:
         raise exc.InvalidParameterValue(
             "Unknown power state %s requested" % powerstate)
     powerstate = powerstates[powerstate]
     result = self.wc.grab_json_response_with_status(
         self.powerurl, {'ResetType': powerstate})
     if result[1] < 200 or result[1] >= 300:
         raise exc.PyghmiException(result[0])
     if wait and reqpowerstate in ('on', 'off', 'softoff', 'shutdown'):
         if reqpowerstate in ('softoff', 'shutdown'):
             reqpowerstate = 'off'
         timeout = os.times()[4] + 300
         while (self.get_power()['powerstate'] != reqpowerstate
                and os.times()[4] < timeout):
             time.sleep(1)
         if self.get_power()['powerstate'] != reqpowerstate:
             raise exc.PyghmiException(
                 "System did not accomplish power state change")
         return {'powerstate': reqpowerstate}
     return {'pendingpowerstate': reqpowerstate}
Пример #5
0
    def set_power(self, powerstate, wait=False):
        """Request power state change

        :param powerstate:
                            * on -- Request system turn on
                            * off -- Request system turn off without waiting
                                     for OS to shutdown
                            * shutdown -- Have system request OS proper
                                          shutdown
                            * reset -- Request system reset without waiting for
                              OS
                            * boot -- If system is off, then 'on', else 'reset'
        :param wait: If True, do not return until system actually completes
                     requested state change for 300 seconds.
                     If a non-zero number, adjust the wait time to the
                     requested number of seconds
        :returns: dict -- A dict describing the response retrieved
        """
        if powerstate not in power_states:
            raise exc.InvalidParameterValue(
                "Unknown power state %s requested" % powerstate)
        self.newpowerstate = powerstate
        response = self.ipmi_session.raw_command(netfn=0, command=1)
        if 'error' in response:
            raise exc.IpmiException(response['error'])
        self.powerstate = 'on' if (response['data'][0] & 1) else 'off'
        if self.powerstate == self.newpowerstate:
            return {'powerstate': self.powerstate}
        if self.newpowerstate == 'boot':
            self.newpowerstate = 'on' if self.powerstate == 'off' else 'reset'
        response = self.ipmi_session.raw_command(
            netfn=0, command=2, data=[power_states[self.newpowerstate]])
        if 'error' in response:
            raise exc.IpmiException(response['error'])
        self.lastresponse = {'pendingpowerstate': self.newpowerstate}
        waitattempts = 300
        if not isinstance(wait, bool):
            waitattempts = wait
        if (wait and self.newpowerstate
                in ('on', 'off', 'shutdown', 'softoff')):
            if self.newpowerstate in ('softoff', 'shutdown'):
                self.waitpowerstate = 'off'
            else:
                self.waitpowerstate = self.newpowerstate
            currpowerstate = None
            while currpowerstate != self.waitpowerstate and waitattempts > 0:
                response = self.ipmi_session.raw_command(netfn=0,
                                                         command=1,
                                                         delay_xmit=1)
                if 'error' in response:
                    return response
                currpowerstate = 'on' if (response['data'][0] & 1) else 'off'
                waitattempts -= 1
            if currpowerstate != self.waitpowerstate:
                raise exc.IpmiException(
                    "System did not accomplish power state change")
            return {'powerstate': currpowerstate}
        else:
            return self.lastresponse
Пример #6
0
 def _get_status(self, disk, realcfg):
     for cfgdisk in realcfg.disks:
         if disk.id == cfgdisk.id:
             currstatus = cfgdisk.status
             break
     else:
         raise pygexc.InvalidParameterValue('Requested disk not found')
     return currstatus
Пример #7
0
 def set_ntp_server(self, server, index=0):
     if self.has_tsm:
         if not (0 <= index <= 1):
             raise pygexc.InvalidParameterValue("Index must be 0 or 1")
         cmddata = bytearray((1 + index, ))
         cmddata += server.ljust(128, '\x00')
         self.ipmicmd.xraw_command(netfn=0x32, command=0xa8, data=cmddata)
         return True
     return None
Пример #8
0
    def set_bootdev(self, bootdev, persist=False, uefiboot=None):
        """Set boot device to use on next reboot

        :param bootdev:
                        *network -- Request network boot
                        *hd -- Boot from hard drive
                        *safe -- Boot from hard drive, requesting 'safe mode'
                        *optical -- boot from CD/DVD/BD drive
                        *setup -- Boot into setup utility
                        *default -- remove any directed boot device request
        :param persist: If true, ask that system firmware use this device
                        beyond next boot.  Be aware many systems do not honor
                        this
        :param uefiboot: If true, request UEFI boot explicitly.  If False,
                         request BIOS style boot.
                         None (default) does not modify the boot mode.
        :raises: PyghmiException on an error.
        :returns: dict or True -- If callback is not provided, the response
        """
        reqbootdev = bootdev
        if (bootdev not in boot_devices_write
                and bootdev not in boot_devices_read):
            raise exc.InvalidParameterValue('Unsupported device ' +
                                            repr(bootdev))
        bootdev = boot_devices_write.get(bootdev, bootdev)
        if bootdev == 'None':
            payload = {'Boot': {'BootSourceOverrideEnabled': 'Disabled'}}
        else:
            payload = {
                'Boot': {
                    'BootSourceOverrideEnabled':
                    'Continuous' if persist else 'Once',
                    'BootSourceOverrideTarget': bootdev,
                }
            }
            if uefiboot is not None:
                uefiboot = 'UEFI' if uefiboot else 'Legacy'
                payload['BootSourceOverrideMode'] = uefiboot
        self._do_web_request(self.sysurl, payload, method='PATCH')
        return {'bootdev': reqbootdev}
Пример #9
0
    def set_fw_options(self, options):
        changes = False
        random.seed()
        ident = 'ASU-%x-%x-%x-0' % (random.getrandbits(48),
                                    random.getrandbits(32),
                                    random.getrandbits(64))

        configurations = etree.Element('configurations',
                                       ID=ident,
                                       type='update',
                                       update='ASU Client')

        for option in options.keys():
            if options[option]['new_value'] is None:
                continue
            if options[option]['current'] == options[option]['new_value']:
                continue
            if options[option]['pending'] == options[option]['new_value']:
                continue
            if options[option]['readonly']:
                errstr = '{0} is read only'.format(option)
                if options[option]['readonly_why']:
                    ea = ' due to one of the following settings: {0}'.format(
                        ','.join(sorted(options[option]['readonly_why'])))
                    errstr += ea
                raise pygexc.InvalidParameterValue(errstr)
            if (isinstance(options[option]['new_value'], str)
                    or isinstance(options[option]['new_value'], unicode)):
                # Coerce a simple string parameter to the expected list format
                options[option]['new_value'] = [options[option]['new_value']]
            options[option]['pending'] = options[option]['new_value']

            is_list = options[option]['is_list']
            count = 0
            changes = True
            config = etree.Element('config', ID=options[option]['lenovo_id'])
            configurations.append(config)
            group = etree.Element('group', ID=options[option]['lenovo_group'])
            config.append(group)
            setting = etree.Element('setting',
                                    ID=options[option]['lenovo_setting'])
            group.append(setting)

            if is_list:
                container = etree.Element('list_data')
                setting.append(container)
            else:
                container = etree.Element('enumerate_data')
                setting.append(container)

            for value in options[option]['new_value']:
                choice = etree.Element('choice')
                container.append(choice)
                label = etree.Element('label')
                label.text = value
                choice.append(label)
                if is_list:
                    count += 1
                    instance = etree.Element(
                        'instance',
                        ID=options[option]['lenovo_instance'],
                        order=str(count))
                else:
                    instance = etree.Element(
                        'instance', ID=options[option]['lenovo_instance'])
                choice.append(instance)

        if not changes:
            return

        xml = etree.tostring(configurations)
        data = EfiCompressor.FrameworkCompress(xml, len(xml))
        filehandle = self.imm_open("asu_update.efi",
                                   write=True,
                                   size=len(data))
        self.imm_write(filehandle, len(data), data)
        self.imm_close(filehandle)
Пример #10
0
 def _create_array(self, pool):
     params = self._parse_array_spec(pool)
     url = '/api/function/raid_conf?params=raidlink_GetDefaultVolProp'
     args = (url, params['controller'], 0, params['drives'])
     props = self.wc.grab_json_response(','.join([str(x) for x in args]))
     props = props['items'][0]
     volumes = pool.volumes
     remainingcap = params['capacity']
     nameappend = 1
     vols = []
     currvolnames = None
     currcfg = None
     for vol in volumes:
         if vol.name is None:
             # need to iterate while there exists a volume of that name
             if currvolnames is None:
                 currcfg = self.get_storage_configuration()
                 currvolnames = set([])
                 for pool in currcfg.arrays:
                     for volume in pool.volumes:
                         currvolnames.add(volume.name)
             name = props['name'] + '_{0}'.format(nameappend)
             nameappend += 1
             while name in currvolnames:
                 name = props['name'] + '_{0}'.format(nameappend)
                 nameappend += 1
         else:
             name = vol.name
         stripesize = props['stripsize'] if vol.stripesize is None \
             else vol.stripesize
         strsize = 'remainder' if vol.size is None else str(vol.size)
         if strsize in ('all', '100%'):
             volsize = params['capacity']
         elif strsize in ('remainder', 'rest'):
             volsize = remainingcap
         elif strsize.endswith('%'):
             volsize = int(params['capacity'] *
                           float(strsize.replace('%', '')) / 100.0)
         else:
             try:
                 volsize = int(strsize)
             except ValueError:
                 raise pygexc.InvalidParameterValue('Unrecognized size ' +
                                                    strsize)
         remainingcap -= volsize
         if remainingcap < 0:
             raise pygexc.InvalidParameterValue(
                 'Requested sizes exceed available capacity')
         vols.append('{0};{1};{2};{3};{4};{5};{6};{7};{8};|'.format(
             name, volsize, stripesize, props['cpwb'], props['cpra'],
             props['cpio'], props['ap'], props['dcp'], props['initstate']))
     url = '/api/function'
     arglist = '{0},{1},{2},{3},{4},{5},'.format(
         params['controller'], params['raidlevel'], params['spans'],
         params['perspan'], params['drives'], params['hotspares'])
     arglist += ''.join(vols)
     parms = {'raidlink_AddNewVolWithNaAsync': arglist}
     rsp = self.wc.grab_json_response(url, parms)
     if rsp['return'] != 0:
         raise Exception('Unexpected response to add volume command: ' +
                         repr(rsp))
     self._wait_storage_async()