Esempio n. 1
0
 def connect(self, callback):
     self.datacallback = callback
     # we provide a weak reference to pyghmi as otherwise we'd
     # have a circular reference and reference counting would never get
     # out...
     try:
         self.solconnection = console.Console(bmc=self.bmc, port=self.port,
                                              userid=self.username,
                                              password=self.password,
                                              kg=self.kg, force=True,
                                              iohandler=self.handle_data)
         while not self.solconnection.connected and not self.broken:
             w = eventlet.event.Event()
             _ipmiwaiters.append(w)
             w.wait()
             if self.broken:
                 break
         if self.broken:
             if (self.error.startswith('Incorrect password') or
                     self.error.startswith('Unauthorized name')):
                 raise exc.TargetEndpointBadCredentials
             else:
                 raise exc.TargetEndpointUnreachable(self.error)
         self.connected = True
     except socket.gaierror as err:
         raise exc.TargetEndpointUnreachable(str(err))
Esempio n. 2
0
    def __init__(self, operation, node, element, cfd, inputdata, cfg, output):
        self.sensormap = {}
        self.invmap = {}
        self.output = output
        self.sensorcategory = None
        self.broken = False
        self.error = None
        eventlet.sleep(0)
        self.cfg = cfd[node]
        self.loggedin = False
        self.node = node
        self.element = element
        self.op = operation
        connparams = get_conn_params(node, self.cfg)
        self.ipmicmd = None
        self.inputdata = inputdata
        self.tenant = cfg.tenant
        tenant = cfg.tenant
        if ((node, tenant) not in persistent_ipmicmds or
                not persistent_ipmicmds[(node, tenant)].ipmi_session.logged):
            try:
                persistent_ipmicmds[(node, tenant)].close_confluent()
            except KeyError:  # was no previous session
                pass
            try:
                persistent_ipmicmds[(node, tenant)] = IpmiCommandWrapper(
                    node,
                    cfg,
                    bmc=connparams['bmc'],
                    userid=connparams['username'],
                    password=connparams['passphrase'],
                    kg=connparams['kg'],
                    port=connparams['port'],
                    onlogon=self.logged)

                ipmisess = persistent_ipmicmds[(node, tenant)].ipmi_session
                begin = util.monotonic_time()
                while ((not (self.broken or self.loggedin))
                       and (util.monotonic_time() - begin) < 180):
                    ipmisess.wait_for_rsp(180)
                if not (self.broken or self.loggedin):
                    raise exc.TargetEndpointUnreachable("Login process to " +
                                                        connparams['bmc'] +
                                                        " died")
            except socket.gaierror as ge:
                if ge[0] == -2:
                    raise exc.TargetEndpointUnreachable(ge[1])
                raise
        self.ipmicmd = persistent_ipmicmds[(node, tenant)]
Esempio n. 3
0
 def __init__(self, operation, node, element, cfd, inputdata, cfg, output):
     self.sensormap = {}
     self.invmap = {}
     self.output = output
     self.sensorcategory = None
     self.broken = False
     self.error = None
     eventlet.sleep(0)
     self.cfg = cfd[node]
     self.loggedin = False
     self.node = node
     self.element = element
     self.op = operation
     connparams = get_conn_params(node, self.cfg)
     self.ipmicmd = None
     self.inputdata = inputdata
     tenant = cfg.tenant
     self._logevt = None
     if ((node, tenant) not in persistent_ipmicmds or
             not persistent_ipmicmds[(node, tenant)].ipmi_session.logged):
         self._logevt = threading.Event()
         try:
             persistent_ipmicmds[(node, tenant)].close_confluent()
         except KeyError:  # was no previous session
             pass
         try:
             persistent_ipmicmds[(node, tenant)] = IpmiCommandWrapper(
                 node, cfg, bmc=connparams['bmc'],
                 userid=connparams['username'],
                 password=connparams['passphrase'], kg=connparams['kg'],
                 port=connparams['port'], onlogon=self.logged)
         except socket.gaierror as ge:
             if ge[0] == -2:
                 raise exc.TargetEndpointUnreachable(ge[1])
     self.ipmicmd = persistent_ipmicmds[(node, tenant)]
Esempio n. 4
0
    def walk(self, oid):
        """Walk over children of a given OID

        This is roughly equivalent to snmpwalk.  It will automatically try to
        be a snmpbulkwalk if possible.

        :param oid: The SNMP object identifier
        """
        # SNMP is a complicated mess of things.  Will endeavor to shield caller
        # from as much as possible, assuming reasonable defaults when possible.
        # there may come a time where we add more parameters to override the
        # automatic behavior (e.g. DES is weak, so it's likely to be
        # overriden, but some devices only support DES)
        tp = _get_transport(self.server)
        ctx = snmp.ContextData(self.context)
        resolvemib = False
        if '::' in oid:
            resolvemib = True
            mib, field = oid.split('::')
            obj = snmp.ObjectType(snmp.ObjectIdentity(mib, field))
        else:
            obj = snmp.ObjectType(snmp.ObjectIdentity(oid))

        walking = snmp.bulkCmd(self.eng,
                               self.authdata,
                               tp,
                               ctx,
                               0,
                               10,
                               obj,
                               lexicographicMode=False,
                               lookupMib=resolvemib)
        try:
            for rsp in walking:
                errstr, errnum, erridx, answers = rsp
                if errstr:
                    errstr = str(errstr)
                    finerr = errstr + ' while trying to connect to ' \
                                      '{0}'.format(self.server)
                    if errstr in ('Unknown USM user', 'unknownUserName',
                                  'wrongDigest', 'Wrong SNMP PDU digest'):
                        raise exc.TargetEndpointBadCredentials(finerr)
                    # need to do bad credential versus timeout
                    raise exc.TargetEndpointUnreachable(finerr)
                elif errnum:
                    raise exc.ConfluentException(errnum.prettyPrint() +
                                                 ' while trying to connect to '
                                                 '{0}'.format(self.server))
                for ans in answers:
                    if not obj[0].isPrefixOf(ans[0]):
                        # PySNMP returns leftovers in a bulk command
                        # filter out such leftovers
                        break
                    yield ans
        except snmperr.WrongValueError:
            raise exc.TargetEndpointBadCredentials('Invalid SNMPv3 password')
Esempio n. 5
0
    def walk(self, oid):
        """Walk over children of a given OID

        This is roughly equivalent to snmpwalk.  It will automatically try to
        be a snmpbulkwalk if possible.

        :param oid: The SNMP object identifier
        """
        # SNMP is a complicated mess of things.  Will endeavor to shield caller
        # from as much as possible, assuming reasonable defaults when possible.
        # there may come a time where we add more parameters to override the
        # automatic behavior (e.g. DES is weak, so it's likely to be
        # overriden, but some devices only support DES)
        tp = _get_transport(self.server)
        ctx = snmp.ContextData(self.context)
        if '::' in oid:
            mib, field = oid.split('::')
            obj = snmp.ObjectType(snmp.ObjectIdentity(mib, field))
        else:
            obj = snmp.ObjectType(snmp.ObjectIdentity(oid))

        walking = snmp.bulkCmd(self.eng,
                               self.authdata,
                               tp,
                               ctx,
                               0,
                               10,
                               obj,
                               lexicographicMode=False)
        for rsp in walking:
            errstr, errnum, erridx, answers = rsp
            if errstr:
                raise exc.TargetEndpointUnreachable(str(errstr))
            elif errnum:
                raise exc.ConfluentException(errnum.prettyPrint())
            for ans in answers:
                yield ans
Esempio n. 6
0
 def strip_node(self, node):
     raise exc.TargetEndpointUnreachable(self.error)
Esempio n. 7
0
 def _bmcconfig(self, nodename, reset=False, customconfig=None, vc=None):
     # TODO(jjohnson2): set ip parameters, user/pass, alert cfg maybe
     # In general, try to use https automation, to make it consistent
     # between hypothetical secure path and today.
     creds = self.configmanager.get_node_attributes(nodename, [
         'secret.hardwaremanagementuser',
         'secret.hardwaremanagementpassword'
     ],
                                                    decrypt=True)
     user = creds.get(nodename, {}).get('secret.hardwaremanagementuser',
                                        {}).get('value', None)
     passwd = creds.get(nodename,
                        {}).get('secret.hardwaremanagementpassword',
                                {}).get('value', None)
     try:
         ic = self._get_ipmicmd()
         passwd = self.DEFAULT_PASS
     except pygexc.IpmiException as pi:
         havecustomcreds = False
         if user is not None and user != self.DEFAULT_USER:
             havecustomcreds = True
         else:
             user = self.DEFAULT_USER
         if passwd is not None and passwd != self.DEFAULT_PASS:
             havecustomcreds = True
         else:
             passwd = self.DEFAULT_PASS
         if havecustomcreds:
             ic = self._get_ipmicmd(user, passwd)
         else:
             raise
     if vc:
         ic.register_key_handler(vc)
     currusers = ic.get_users()
     lanchan = ic.get_network_channel()
     userdata = ic.xraw_command(netfn=6, command=0x44, data=(lanchan, 1))
     userdata = bytearray(userdata['data'])
     maxusers = userdata[0] & 0b111111
     enabledusers = userdata[1] & 0b111111
     lockedusers = userdata[2] & 0b111111
     cfg = self.configmanager
     cd = cfg.get_node_attributes(nodename, [
         'secret.hardwaremanagementuser',
         'secret.hardwaremanagementpassword', 'hardwaremanagement.manager'
     ], True)
     cd = cd.get(nodename, {})
     if ('secret.hardwaremanagementuser' not in cd
             or 'secret.hardwaremanagementpassword' not in cd):
         raise exc.TargetEndpointBadCredentials(
             'secret.hardwaremanagementuser and/or '
             'secret.hardwaremanagementpassword was not configured')
     newuser = cd['secret.hardwaremanagementuser']['value']
     newpass = cd['secret.hardwaremanagementpassword']['value']
     for uid in currusers:
         if currusers[uid]['name'] == newuser:
             # Use existing account that has been created
             newuserslot = uid
             if newpass != passwd:  # don't mess with existing if no change
                 ic.set_user_password(newuserslot, password=newpass)
                 ic = self._get_ipmicmd(user, passwd)
                 if vc:
                     ic.register_key_handler(vc)
             break
     else:
         newuserslot = lockedusers + 1
         if newuserslot < 2:
             newuserslot = 2
         if newpass != passwd:  # don't mess with existing if no change
             ic.set_user_password(newuserslot, password=newpass)
         ic.set_user_name(newuserslot, newuser)
         if havecustomcreds:
             ic = self._get_ipmicmd(user, passwd)
             if vc:
                 ic.register_key_handler(vc)
         #We are remote operating on the account we are
         #using, no need to try to set user access
         #ic.set_user_access(newuserslot, lanchan,
         #                   privilege_level='administrator')
     # Now to zap others
     for uid in currusers:
         if uid != newuserslot:
             if uid <= lockedusers:  # we cannot delete, settle for disable
                 ic.disable_user(uid, 'disable')
             else:
                 # lead with the most critical thing, removing user access
                 ic.set_user_access(uid,
                                    channel=None,
                                    callback=False,
                                    link_auth=False,
                                    ipmi_msg=False,
                                    privilege_level='no_access')
                 # next, try to disable the password
                 ic.set_user_password(uid, mode='disable', password=None)
                 # ok, now we can be less paranoid
                 try:
                     ic.user_delete(uid)
                 except pygexc.IpmiException as ie:
                     if ie.ipmicode != 0xd5:  # some response to the 0xff
                         # name...
                         # the user will remain, but that is life
                         raise
     if customconfig:
         customconfig(ic)
     if ('hardwaremanagement.manager' in cd
             and cd['hardwaremanagement.manager']['value']
             and not cd['hardwaremanagement.manager']['value'].startswith(
                 'fe80::')):
         newip = cd['hardwaremanagement.manager']['value']
         newipinfo = getaddrinfo(newip, 0)[0]
         # This getaddrinfo is repeated in get_nic_config, could be
         # optimized, albeit with a more convoluted api..
         newip = newipinfo[-1][0]
         if ':' in newip:
             raise exc.NotImplementedException('IPv6 remote config TODO')
         netconfig = netutil.get_nic_config(cfg, nodename, ip=newip)
         plen = netconfig['prefix']
         newip = '{0}/{1}'.format(newip, plen)
         currcfg = ic.get_net_configuration()
         if currcfg['ipv4_address'] != newip:
             # do not change the ipv4_config if the current config looks
             # like it is already accurate
             ic.set_net_configuration(
                 ipv4_address=newip,
                 ipv4_configuration='static',
                 ipv4_gateway=netconfig['ipv4_gateway'])
     elif self.ipaddr.startswith('fe80::'):
         cfg.set_node_attributes(
             {nodename: {
                 'hardwaremanagement.manager': self.ipaddr
             }})
     else:
         raise exc.TargetEndpointUnreachable(
             'hardwaremanagement.manager must be set to desired address')
     if reset:
         ic.reset_bmc()
     return ic
Esempio n. 8
0
 def config(self, nodename):
     self.nodename = nodename
     creds = self.configmanager.get_node_attributes(
         nodename, ['secret.hardwaremanagementuser',
                    'secret.hardwaremanagementpassword',
                    'hardwaremanagement.manager', 'hardwaremanagement.method', 'console.method'],
                    True)
     cd = creds.get(nodename, {})
     user, passwd, _ = self.get_node_credentials(
             nodename, creds, self.DEFAULT_USER, self.DEFAULT_PASS)
     user = util.stringify(user)
     passwd = util.stringify(passwd)
     self.targuser = user
     self.targpass = passwd
     wc = self._get_wc()
     wc.set_header('X-CSRFTOKEN', self.csrftok)
     curruserinfo = {}
     authupdate = False
     wc.set_header('Content-Type', 'application/json')
     if user != self.curruser:
         authupdate = True
         if not curruserinfo:
             curruserinfo = wc.grab_json_response('/api/settings/users')
             authchg = curruserinfo[1]
         authchg['name'] = user
     if passwd != self.currpass:
         authupdate = True
         if not curruserinfo:
             curruserinfo = wc.grab_json_response('/api/settings/users')
             authchg = curruserinfo[1]
         authchg['changepassword'] = 0
         authchg['password_size'] = 'bytes_20'
         authchg['password'] = passwd
         authchg['confirm_password'] = passwd
     if authupdate:
         rsp, status = wc.grab_json_response_with_status('/api/settings/users/2', authchg, method='PUT')
     if (cd.get('hardwaremanagement.method', {}).get('value', 'ipmi') != 'redfish'
             or cd.get('console.method', {}).get('value', None) == 'ipmi'):
         # IPMI must be enabled per user config
         wc.grab_json_response('/api/settings/ipmilanconfig', {
             'ipv4_enable': 1, 'ipv6_enable': 1,
             'uncheckedipv4lanEnable': 0, 'uncheckedipv6lanEnable': 0,
             'checkedipv4lanEnable': 1, 'checkedipv6lanEnable': 1})
     if ('hardwaremanagement.manager' in cd and
             cd['hardwaremanagement.manager']['value'] and
             not cd['hardwaremanagement.manager']['value'].startswith(
                 'fe80::')):
         newip = cd['hardwaremanagement.manager']['value']
         newipinfo = getaddrinfo(newip, 0)[0]
         newip = newipinfo[-1][0]
         if ':' in newip:
             raise exc.NotImplementedException('IPv6 remote config TODO')
         currnet = wc.grab_json_response('/api/settings/network')
         for net in currnet:
             if net['channel_number'] == self.channel and net['lan_enable'] == 0:
                 # ignore false indication and switch to 8 (dedicated)
                 self.channel = 8
             if net['channel_number'] == self.channel:
                 # we have found the interface to potentially manipulate
                 if net['ipv4_address'] != newip:
                     netconfig = netutil.get_nic_config(self.configmanager, nodename, ip=newip)
                     newmask = netutil.cidr_to_mask(netconfig['prefix'])
                     net['ipv4_address'] = newip
                     net['ipv4_subnet'] = newmask
                     if netconfig['ipv4_gateway']:
                         net['ipv4_gateway'] = netconfig['ipv4_gateway']
                     net['ipv4_dhcp_enable'] = 0
                     rsp, status = wc.grab_json_response_with_status(
                         '/api/settings/network/{0}'.format(net['id']), net, method='PUT')
                 break
     elif self.ipaddr.startswith('fe80::'):
         self.configmanager.set_node_attributes(
             {nodename: {'hardwaremanagement.manager': self.ipaddr}})
     else:
         raise exc.TargetEndpointUnreachable(
             'hardwaremanagement.manager must be set to desired address (No IPv6 Link Local detected)')
     rsp, status = wc.grab_json_response_with_status('/api/session', method='DELETE')
Esempio n. 9
0
 def config(self, nodename, reset=False):
     self.nodename = nodename
     # TODO(jjohnson2): set ip parameters, user/pass, alert cfg maybe
     # In general, try to use https automation, to make it consistent
     # between hypothetical secure path and today.
     dpp = self.configmanager.get_node_attributes(
         nodename, 'discovery.passwordrules')
     strruleset = dpp.get(nodename, {}).get(
         'discovery.passwordrules', {}).get('value', '')
     wc = self.wc
     creds = self.configmanager.get_node_attributes(
         self.nodename, ['secret.hardwaremanagementuser',
         'secret.hardwaremanagementpassword'], decrypt=True)
     user, passwd, isdefault = self.get_node_credentials(nodename, creds, 'USERID', 'PASSW0RD')
     self.set_password_policy(strruleset, wc)
     if self._atdefaultcreds:
         if isdefault and self.tmppasswd:
             raise Exception(
                 'Request to use default credentials, but refused by target after it has been changed to {0}'.format(self.tmppasswd))
         if not isdefault:
             self._setup_xcc_account(user, passwd, wc)
     self._convert_sha256account(user, passwd, wc)
     cd = self.configmanager.get_node_attributes(
         nodename, ['secret.hardwaremanagementuser',
                    'secret.hardwaremanagementpassword',
                    'hardwaremanagement.manager', 'hardwaremanagement.method', 'console.method'],
                    True)
     cd = cd.get(nodename, {})
     if (cd.get('hardwaremanagement.method', {}).get('value', 'ipmi') != 'redfish'
             or cd.get('console.method', {}).get('value', None) == 'ipmi'):
         nwc = wc.dupe()
         nwc.set_basic_credentials(self._currcreds[0], self._currcreds[1])
         rsp = nwc.grab_json_response('/redfish/v1/Managers/1/NetworkProtocol')
         if not rsp.get('IPMI', {}).get('ProtocolEnabled', True):
             # User has indicated IPMI support, but XCC is currently disabled
             # change XCC to be consistent
             _, _ = nwc.grab_json_response_with_status(
                     '/redfish/v1/Managers/1/NetworkProtocol',
                     {'IPMI': {'ProtocolEnabled': True}}, method='PATCH')
     if ('hardwaremanagement.manager' in cd and
             cd['hardwaremanagement.manager']['value'] and
             not cd['hardwaremanagement.manager']['value'].startswith(
                 'fe80::')):
         newip = cd['hardwaremanagement.manager']['value']
         newipinfo = getaddrinfo(newip, 0)[0]
         newip = newipinfo[-1][0]
         if ':' in newip:
             raise exc.NotImplementedException('IPv6 remote config TODO')
         netconfig = netutil.get_nic_config(self.configmanager, nodename, ip=newip)
         newmask = netutil.cidr_to_mask(netconfig['prefix'])
         currinfo = wc.grab_json_response('/api/providers/logoninfo')
         currip = currinfo.get('items', [{}])[0].get('ipv4_address', '')
         # do not change the ipv4_config if the current config looks right already
         if currip != newip:
             statargs = {
                 'ENET_IPv4Ena': '1', 'ENET_IPv4AddrSource': '0',
                 'ENET_IPv4StaticIPAddr': newip, 'ENET_IPv4StaticIPNetMask': newmask
                 }
             if netconfig['ipv4_gateway']:
                 statargs['ENET_IPv4GatewayIPAddr'] = netconfig['ipv4_gateway']
             wc.grab_json_response('/api/dataset', statargs)
     elif self.ipaddr.startswith('fe80::'):
         self.configmanager.set_node_attributes(
             {nodename: {'hardwaremanagement.manager': self.ipaddr}})
     else:
         raise exc.TargetEndpointUnreachable(
             'hardwaremanagement.manager must be set to desired address (No IPv6 Link Local detected)')
     wc.grab_json_response('/api/providers/logout')
     ff = self.info.get('attributes', {}).get('enclosure-form-factor', '')
     if ff not in ('dense-computing', [u'dense-computing']):
         return
     enclosureuuid = self.info.get('attributes', {}).get('chassis-uuid', [None])[0]
     if enclosureuuid:
         enclosureuuid = enclosureuuid.lower()
         em = self.configmanager.get_node_attributes(nodename,
                                                     'enclosure.manager')
         em = em.get(nodename, {}).get('enclosure.manager', {}).get(
             'value', None)
         # ok, set the uuid of the manager...
         if em:
             self.configmanager.set_node_attributes(
                 {em: {'id.uuid': enclosureuuid}})