WIP modules and states for managing Dell FX2 chassis via salt-proxy

This commit is contained in:
C. R. Oldham 2015-10-13 16:00:00 -06:00
parent 36f05fb526
commit cca310eee0
3 changed files with 1536 additions and 0 deletions

1159
salt/modules/dracr.py Normal file

File diff suppressed because it is too large Load Diff

99
salt/proxy/fx2.py Normal file
View File

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
'''
Proxy minion interface module for managing Dell FX2 chassis
'''
from __future__ import absolute_import
# Import python libs
import logging
import salt.utils
import salt.utils.http
# This must be present or the Salt loader won't load this module
__proxyenabled__ = ['fx2']
# Variables are scoped to this module so we can have persistent data
# across calls to fns in here.
GRAINS_CACHE = {}
DETAILS = {}
# Want logging!
log = logging.getLogger(__file__)
def __virtual__():
'''
Only return if all the modules are available
'''
if not salt.utils.which('racadm'):
log.critical('fx2 proxy minion needs "racadm" to be installed.')
return False
return True
def init(opts):
'''
Every proxy module needs an 'init', though you can
just put a 'pass' here if it doesn't need to do anything.
'''
# Save the login details
DETAILS['admin_username'] = opts['proxy']['admin_username']
DETAILS['admin_password'] = opts['proxy']['admin_password']
DETAILS['host'] = opts['proxy']['host']
def grains():
'''
Get the grains from the proxied device
'''
if not GRAINS_CACHE:
r = __salt__['dracr.system_info'](host=DETAILS['host'],
admin_username=DETAILS['admin_username'],
admin_password=DETAILS['admin_password'])
GRAINS_CACHE = r
return GRAINS_CACHE
def grains_refresh():
'''
Refresh the grains from the proxied device
'''
GRAINS_CACHE = {}
return grains()
def chconfig(cmd, *args, **kwargs):
# Strip the __pub_ keys...is there a better way to do this?
for k in kwargs.keys():
if k.startswith('__pub_'):
kwargs.pop(k)
if 'dracr.'+cmd not in __salt__:
return {'retcode': -1, 'message': 'dracr.' + cmd + ' is not available'}
else:
return __salt__['dracr.'+cmd](*args, **kwargs)
def ping():
'''
Is the REST server up?
'''
r = __salt__['dracr.system_info'](host=DETAILS['host'],
admin_username=DETAILS['admin_username'],
admin_password=DETAILS['admin_password'])
if r.get('retcode', 0) == 1:
return False
else:
return True
try:
return r['dict'].get('ret', False)
except Exception:
return False
def shutdown(opts):
'''
For this proxy shutdown is a no-op
'''
log.debug('fx2 proxy shutdown() called...')

278
salt/states/dellchassis.py Normal file
View File

@ -0,0 +1,278 @@
'''
Manage chassis via Salt Proxies.
.. versionadded:: 2015.8.2
Example managing a Dell chassis:
.. code-block:: yaml
my-dell-chassis:
chassis.dell:
- name: my-dell-chassis
- location: my-location
- mode: 2
- idrac_launch: 1
- slot_names:
- 1: my-slot-name
- 2: my-other-slot-name
- blade_power:
- server-1: on
- server-2: off
- server-3: powercycle
'''
# Import python libs
from __future__ import absolute_import
import logging
# Import Salt Libs
log = logging.getLogger(__name__)
def __virtual__():
return 'chassis.cmd' in __salt__
def dell(name, location=None, mode=None, idrac_launch=None, slot_names=None):
'''
Manage a Dell Chassis.
name
The name of the chassis.
location
The location of the chassis.
mode
The management mode of the chassis. Viable options are:
- 0: None
- 1: Monitor
- 2: Manage and Monitor
idrac_launch
The iDRAC launch method of the chassis. Viable options are:
- 0: Disabled (launch iDRAC using IP address)
- 1: Enabled (launch iDRAC using DNS name)
slot_names
The names of the slots, provided as a list.
Example:
.. code-block:: yaml
my-dell-chassis:
chassis.dell:
- name: my-dell-chassis
- location: my-location
- mode: 2
- idrac_launch: 1
- slot_names:
- 1: my-slot-name
- 2: my-other-slot-name
'''
ret = {'name': name,
'result': True,
'changes': {},
'comment': ''}
chassis_cmd = 'chassis.cmd'
cfg_tuning = 'cfgRacTuning'
mode_cmd = 'cfgRacTuneChassisMgmtAtServer'
launch_cmd = 'cfgRacTuneIdracDNSLaunchEnable'
current_name = __salt__[chassis_cmd]('get_chassis_name')
if name != current_name:
ret['changes'].update({'Name':
{'Old': current_name,
'New': name}})
if location:
current_location = __salt__[chassis_cmd]('get_chassis_location')
if location != current_location:
ret['changes'].update({'Location':
{'Old': current_location,
'New': location}})
if mode:
current_mode = __salt__[chassis_cmd]('get_general', cfg_tuning, mode_cmd)
if mode != current_mode:
ret['changes'].update({'Management Mode':
{'Old': current_mode,
'New': mode}})
if idrac_launch:
current_launch_method = __salt__[chassis_cmd]('get_general', cfg_tuning, launch_cmd)
if idrac_launch != current_launch_method:
ret['changes'].update({'iDrac Launch Method':
{'Old': current_launch_method,
'New': idrac_launch}})
if slot_names:
current_slot_names = __salt__[chassis_cmd]('list_slotnames')
for item in slot_names:
slot_name = slot_names.get(item)
current_slot_name = current_slot_names.get(item).get('slotname')
if current_slot_name != slot_name:
old = {item: current_slot_name}
new = {item: slot_name}
if ret['changes'].get('Slot Names') is None:
ret['changes'].update({'Slot Names':
{'Old': {item: current_slot_name},
'New': {item: slot_name}}})
ret['changes']['Slot Names']['Old'].update(old)
ret['changes']['Slot Names']['New'].update(new)
if ret['changes'] == {}:
ret['comment'] = 'Dell chassis is already in the desired state.'
return ret
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'Dell chassis configuration will change.'
return ret
# Finally, set the necessary configurations on the chassis.
name = __salt__[chassis_cmd]('set_chassis_name', name)
if location:
location = __salt__[chassis_cmd]('set_chassis_location', location)
if mode:
mode = __salt__[chassis_cmd]('set_general', cfg_tuning, mode_cmd, mode)
if idrac_launch:
idrac_launch = __salt__[chassis_cmd]('set_general', cfg_tuning, launch_cmd, idrac_launch)
if slot_names:
slot_rets = []
for key, val in slot_names.iteritems():
slot_name = val.get('slotname')
slot_rets.append(__salt__[chassis_cmd]('set_slotname', key, slot_name))
if any(slot_rets) is False:
slot_names = False
else:
slot_names = True
if any([name, location, mode, idrac_launch, slot_names]) is False:
ret['result'] = False
ret['comment'] = 'There was an error setting the Dell chassis.'
ret['comment'] = 'Dell chassis was updated.'
return ret
def dell_switch(name, ip=None, netmask=None, gateway=None, dhcp=None,
password=None, snmp=None):
'''
Manage switches in a Dell Chassis.
name
The switch designation (e.g. switch-1, switch-2)
ip
The Static IP Address of the switch
netmask
The netmask for the static IP
gateway
The gateway for the static IP
dhcp
True: Enable DHCP
False: Do not change DHCP setup
(disabling DHCP is automatic when a static IP is set)
password
The access (root) password for the switch
snmp
The SNMP community string for the switch
Example:
.. code-block:: yaml
my-dell-chassis:
chassis.dell_switch:
- switch: switch-1
- ip: 192.168.1.1
- netmask: 255.255.255.0
- gateway: 192.168.1.254
- dhcp: True
- password: secret
- snmp: public
'''
ret = {'name': name,
'result': True,
'changes': {},
'comment': ''}
current_nic = __salt__['chassis.cmd']('network_info', module=name)
if current_nic.get('retcode', 0) != 0:
ret['result'] = False
ret['comment'] = current_nic['stdout']
return ret
if ip or netmask or gateway:
if not ip:
ip = current_nic['Network']['IP Address']
if not netmask:
ip = current_nic['Network']['Subnet Mask']
if not gateway:
ip = current_nic['Network']['Gateway']
if current_nic['Network']['DHCP Enabled'] == '0' and dhcp:
ret['changes'].update({'DHCP': { 'Old': { 'DHCP Enabled': current_nic['Network']['DHCP Enabled'] },
'New': { 'DHCP Enabled': dhcp }}})
if ((ip or netmask or gateway) and not dhcp and (ip != current_nic['Network']['IP Address'] or
netmask != current_nic['Network']['Subnet Mask'] or
gateway != current_nic['Network']['Gateway'])):
ret['changes'].update({'IP': {'Old': current_nic['Network'],
'New': {'IP Address': ip,
'Subnet Mask': netmask,
'Gateway': gateway}}})
if password:
if 'New' not in ret['changes']:
ret['changes']['New'] = {}
ret['changes']['New'].update({'Password': '*****'})
if snmp:
if 'New' not in ret['changes']:
ret['changes']['New'] = {}
ret['changes']['New'].update({'SNMP': '*****'})
if ret['changes'] == {}:
ret['comment'] = 'Switch ' + name + ' is already in desired state'
return ret
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'Switch ' + name + ' configuration will change'
return ret
# Finally, set the necessary configurations on the chassis.
dhcp_ret = net_ret = password_ret = snmp_ret = True
if dhcp:
dhcp_ret = __salt__['chassis.cmd']('set_niccfg', module=name, dhcp=dhcp)
if ip or netmask or gateway:
net_ret = __salt__['chassis.cmd']('set_niccfg', ip, netmask, gateway, module=name)
if password:
password_ret = __salt__['chassis.cmd']('deploy_password', 'root', password, module=name)
if snmp:
snmp_ret = __salt__['chassis.cmd']('deploy_snmp', password, module=name)
if any([password_ret, snmp_ret, net_ret, dhcp_ret]) is False:
ret['result'] = False
ret['comment'] = 'There was an error setting the switch {0}.'.format(name)
ret['comment'] = 'Dell chassis switch {0} was updated.'.format(name)
return ret