diff options
author | Peter Mikus <pmikus@cisco.com> | 2019-02-23 16:27:07 +0000 |
---|---|---|
committer | Peter Mikus <pmikus@cisco.com> | 2019-05-22 09:30:11 +0000 |
commit | 04ea580e111ddf5be6101be1fbfe9fde56f1a214 (patch) | |
tree | 09247ed50f1da5e09b79dcf41a05b38afeaa4ee2 /resources/tools/testbed-setup/cimc | |
parent | c6cd03e08d9429168b0e183b8dcbce991112f279 (diff) |
Ansible: Add CIMC/IPMI/COBBLER
- added tasks and handlers for CIMC, IPMI, COBBLER
- allows provisioning of servers via COBBLER
Change-Id: I64080069260dabb8a6e3b648aeff12f109d3f7c2
Signed-off-by: Peter Mikus <pmikus@cisco.com>
Diffstat (limited to 'resources/tools/testbed-setup/cimc')
-rwxr-xr-x | resources/tools/testbed-setup/cimc/cimc.py | 95 | ||||
-rw-r--r-- | resources/tools/testbed-setup/cimc/cimclib.py | 414 |
2 files changed, 0 insertions, 509 deletions
diff --git a/resources/tools/testbed-setup/cimc/cimc.py b/resources/tools/testbed-setup/cimc/cimc.py deleted file mode 100755 index 2e0fc42a25..0000000000 --- a/resources/tools/testbed-setup/cimc/cimc.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/python -# -# Copyright (c) 2016 Cisco and/or its affiliates. -# 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 cimclib -import argparse - -parser = argparse.ArgumentParser() -parser.add_argument("ip", help="CIMC IP address") -parser.add_argument("-u", "--username", help="CIMC username (admin)", - default="admin") -parser.add_argument("-p", "--password", help="CIMC password (cisco123)", - default="cisco123") -parser.add_argument("-d", "--debug", help="Enable debugging", action="count", - default=0) - -parser.add_argument("-i", "--initialize", - help="Initialize args.ip: Power-Off, reset BIOS defaults, Enable console redir, get LOM MAC addr", - action='store_true') -parser.add_argument("-s", "--set", - help="Set specific BIOS settings", action='append') -parser.add_argument("--wipe", help="Delete all virtual drives", - action='store_true') -parser.add_argument("-r", "--raid", help="Create RAID array", - action='store_true') -parser.add_argument("-rl", "--raid-level", help="RAID level", default='10') -parser.add_argument("-rs", "--raid-size", help="RAID size", default=3*571250) -parser.add_argument("-rd", "--raid-disks", - help="RAID disks ('[1,2][3,4][5,6]')", - default='[1,2][3,4][5,6]') -parser.add_argument("-pxe", "--boot-pxe", help="Reboot using PXE", - action='store_true') -parser.add_argument("-hdd", "--boot-hdd", help="Boot using HDD on next boot", - action='store_true') -parser.add_argument("-poff", "--power-off", help="Power Off", - action='store_true') -parser.add_argument("-pon", "--power-on", help="Power On", action='store_true') -parser.add_argument("-m", "--mac-table", - help="Show interface MAC address table", - action='store_true') - -args = parser.parse_args() - -cookie = cimclib.login(args.ip, args.username, args.password) - -if args.wipe: - cimclib.deleteAllVirtualDrives(args.ip, cookie, args.debug) - -if args.raid: - cimclib.createRaid(args.ip, cookie, "raid-virl", args.raid_level, args.raid_size, args.raid_disks, args.debug) - -if args.initialize: - cimclib.powerOff(args.ip, cookie) - cimclib.restoreBiosDefaultSettings(args.ip, cookie, args.debug) - cimclib.enableConsoleRedir(args.ip, cookie, args.debug) - cimclib.powerOn(args.ip, cookie, args.debug) - cimclib.bootIntoUefi(args.ip, cookie, args.debug) - lom_mac = cimclib.getLOMMacAddress(args.ip, cookie, args.debug) - print "Host {} LOM MAC address: {}".format(args.ip, lom_mac) - -if args.set: - cimclib.setBiosSettings(args.ip, cookie, args.set, args.debug) - -if args.boot_pxe: - cimclib.bootPXE(args.ip, cookie, args.debug) - -if args.boot_hdd: - cimclib.bootHDDPXE(args.ip, cookie, args.debug) - -if args.power_off: - cimclib.powerOff(args.ip, cookie, args.debug) - -if args.power_on: - cimclib.powerOn(args.ip, cookie, args.debug) - -if args.mac_table: - maclist = cimclib.getMacAddresses(args.ip, cookie, args.debug) - - for k in sorted(maclist.keys()): - print "{}:".format(k) - for p in sorted(maclist[k].keys()): - print " {} - {}".format(p, maclist[k][p]) - -cimclib.logout(args.ip, cookie) diff --git a/resources/tools/testbed-setup/cimc/cimclib.py b/resources/tools/testbed-setup/cimc/cimclib.py deleted file mode 100644 index f91832e0c9..0000000000 --- a/resources/tools/testbed-setup/cimc/cimclib.py +++ /dev/null @@ -1,414 +0,0 @@ -#!/usr/bin/python -# -# Copyright (c) 2016 Cisco and/or its affiliates. -# 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 requests -import xml.etree.ElementTree as et -import re - -from requests.packages.urllib3.exceptions import InsecureRequestWarning -requests.packages.urllib3.disable_warnings(InsecureRequestWarning) - -BASEDN = "sys/rack-unit-1" - -### -### Helper function - iterate through a list in pairs -### -def chunks(lst, chunksize): - """Yield successive n-sized chunks from l.""" - for i in range(0, len(lst), chunksize): - yield lst[i:i+chunksize] - -### -### Helper function: Perform an XML request to CIMC -### -def xml_req(ip, xml, debug=False): - if debug: - print "DEBUG: XML-REQUEST:" - et.dump(xml) - headers = {'Content-Type': 'text/xml'} - req = requests.post('https://' + ip + '/nuova', headers=headers, - verify=False, data=et.tostring(xml)) - resp = et.fromstring(req.content) - if debug: - print "DEBUG: XML-RESPONSE:" - et.dump(resp) - - if resp.tag == 'error': - if debug: - print "XML response contains error:" - et.dump(error) - raise RuntimeError('XML response contains error') - return resp - -### -### Authenticate (Log-In) to CIMC and obtain a cookie -### -def login(ip, username, password): - reqxml = et.Element('aaaLogin', - attrib={'inName':username, 'inPassword':password}) - respxml = xml_req(ip, reqxml) - try: - cookie = respxml.attrib['outCookie'] - except: - print "Cannot find cookie in CIMC server response." - print "CIMC server output:" - et.dump(respxml) - raise - - return cookie - -### -### Log out from CIMC. -### -### Note: There is a maximum session limit in CIMC and sessions to take a long -### time (10 minutes) to time out. Therefore, calling this function during -### testing is essential, otherwise one will quickly exhaust all available -### sessions. -### -def logout(ip, cookie): - reqxml = et.Element('aaaLogout', attrib={'cookie': cookie, - 'inCookie': cookie}) - xml_req(ip, reqxml) - -### -### Power off the host -### -def powerOff(ip, cookie, debug=False): - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'false', - 'dn': BASEDN}) - inconfig = et.SubElement(reqxml, 'inConfig') - et.SubElement(inconfig, 'computeRackUnit', - attrib={'adminPower': 'down', 'dn': BASEDN}) - respxml = xml_req(ip, reqxml, debug) - return respxml - -### -### Power on the host -### -def powerOn(ip, cookie, debug=False): - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'false', - 'dn': BASEDN}) - inconfig = et.SubElement(reqxml, 'inConfig') - et.SubElement(inconfig, 'computeRackUnit', - attrib={'adminPower': 'up', 'dn': BASEDN}) - respxml = xml_req(ip, reqxml, debug) - return respxml - -### -### Restore BIOS to default settings -### -def restoreBiosDefaultSettings(ip, cookie, debug=False): - reqxml = et.Element('configResolveClass', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'classId': 'biosPlatformDefaults'}) - respxml = xml_req(ip, reqxml, debug) - - configs = respxml.find('outConfigs') - defaults = configs.find('biosPlatformDefaults') - - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'dn': "{}/bios/bios-settings".format(BASEDN)}) - inconfig = et.SubElement(reqxml, 'inConfig') - biosset = et.SubElement(inconfig, 'biosSettings') - biosset.extend(defaults) - - respxml = xml_req(ip, reqxml, debug) - return respxml - -### -### Apply specified BIOS settings. -### -### These must be a list of strings in XML format. Not currently very -### user friendly. Format can either be obtained from CIMC -### documention, or by setting them manually and then fetching -### BIOS settings via CIMC XML API. -### -def setBiosSettings(ip, cookie, settings, debug=False): - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'dn': "{}/bios/bios-settings".format(BASEDN)}) - inconfig = et.SubElement(reqxml, 'inConfig') - biosset = et.SubElement(inconfig, 'biosSettings') - print "Applying settings:" - print settings - for s in settings: - x = et.fromstring(s) - et.dump(x) - biosset.append(et.fromstring(s)) - - respxml = xml_req(ip, reqxml, debug) - return respxml -### -### Delete any existing virtual drives -### -### WARNING: THIS WILL ERASE ALL DATA ON ALL DISKS, WITHOUT ANY CONFIRMATION -### QUESTION. -### -### The server must be POWERED ON for this to succeed. -### -def deleteAllVirtualDrives(ip, cookie, debug=False): - reqxml = et.Element('configResolveClass', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'classId': 'storageController'}) - respxml = xml_req(ip, reqxml, debug) - - configs = respxml.find('outConfigs') - for sc in configs.iter('storageController'): - if debug: - print "DEBUG: SC DN {} ID {}".format(sc.attrib['dn'], - sc.attrib['id']) - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'dn': sc.attrib['dn']}) - inconfig = et.SubElement(reqxml, 'inConfig') - et.SubElement(inconfig, 'storageController', - attrib={'adminAction': 'delete-all-vds-reset-pds', - 'dn': sc.attrib['dn']}) - xml_req(ip, reqxml, debug) - -### -### Create a single RAID-10 across all drives. -### -### The server must be POWERED ON for this to succeed. -### -def createRaid10_all(ip, cookie, debug=False): - reqxml = et.Element('configResolveClass', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'classId': 'storageController'}) - respxml = xml_req(ip, reqxml, debug) - - configs = respxml.find('outConfigs') - for sc in configs.iter('storageController'): - if debug: - print "DEBUG: SC DN {} ID {}".format(sc.attrib['dn'], - sc.attrib['id']) - # - # Find disk size and number of disks - # - disks = [] - total_size = 0 - for pd in sc.iter('storageLocalDisk'): - if debug: - print "DEBUG: PD {} size {}".format(pd.attrib['id'], - pd.attrib['coercedSize']) - disks.append(pd.attrib['id']) - total_size += int(pd.attrib['coercedSize'].split(' ')[0]) - - # - # Create a RAID10 array of all available disks, as in: - # [1,2][3,4][5,6][7,8][9,10][11,12][13,14][15,16][17,18] - # - raid_size = total_size/2 - raid_span = '' - for p in list(chunks(disks, 2)): - raid_span += "[{},{}]".format(p[0], p[1]) - - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'dn': sc.attrib['dn']}) - inconfig = et.SubElement(reqxml, 'inConfig') - et.SubElement(inconfig, - 'storageVirtualDriveCreatorUsingUnusedPhysicalDrive', - attrib={'virtualDriveName': 'raid10-all', - 'size': str(raid_size)+' MB', - 'raidLevel': '10', 'driveGroup': raid_span, - 'adminState': 'trigger'}) - - xml_req(ip, reqxml, debug) - -### -### Create a single RAID across from empty drives as provided. -### -### The server must be POWERED ON for this to succeed. -### -def createRaid(ip, cookie, name, raidlevel, size, drives, debug=False): - reqxml = et.Element('configResolveClass', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'classId': 'storageController'}) - respxml = xml_req(ip, reqxml, debug) - - configs = respxml.find('outConfigs') - for sc in configs.iter('storageController'): - if debug: - print "DEBUG: SC DN {} ID {}".format(sc.attrib['dn'], - sc.attrib['id']) - - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'dn': sc.attrib['dn']}) - inconfig = et.SubElement(reqxml, 'inConfig') - et.SubElement(inconfig, - 'storageVirtualDriveCreatorUsingUnusedPhysicalDrive', - attrib={'virtualDriveName': name, - 'size': str(size)+' MB', - 'raidLevel': raidlevel, - 'driveGroup': drives, - 'adminState': 'trigger'}) - - xml_req(ip, reqxml, debug) - -### -### Enable Serial-Over-LAN (SOL) console and redirect BIOS output to -### serial console -### -def enableConsoleRedir(ip, cookie, debug=False): - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'false', - 'dn': "{}/bios/bios-settings".format(BASEDN)}) - inconfig = et.SubElement(reqxml, 'inConfig') - bs = et.SubElement(inconfig, 'biosSettings', - attrib={'dn': "{}/bios/bios-settings".format(BASEDN)}) - et.SubElement(bs, - 'biosVfConsoleRedirection', - attrib={'vpConsoleRedirection': 'com-0', - 'vpBaudRate': '115200'}) - respxml = xml_req(ip, reqxml, debug) - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'false', - 'dn': BASEDN+'/sol-if'}) - inconfig = et.SubElement(reqxml, 'inConfig') - et.SubElement(inconfig, 'solIf', - attrib={'dn': BASEDN+'/sol-if', 'adminState': 'enable', - 'speed': '115200', 'comport': 'com0'}) - respxml = xml_req(ip, reqxml, debug) - return respxml - -### -### Boot into UEFI bootloader (we may use this to "park" the host in -### powered-on state) -### -def bootIntoUefi(ip, cookie, debug=False): - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'false', - 'dn': BASEDN+'/boot-policy'}) - inconfig = et.SubElement(reqxml, 'inConfig') - bootDef = et.SubElement(inconfig, 'lsbootDef', - attrib={'dn': BASEDN+'/boot-policy', - 'rebootOnUpdate': 'yes'}) - et.SubElement(bootDef, 'lsbootEfi', - attrib={'rn': 'efi-read-only', 'order': '1', - 'type': 'efi'}) - - respxml = xml_req(ip, reqxml, debug) - return respxml - -### -### Boot via PXE. Reboot immediately. -### -def bootPXE(ip, cookie, debug=False): - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'false', - 'dn': BASEDN+'/boot-policy'}) - inconfig = et.SubElement(reqxml, 'inConfig') - bootDef = et.SubElement(inconfig, 'lsbootDef', - attrib={'dn': BASEDN+'/boot-policy', - 'rebootOnUpdate': 'yes'}) - et.SubElement(bootDef, 'lsbootLan', - attrib={'rn': 'lan-read-only', 'order': '1', - 'type': 'lan', 'prot': 'pxe'}) - - respxml = xml_req(ip, reqxml, debug) - return respxml - - -### -### Boot via Local HDD first, then via PXE. Do not reboot immediately. -### -def bootHDDPXE(ip, cookie, debug=False): - reqxml = et.Element('configConfMo', - attrib={'cookie': cookie, 'inHierarchical': 'false', - 'dn': BASEDN+'/boot-policy'}) - inconfig = et.SubElement(reqxml, 'inConfig') - bootDef = et.SubElement(inconfig, 'lsbootDef', - attrib={'dn': BASEDN+'/boot-policy', - 'rebootOnUpdate': 'no'}) - storage = et.SubElement(bootDef, 'lsbootStorage', - attrib={'rn': 'storage-read-write', - 'access': 'read-write', - 'order': '1', 'type': 'storage'}) - et.SubElement(storage, 'lsbootLocalStorage', - attrib={'rn': 'local-storage'}) - et.SubElement(bootDef, 'lsbootLan', - attrib={'rn': 'lan-read-only', 'order': '2', - 'type': 'lan', 'prot': 'pxe'}) - - respxml = xml_req(ip, reqxml, debug) - return respxml - -### -### Return LOM port 1 MAC address -### -def getLOMMacAddress(ip, cookie, debug=False): - reqxml = et.Element('configResolveClass', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'classId': 'networkAdapterUnit'}) - respxml = xml_req(ip, reqxml, debug) - reqxml = et.Element('configResolveDn', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'dn': BASEDN+'/network-adapter-L/eth-1'}) - respxml = xml_req(ip, reqxml, debug) - - oc = respxml.find('outConfig') - netw = oc.find('networkAdapterEthIf') - if debug: - print "DEBUG: MAC address is {}".format(netw.get('mac')) - return netw.get('mac') - -### -### Return all port MAC addresses -### -def getMacAddresses(ip, cookie, debug=False): - maclist = {} - reqxml = et.Element('configResolveClass', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'classId': 'networkAdapterUnit'}) - respxml = xml_req(ip, reqxml, debug) - oc = respxml.find('outConfigs') - for adapter in oc.iter('networkAdapterUnit'): - if debug: - print "DEBUG: ADAPTER SLOT {} MODEL {}".format(adapter.attrib['slot'], - adapter.attrib['model']) - slot = adapter.attrib['slot'] - maclist[slot] = {} - for port in adapter.iter('networkAdapterEthIf'): - if debug: - print "DEBUG: SLOT {} PORT {} MAC {}".format(slot, - port.attrib['id'], - port.attrib['mac']) - maclist[slot][port.attrib['id']] = port.attrib['mac'].lower() - - reqxml = et.Element('configResolveClass', - attrib={'cookie': cookie, 'inHierarchical': 'true', - 'classId': 'adaptorUnit'}) - respxml = xml_req(ip, reqxml, debug) - oc = respxml.find('outConfigs') - for adapter in oc.iter('adaptorUnit'): - if debug: - print "DEBUG: VIC ADAPTER SLOT {} MODEL {}".format(adapter.attrib['pciSlot'], - adapter.attrib['model']) - slot = adapter.attrib['pciSlot'] - maclist[slot] = {} - for port in adapter.iter('adaptorHostEthIf'): - portnum = int(re.sub('eth([0-9]+)', '\\1', port.attrib['name']))+1 - if debug: - print "DEBUG: VIC SLOT {} PORT {} MAC {}".format(slot, - portnum, - port.attrib['mac']) - maclist[slot][portnum] = port.attrib['mac'].lower() - - return maclist |