Skip to content

Commit

Permalink
Merge pull request #164 from jimi1283/powerpipe
Browse files Browse the repository at this point in the history
Reworking of power commands to use STDIN
  • Loading branch information
jimi-c committed May 7, 2012
2 parents 1a9ba99 + a9a2809 commit 6d9167e
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 49 deletions.
42 changes: 9 additions & 33 deletions cobbler/action_power.py
Expand Up @@ -69,8 +69,9 @@ def power(self, desired_state):
interested in maximum security should take that route.
"""

template = self.get_command_template()
template_file = open(template, "r")
power_command = utils.get_power(self.system.power_type)
if not power_command:
utils.die(self.logger,"no power type set for system")

meta = utils.blender(self.api, False, self.system)
meta["power_mode"] = desired_state
Expand All @@ -81,43 +82,34 @@ def power(self, desired_state):
if self.force_pass is not None:
meta["power_pass"] = self.force_pass

tmp = templar.Templar(self.api._config)
cmd = tmp.render(template_file, meta, None, self.system)
template_file.close()

cmd = cmd.strip()

self.logger.info("cobbler power configuration is:")

self.logger.info(" type : %s" % self.system.power_type)
self.logger.info(" address: %s" % self.system.power_address)
self.logger.info(" user : %s" % self.system.power_user)
self.logger.info(" id : %s" % self.system.power_id)

# if no username/password data, check the environment

if meta.get("power_user","") == "":
meta["power_user"] = os.environ.get("COBBLER_POWER_USER","")
if meta.get("power_pass","") == "":
meta["power_pass"] = os.environ.get("COBBLER_POWER_PASS","")

self.logger.info("- %s" % cmd)

# use shell so we can have mutliple power commands chained together
cmd = ['/bin/sh','-c', cmd]
template = utils.get_power_template(self.system.power_type)
tmp = templar.Templar(self.api._config)
template_data = tmp.render(template, meta, None, self.system)

# Try the power command 5 times before giving up.
# Some power switches are flakey
for x in range(0,5):
output, rc = utils.subprocess_sp(self.logger, cmd, shell=False)
output, rc = utils.subprocess_sp(self.logger, power_command, shell=False, input=template_data)
if rc == 0:
# If the desired state is actually a query for the status
# return different information than command return code
if desired_state == 'status':
match = re.match('(^Status:\s)(ON|OFF)', output)
match = re.match('(^Status:\s)(on|off)', output, re.IGNORECASE)
if match:
power_status = match.groups()[1]
if power_status == 'ON':
if power_status.lower() == 'on':
return True
else:
return False
Expand All @@ -132,19 +124,3 @@ def power(self, desired_state):

return rc

def get_command_template(self):

"""
In case the user wants to customize the power management commands,
we source the code for each command from /etc/cobbler and run
them through Cheetah.
"""

if self.system.power_type in [ "", "none" ]:
utils.die(self.logger,"Power management is not enabled for this system")

result = utils.get_power(self.system.power_type)
if not result:
utils.die(self.logger, "Invalid power management type for this system (%s, %s)" % (self.system.power_type, self.system.name))
return result

10 changes: 5 additions & 5 deletions cobbler/item_system.py
Expand Up @@ -54,11 +54,11 @@
["virt_auto_boot","<<inherit>>",0,"Virt Auto Boot",True,"Auto boot this VM?",0,"bool"],
["ctime",0,0,"",False,"",0,"float"],
["mtime",0,0,"",False,"",0,"float"],
["power_type","SETTINGS:power_management_default_type",0,"Type",True,"Power management script to use",utils.get_power_types(),"str"],
["power_address","",0,"Address",True,"Ex: power-device.example.org",0,"str"],
["power_user","",0,"Username ",True,"",0,"str"],
["power_pass","",0,"Password",True,"",0,"str"],
["power_id","",0,"ID",True,"Usually a plug number or blade name, if power type requires it",0,"str"],
["power_type","SETTINGS:power_management_default_type",0,"Power Management Type",True,"Power management script to use",utils.get_power_types(),"str"],
["power_address","",0,"Power Management Address",True,"Ex: power-device.example.org",0,"str"],
["power_user","",0,"Power Management Username ",True,"",0,"str"],
["power_pass","",0,"Power Management Password",True,"",0,"str"],
["power_id","",0,"Power Management ID",True,"Usually a plug number or blade name, if power type requires it",0,"str"],
["hostname","",0,"Hostname",True,"",0,"str"],
["gateway","",0,"Gateway",True,"",0,"str"],
["name_servers",[],0,"Name Servers",True,"space delimited",0,"list"],
Expand Down
41 changes: 30 additions & 11 deletions cobbler/utils.py
Expand Up @@ -1680,29 +1680,34 @@ def is_remote_file(file):
else:
return False

def subprocess_sp(logger, cmd, shell=True):
def subprocess_sp(logger, cmd, shell=True, input=None):
if logger is not None:
logger.info("running: %s" % cmd)

stdin = None
if input:
stdin = sub_process.PIPE

try:
sp = sub_process.Popen(cmd, shell=shell, stdout=sub_process.PIPE, stderr=sub_process.PIPE, close_fds=True)
sp = sub_process.Popen(cmd, shell=shell, stdin=stdin, stdout=sub_process.PIPE, stderr=sub_process.PIPE, close_fds=True)
except OSError:
if logger is not None:
log_exc(logger)
die(logger, "OS Error, command not found? While running: %s" % cmd)

(out,err) = sp.communicate()
(out,err) = sp.communicate(input)
rc = sp.returncode
if logger is not None:
logger.info("received on stdout: %s" % out)
logger.debug("received on stderr: %s" % err)
return out, rc

def subprocess_call(logger, cmd, shell=True):
data, rc = subprocess_sp(logger, cmd, shell=shell)
def subprocess_call(logger, cmd, shell=True, input=None):
data, rc = subprocess_sp(logger, cmd, shell=shell, input=input)
return rc

def subprocess_get(logger, cmd, shell=True):
data, rc = subprocess_sp(logger, cmd, shell=shell)
def subprocess_get(logger, cmd, shell=True, input=None):
data, rc = subprocess_sp(logger, cmd, shell=shell, input=input)
return data

def popen2(args, **kwargs):
Expand Down Expand Up @@ -1964,8 +1969,8 @@ def get_power_types():
Return all possible power types
"""
power_types = []
power_template = re.compile(r'power_(.*).template')
for x in glob.glob("/etc/cobbler/power/power_*.template"):
power_template = re.compile(r'fence_(.*)')
for x in glob.glob("/usr/sbin/fence_*"):
power_types.append(power_template.search(x).group(1))
power_types.sort()
return power_types
Expand All @@ -1975,11 +1980,25 @@ def get_power(powertype=None):
Return power command for type
"""
if powertype:
powerpath = "/etc/cobbler/power/power_%s.template" % powertype
if os.path.isfile(powerpath):
powerpath = "/usr/sbin/fence_%s" % powertype
if os.path.isfile(powerpath) and os.access(powerpath, os.X_OK):
return powerpath
return None

def get_power_template(powertype=None):
"""
Return power template for type
"""
if powertype:
powertemplate = "/etc/cobbler/power/fence_%s.template" % powertype
if os.path.isfile(powertemplate):
f = open(powertemplate)
template = f.read()
f.close()
return template
# return a generic template if a specific one wasn't found
return "action=$power_mode\nlogin=$power_user\npasswd=$power_pass\nipaddr=$power_address\nport=$power_id"

def get_shared_secret():
"""
The 'web.ss' file is regenerated each time cobblerd restarts and is
Expand Down

0 comments on commit 6d9167e

Please sign in to comment.