Ejemplo n.º 1
0
    def set_identify(self, on=True, duration=None):
        """Request identify light

        Request the identify light to turn off, on for a duration,
        or on indefinitely.  Other than error exceptions,

        :param on: Set to True to force on or False to force off
        :param duration: Set if wanting to request turn on for a duration
                         rather than indefinitely on
        """
        if duration is not None:
            duration = int(duration)
            if duration > 255:
                duration = 255
            if duration < 0:
                duration = 0
            response = self.raw_command(netfn=0, command=4, data=[duration])
            if 'error' in response:
                raise exc.IpmiException(response['error'])
            return
        forceon = 0
        if on:
            forceon = 1
        if self.ipmi_session.ipmiversion < 2.0:
            # ipmi 1.5 made due with just one byte, make best effort
            # to imitate indefinite as close as possible
            identifydata = [255 * forceon]
        else:
            identifydata = [0, forceon]
        response = self.raw_command(netfn=0, command=4, data=identifydata)
        if 'error' in response:
            raise exc.IpmiException(response['error'])
Ejemplo n.º 2
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
Ejemplo n.º 3
0
    def set_ris_configuration_parameter(self, media_type_id, param_id, value):
        multiply = lambda value, times=None: [value] * times if times else []
        hexify = lambda x, y=None: ([ord(elem) for elem in x])

        reset_progress_bit = False

        data = [media_type_id, param_id]

        # Ris Restart
        if param_id == 0x0b and media_type_id == 0x08:
            rsp = self.ipmicmd.raw_command(netfn=0x32, command=0x9f, data=data)
        # Ris State
        elif param_id == 0x0a and media_type_id == 0x08:
            data.extend([0x00, 0x00 if value == 'disable' else 0x01])
            rsp = self.ipmicmd.raw_command(netfn=0x32, command=0x9f, data=data)
        # Password
        elif param_id in [0x04] and media_type_id != 0x08:
            data.append(0x00)
            data.extend(hexify(value, 32))
            rsp = self.ipmicmd.raw_command(netfn=0x32, command=0x9f, data=data)
        elif param_id in [0x02, 0x05] and media_type_id != 0x08:
            data.append(0x00)
            data.extend(hexify(value, 64))
            rsp = self.ipmicmd.raw_command(netfn=0x32, command=0x9f, data=data)
        # Ris Souce Path, image name, domain name or user name
        elif param_id in [0x01, 0x00, 0x06, 0x03] and media_type_id != 0x08:
            if len(value) > 256:
                raise StandardError('Value should be less than 256 caracteres')
            # Progress Bit
            self.ipmicmd.xraw_command(netfn=0x32,
                                      command=0x9f,
                                      data=(0x01, param_id, 0x00, 0x01))

            for i in range(1, int(math.ceil(len(value) / 64.0)) + 1):
                data = [0x01, param_id, i]
                substr_start = (i - 1) * 64
                substr_end = i * 64
                data.extend(hexify(value[substr_start:substr_end], 64))
                self.ipmicmd.raw_command(netfn=0x32, command=0x9f, data=data)

            # Reset Progress Bit
            rsp = self.ipmicmd.raw_command(netfn=0x32,
                                           command=0x9f,
                                           data=(0x01, param_id, 0x00, 0x00))
        else:
            raise StandardError('Unknown parameter or not implemented')

        error_messages = {
            # Documented message
            0x95: 'Image format is not supported',
        }

        if 'code' in rsp and rsp['code'] != 0:
            if rsp['code'] in error_messages:
                raise pygexc.IpmiException(error_messages[rsp['code']],
                                           rsp['code'])
            else:
                raise pygexc.IpmiException(rsp['error'], rsp['code'])
Ejemplo n.º 4
0
 def _xmit_packet(self, retry=True, delay_xmit=None):
     if self.sequencenumber:
         self.sequencenumber += 1
     if delay_xmit is not None:
         # skip transmit, let retry timer do it's thing
         self.waiting_sessions[self] = {}
         self.waiting_sessions[self]["ipmisession"] = self
         self.waiting_sessions[self]["timeout"] = delay_xmit + _monotonic_time()
         return
     if self.sockaddr:
         self.send_data(self.netpacket, self.sockaddr)
     else:
         self.allsockaddrs = []
         try:
             for res in socket.getaddrinfo(
                 self.bmc, self.port, 0, socket.SOCK_DGRAM
             ):
                 sockaddr = res[4]
                 if res[0] == socket.AF_INET:
                     # convert the sockaddr to AF_INET6
                     newhost = "::ffff:" + sockaddr[0]
                     sockaddr = (newhost, sockaddr[1], 0, 0)
                 self.allsockaddrs.append(sockaddr)
                 self.bmc_handlers[sockaddr] = self
                 self.send_data(self.netpacket, sockaddr)
         except socket.gaierror:
             raise exc.IpmiException("Unable to transmit to specified address")
     if retry:
         self.waiting_sessions[self] = {}
         self.waiting_sessions[self]["ipmisession"] = self
         self.waiting_sessions[self]["timeout"] = self.timeout + _monotonic_time()
Ejemplo n.º 5
0
    def test__run_set_power_cmd_ipmi_exc(self, mock_command):
        ipmicmd = mock_command.return_value
        ipmicmd.set_power.side_effect = pyghmi_exc.IpmiException()

        self.assertRaises(pyghmi_exc.IpmiException,
                          self.driver._run_set_power_cmd,
                          self.host,
                          'off',
                          expected_state='off')
Ejemplo n.º 6
0
    def get_boot_device(self, task):
        """Get the current boot device for the task's node.

        Returns the current boot device of the node.

        :param task: a task from TaskManager.
        :raises: MissingParameterValue if required IPMI parameters
            are missing.
        :raises: IPMIFailure on an error from pyghmi.
        :returns: a dictionary containing:

            :boot_device: the boot device, one of
                :mod:`ironic.common.boot_devices` or None if it is unknown.
            :persistent: Whether the boot device will persist to all
                future boots or not, None if it is unknown.

        """
        driver_info = task.node.driver_info
        driver_internal_info = task.node.driver_internal_info
        if (driver_info.get('ipmi_force_boot_device', False)
                and driver_internal_info.get('persistent_boot_device')
                and driver_internal_info.get('is_next_boot_persistent', True)):
            return {
                'boot_device': driver_internal_info['persistent_boot_device'],
                'persistent': True
            }

        driver_info = _parse_driver_info(task.node)
        response = {'boot_device': None}

        try:
            ipmicmd = ipmi_command.Command(bmc=driver_info['address'],
                                           userid=driver_info['username'],
                                           password=driver_info['password'])
            ret = ipmicmd.get_bootdev()
            # FIXME(lucasagomes): pyghmi doesn't seem to handle errors
            # consistently, for some errors it raises an exception
            # others it just returns a dictionary with the error.
            if 'error' in ret:
                raise pyghmi_exception.IpmiException(ret['error'])
        except pyghmi_exception.IpmiException as e:
            LOG.error(
                _LE("IPMI get boot device failed for node %(node_id)s "
                    "with the following error: %(error)s"), {
                        'node_id': driver_info['uuid'],
                        'error': e
                    })
            raise exception.IPMIFailure(cmd=e)

        response['persistent'] = ret.get('persistent')
        bootdev = ret.get('bootdev')
        if bootdev:
            response['boot_device'] = next(
                (dev for dev, hdev in _BOOT_DEVICES_MAP.items()
                 if hdev == bootdev), None)
        return response
Ejemplo n.º 7
0
 def send_payload(self, payload, payload_type=1, retry=True,
                  needskeepalive=False):
     while not (self.connected or self.broken):
         session.Session.wait_for_rsp(timeout=10)
     if not self.ipmi_session.logged:
         raise exc.IpmiException('Session no longer connected')
     self.ipmi_session.send_payload(payload,
                                    payload_type=payload_type,
                                    retry=retry,
                                    needskeepalive=needskeepalive)
Ejemplo n.º 8
0
 def fetch_fru(self, fruid):
     response = self.ipmicmd.raw_command(netfn=0xa,
                                         command=0x10,
                                         data=[fruid])
     if 'error' in response:
         raise iexc.IpmiException(response['error'], code=response['code'])
     frusize = response['data'][0] | (response['data'][1] << 8)
     # In our case, we don't need to think too hard about whether
     # the FRU is word or byte, we just process what we get back in the
     # payload
     chunksize = 240
     # Selected as it is accomodated by most tested things
     # and many tested things broke after going much
     # bigger
     if chunksize > frusize:
         chunksize = frusize
     offset = 0
     self.rawfru = bytearray([])
     while chunksize:
         response = self.ipmicmd.raw_command(
             netfn=0xa,
             command=0x11,
             data=[fruid, offset & 0xff, offset >> 8, chunksize])
         if response['code'] in (201, 202):
             # if it was too big, back off and try smaller
             # Try just over half to mitigate the chance of
             # one request becoming three rather than just two
             if chunksize == 3:
                 raise iexc.IpmiException(response['error'])
             chunksize //= 2
             chunksize += 2
             continue
         elif 'error' in response:
             raise iexc.IpmiException(response['error'], response['code'])
         self.rawfru.extend(response['data'][1:])
         offset += response['data'][0]
         if response['data'][0] == 0:
             break
         if offset + chunksize > frusize:
             chunksize = frusize - offset
Ejemplo n.º 9
0
 def set_media_redirection_state(self, image_type, image_name, value):
     data = [image_type, 0x01 if value == 'start' else 0x00]
     data.extend([ord(elem) for elem in image_name])
     data.append(0x00)
     rsp = self.ipmicmd.raw_command(netfn=0x3a, command=0x16, data=data)
     error_messages = {
         0x90: 'Media support is not enabled',
         0x91: 'Error in get vmedia configuration',
         0x92: 'Media is not running',
         0x95: 'Slot is not available for the particular Image type',
         0x96: 'Error in retrieving available image information',
         0x97: 'Valid Image is not available',
         0x98: 'Image format is not supported',
         0x99: 'Image file not found',
         0x9a: 'invalid start/stop command'
     }
     if 'code' in rsp and rsp['code'] != 0:
         if rsp['code'] in error_messages:
             raise pygexc.IpmiException(error_messages[rsp['code']],
                                        rsp['code'])
         else:
             raise pygexc.IpmiException(rsp['error'], rsp['code'])
Ejemplo n.º 10
0
    def test_get_pci_exception(self, exec_mock):
        pci_device_ids = ['0x1111/0x1179', '0x2100/0x0080']

        exec_mock.side_effect = ipmi_exception.IpmiException('Error')

        cmd = "0x2E 0xF1 0x80 0x28 0x00 0x1A 0x1 0x00"

        e = self.assertRaises(ipmi.IPMIFailure, ipmi.get_pci_device, self.info,
                              pci_device_ids)
        exec_mock.assert_called_once_with(mock.ANY, cmd)
        self.assertEqual(
            'IPMI operation \'GET PCI device quantity\' '
            'failed: Error', str(e))
Ejemplo n.º 11
0
    def get_power(self):
        """Get current power state of the managed system

        The response, if successful, should contain 'powerstate' key and
        either 'on' or 'off' to indicate current state.

        :returns: dict -- {'powerstate': value}
        """
        response = self.ipmi_session.raw_command(netfn=0, command=1)
        if 'error' in response:
            raise exc.IpmiException(response['error'])
        assert (response['command'] == 1 and response['netfn'] == 1)
        self.powerstate = 'on' if (response['data'][0] & 1) else 'off'
        return {'powerstate': self.powerstate}
Ejemplo n.º 12
0
 def _get_ipmicmd(self, user=None, password=None):
     priv = None
     if user is None or password is None:
         if self.trieddefault:
             raise pygexc.IpmiException()
         priv = 4  # manually indicate priv to avoid double-attempt
     if user is None:
         user = self.DEFAULT_USER
     if password is None:
         password = self.DEFAULT_PASS
     return ipmicommand.Command(self.ipaddr,
                                user,
                                password,
                                privlevel=priv,
                                keepalive=False)
Ejemplo n.º 13
0
    def get_sensor_data(self):
        """Get sensor reading objects

        Iterates sensor reading objects pertaining to the currently
        managed BMC.

        :returns: Iterator of sdr.SensorReading objects
        """
        if self._sdr is None:
            self._sdr = sdr.SDR(self)
        for sensor in self._sdr.get_sensor_numbers():
            rsp = self.raw_command(command=0x2d, netfn=4, data=(sensor, ))
            if 'error' in rsp:
                if rsp['code'] == 203:  # Sensor does not exist, optional dev
                    continue
                raise exc.IpmiException(rsp['error'], code=rsp['code'])
            yield self._sdr.sensors[sensor].decode_sensor_reading(rsp['data'])
Ejemplo n.º 14
0
    def get_sensor_reading(self, sensorname):
        """Get a sensor reading by name

        Returns a single decoded sensor reading per the name
        passed in

        :param sensorname:  Name of the desired sensor
        :returns: sdr.SensorReading object
        """
        if self._sdr is None:
            self._sdr = sdr.SDR(self)
        for sensor in self._sdr.get_sensor_numbers():
            if self._sdr.sensors[sensor].name == sensorname:
                rsp = self.raw_command(command=0x2d, netfn=4, data=(sensor, ))
                if 'error' in rsp:
                    raise exc.IpmiException(rsp['error'], rsp['code'])
                return self._sdr.sensors[sensor].decode_sensor_reading(
                    rsp['data'])
        raise Exception('Sensor not found: ' + sensorname)
Ejemplo n.º 15
0
 def get_sdr(self):
     repinfo = self.ipmicmd.xraw_command(netfn=0x0a, command=0x20)
     repinfo['data'] = bytearray(repinfo['data'])
     if (repinfo['data'][0] != 0x51):
         # we only understand SDR version 51h, the only version defined
         # at time of this writing
         raise NotImplementedError
     #NOTE(jbjohnso): we actually don't need to care about 'numrecords'
     # since FFFF marks the end explicitly
     #numrecords = (rsp['data'][2] << 8) + rsp['data'][1]
     #NOTE(jbjohnso): don't care about 'free space' at the moment
     #NOTE(jbjohnso): most recent timstamp data for add and erase could be
     # handy to detect cache staleness, but for now will assume invariant
     # over life of session
     #NOTE(jbjohnso): not looking to support the various options in op
     # support, ignore those for now, reservation if some BMCs can't read
     # full SDR in one slurp
     recid = 0
     rsvid = 0  # partial 'get sdr' will require this
     offset = 0
     size = 0xff
     chunksize = 128
     self.broken_sensor_ids = {}
     while recid != 0xffff:  # per 33.12 Get SDR command, 0xffff marks end
         newrecid = 0
         currlen = 0
         sdrdata = bytearray()
         while True:  # loop until SDR fetched wholly
             if size != 0xff and rsvid == 0:
                 rsvid = self.get_sdr_reservation()
             rqdata = [
                 rsvid & 0xff, rsvid >> 8, recid & 0xff, recid >> 8, offset,
                 size
             ]
             sdrrec = self.ipmicmd.raw_command(netfn=0x0a,
                                               command=0x23,
                                               data=rqdata)
             if sdrrec['code'] == 0xca:
                 if size == 0xff:  # get just 5 to get header to know length
                     size = 5
                 elif size > 5:
                     size /= 2
                     # push things over such that it's less
                     # likely to be just 1 short of a read
                     # and incur a whole new request
                     size += 2
                     chunksize = size
                 continue
             if sdrrec['code'] == 0xc5:  # need a new reservation id
                 rsvid = 0
                 continue
             if sdrrec['code'] != 0:
                 raise exc.IpmiException(sdrrec['error'])
             if newrecid == 0:
                 newrecid = (sdrrec['data'][1] << 8) + sdrrec['data'][0]
             if currlen == 0:
                 currlen = sdrrec['data'][6] + 5  # compensate for header
             sdrdata.extend(sdrrec['data'][2:])
             # determine next offset to use based on current offset and the
             # size used last time.
             offset += size
             if offset >= currlen:
                 break
             if size == 5 and offset == 5:
                 # bump up size after header retrieval
                 size = chunksize
             if (offset + size) > currlen:
                 size = currlen - offset
         self.add_sdr(sdrdata)
         offset = 0
         if size != 0xff:
             size = 5
         if newrecid == recid:
             raise exc.BmcErrorException("Incorrect SDR record id from BMC")
         recid = newrecid
     for sid in self.broken_sensor_ids:
         del self.sensors[sid]
Ejemplo n.º 16
0
 def get_sdr_reservation(self):
     rsp = self.ipmicmd.raw_command(netfn=0x0a, command=0x22)
     if rsp['code'] != 0:
         raise exc.IpmiException(rsp['error'])
     return rsp['data'][0] + (rsp['data'][1] << 8)
Ejemplo n.º 17
0
 def test__send_raw_fail(self, ipmi_mock):
     ipmicmd = ipmi_mock.return_value
     ipmicmd.xraw_command.side_effect = pyghmi_exception.IpmiException()
     self.assertRaises(exception.IPMIFailure, ipminative._send_raw,
                       self.info, '0x01 0x02')
Ejemplo n.º 18
0
 def get_sdr(self):
     repinfo = self.ipmicmd.xraw_command(netfn=0x0a, command=0x20)
     repinfo['data'] = bytearray(repinfo['data'])
     if (repinfo['data'][0] != 0x51):
         # we only understand SDR version 51h, the only version defined
         # at time of this writing
         raise NotImplementedError
     # NOTE(jbjohnso): we actually don't need to care about 'numrecords'
     # since FFFF marks the end explicitly
     # numrecords = (rsp['data'][2] << 8) + rsp['data'][1]
     # NOTE(jbjohnso): don't care about 'free space' at the moment
     # NOTE(jbjohnso): most recent timstamp data for add and erase could be
     # handy to detect cache staleness, but for now will assume invariant
     # over life of session
     # NOTE(jbjohnso): not looking to support the various options in op
     # support, ignore those for now, reservation if some BMCs can't read
     # full SDR in one slurp
     modtime = struct.unpack('!Q', repinfo['data'][5:13])[0]
     recid = 0
     rsvid = 0  # partial 'get sdr' will require this
     offset = 0
     size = 0xff
     chunksize = 128
     try:
         csdrs = shared_sdrs[
             (self.fw_major, self.fw_minor, self.mfg_id, self.prod_id,
              self.device_id, modtime)]
         self.sensors = csdrs['sensors']
         self.fru = csdrs['fru']
         return
     except KeyError:
         pass
     cachefilename = None
     self.broken_sensor_ids = {}
     if self.cachedir:
         cachefilename = 'sdrcache.{0}.{1}.{2}.{3}.{4}.{5}'.format(
             self.mfg_id, self.prod_id, self.device_id, self.fw_major,
             self.fw_minor, modtime)
         cachefilename = os.path.join(self.cachedir, cachefilename)
     if cachefilename and os.path.isfile(cachefilename):
         with open(cachefilename, 'r') as cfile:
             csdrs = pickle.load(cfile)
             for sdrdata in csdrs:
                 self.add_sdr(sdrdata)
             for sid in self.broken_sensor_ids:
                 try:
                     del self.sensors[sid]
                 except KeyError:
                     pass
             shared_sdrs[
                 (self.fw_major, self.fw_minor, self.mfg_id, self.prod_id,
                  self.device_id, modtime)] = {
                 'sensors': self.sensors,
                 'fru': self.fru,
             }
             return
     sdrraw = [] if cachefilename else None
     while recid != 0xffff:  # per 33.12 Get SDR command, 0xffff marks end
         newrecid = 0
         currlen = 0
         sdrdata = bytearray()
         while True:  # loop until SDR fetched wholly
             if size != 0xff and rsvid == 0:
                 rsvid = self.get_sdr_reservation()
             rqdata = [rsvid & 0xff, rsvid >> 8,
                       recid & 0xff, recid >> 8,
                       offset, size]
             sdrrec = self.ipmicmd.raw_command(netfn=0x0a, command=0x23,
                                               data=rqdata)
             if sdrrec['code'] == 0xca:
                 if size == 0xff:  # get just 5 to get header to know length
                     size = 5
                 elif size > 5:
                     size /= 2
                     # push things over such that it's less
                     # likely to be just 1 short of a read
                     # and incur a whole new request
                     size += 2
                     chunksize = size
                 continue
             if sdrrec['code'] == 0xc5:  # need a new reservation id
                 rsvid = 0
                 continue
             if sdrrec['code'] != 0:
                 raise exc.IpmiException(sdrrec['error'])
             if newrecid == 0:
                 newrecid = (sdrrec['data'][1] << 8) + sdrrec['data'][0]
             if currlen == 0:
                 currlen = sdrrec['data'][6] + 5  # compensate for header
             sdrdata.extend(sdrrec['data'][2:])
             # determine next offset to use based on current offset and the
             # size used last time.
             offset += size
             if offset >= currlen:
                 break
             if size == 5 and offset == 5:
                 # bump up size after header retrieval
                 size = chunksize
             if (offset + size) > currlen:
                 size = currlen - offset
         self.add_sdr(sdrdata)
         if sdrraw is not None:
             sdrraw.append(sdrdata)
         offset = 0
         if size != 0xff:
             size = 5
         if newrecid == recid:
             raise exc.BmcErrorException("Incorrect SDR record id from BMC")
         recid = newrecid
     for sid in self.broken_sensor_ids:
         try:
             del self.sensors[sid]
         except KeyError:
             pass
     shared_sdrs[(self.fw_major, self.fw_minor, self.mfg_id, self.prod_id,
                  self.device_id, modtime)] = {
         'sensors': self.sensors,
         'fru': self.fru,
     }
     if cachefilename:
         suffix = ''.join(
             random.choice(string.ascii_lowercase) for _ in range(12))
         with open(cachefilename + '.' + suffix, 'w') as cfile:
             pickle.dump(sdrraw, cfile)
         os.rename(cachefilename + '.' + suffix, cachefilename)