diff --git a/confluent_server/confluent/discovery/core.py b/confluent_server/confluent/discovery/core.py index b734cece..fd302f8b 100644 --- a/confluent_server/confluent/discovery/core.py +++ b/confluent_server/confluent/discovery/core.py @@ -74,6 +74,7 @@ import confluent.discovery.handlers.tsm as tsm import confluent.discovery.handlers.pxe as pxeh import confluent.discovery.handlers.smm as smm import confluent.discovery.handlers.xcc as xcc +import confluent.discovery.handlers.xcc3 as xcc3 import confluent.discovery.handlers.megarac as megarac import confluent.exceptions as exc import confluent.log as log @@ -114,7 +115,7 @@ nodehandlers = { 'service:lenovo-smm': smm, 'service:lenovo-smm2': smm, 'lenovo-xcc': xcc, - 'lenovo-xcc3': xcc, + 'lenovo-xcc3': xcc3, 'megarac-bmc': megarac, 'service:management-hardware.IBM:integrated-management-module2': imm, 'pxe-client': pxeh, diff --git a/confluent_server/confluent/discovery/handlers/redfishbmc.py b/confluent_server/confluent/discovery/handlers/redfishbmc.py index eed401de..97629f36 100644 --- a/confluent_server/confluent/discovery/handlers/redfishbmc.py +++ b/confluent_server/confluent/discovery/handlers/redfishbmc.py @@ -80,6 +80,7 @@ class NodeHandler(generic.NodeHandler): wc = webclient.SecureHTTPConnection(self.ipaddr, 443, verifycallback=self.validate_cert) wc.set_basic_credentials(defuser, defpass) wc.set_header('Content-Type', 'application/json') + wc.set_header('Accept', 'application/json') authmode = 0 if not self.trieddefault: rsp, status = wc.grab_json_response_with_status('/redfish/v1/Managers') @@ -114,7 +115,7 @@ class NodeHandler(generic.NodeHandler): if status > 400: self.trieddefault = True if status == 401: - wc.set_basic_credentials(self.DEFAULT_USER, self.targpass) + wc.set_basic_credentials(defuser, self.targpass) rsp, status = wc.grab_json_response_with_status('/redfish/v1/Managers') if status == 200: # Default user still, but targpass self.currpass = self.targpass @@ -236,7 +237,10 @@ class NodeHandler(generic.NodeHandler): break else: wc.set_header('If-Match', '*') - rsp, status = wc.grab_json_response_with_status(actualnics[0], {'IPv4StaticAddresses': [newconfig]}, method='PATCH') + rsp, status = wc.grab_json_response_with_status(actualnics[0], { + 'DHCPv4': {'DHCPEnabled': False}, + 'IPv4StaticAddresses': [newconfig]}, method='PATCH') + elif self.ipaddr.startswith('fe80::'): self.configmanager.set_node_attributes( {nodename: {'hardwaremanagement.manager': self.ipaddr}}) diff --git a/confluent_server/confluent/discovery/handlers/xcc3.py b/confluent_server/confluent/discovery/handlers/xcc3.py new file mode 100644 index 00000000..780de4fc --- /dev/null +++ b/confluent_server/confluent/discovery/handlers/xcc3.py @@ -0,0 +1,102 @@ +# Copyright 2024 Lenovo +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import confluent.discovery.handlers.redfishbmc as redfishbmc +import eventlet.support.greendns +import confluent.util as util + +webclient = eventlet.import_patched('pyghmi.util.webclient') + + + +getaddrinfo = eventlet.support.greendns.getaddrinfo + + +class NodeHandler(redfishbmc.NodeHandler): + + def get_firmware_default_account_info(self): + return ('USERID', 'PASSW0RD') + + def scan(self): + ip, port = self.get_web_port_and_ip() + c = webclient.SecureHTTPConnection(ip, port, + verifycallback=self.validate_cert) + i = c.grab_json_response('/api/providers/logoninfo') + modelname = i.get('items', [{}])[0].get('machine_name', None) + if modelname: + self.info['modelname'] = modelname + for attrname in list(self.info.get('attributes', {})): + val = self.info['attributes'][attrname] + if '-uuid' == attrname[-5:] and len(val) == 32: + val = val.lower() + self.info['attributes'][attrname] = '-'.join([val[:8], val[8:12], val[12:16], val[16:20], val[20:]]) + attrs = self.info.get('attributes', {}) + room = attrs.get('room-id', None) + if room: + self.info['room'] = room + rack = attrs.get('rack-id', None) + if rack: + self.info['rack'] = rack + name = attrs.get('name', None) + if name: + self.info['hostname'] = name + unumber = attrs.get('lowest-u', None) + if unumber: + self.info['u'] = unumber + location = attrs.get('location', None) + if location: + self.info['location'] = location + mtm = attrs.get('enclosure-machinetype-model', None) + if mtm: + self.info['modelnumber'] = mtm.strip() + sn = attrs.get('enclosure-serial-number', None) + if sn: + self.info['serialnumber'] = sn.strip() + if attrs.get('enclosure-form-factor', None) == 'dense-computing': + encuuid = attrs.get('chassis-uuid', None) + if encuuid: + self.info['enclosure.uuid'] = fixuuid(encuuid) + slot = int(attrs.get('slot', 0)) + if slot != 0: + self.info['enclosure.bay'] = slot + + def validate_cert(self, certificate): + fprint = util.get_fingerprint(self.https_cert) + return util.cert_matches(fprint, certificate) + + +def remote_nodecfg(nodename, cfm): + cfg = cfm.get_node_attributes( + nodename, 'hardwaremanagement.manager') + ipaddr = cfg.get(nodename, {}).get('hardwaremanagement.manager', {}).get( + 'value', None) + ipaddr = ipaddr.split('/', 1)[0] + ipaddr = getaddrinfo(ipaddr, 0)[0][-1] + if not ipaddr: + raise Exception('Cannot remote configure a system without known ' + 'address') + info = {'addresses': [ipaddr]} + nh = NodeHandler(info, cfm) + nh.config(nodename) + + +if __name__ == '__main__': + import confluent.config.configmanager as cfm + c = cfm.ConfigManager(None) + import sys + info = {'addresses': [[sys.argv[1]]]} + print(repr(info)) + testr = NodeHandler(info, c) + testr.config(sys.argv[2]) +