mirror of
https://github.com/xcat2/confluent.git
synced 2026-09-29 00:31:09 +00:00
Merge branch 'master' into discovery
This commit is contained in:
+101
-13
@@ -542,7 +542,7 @@ def get_session_node(shellargs):
|
||||
return None
|
||||
|
||||
|
||||
def conserver_command(filehandle, command):
|
||||
def conserver_command(filehandle, localcommand):
|
||||
# x - conserver has that as 'show baud', I am inclined to replace that with
|
||||
# 'request exclusive'
|
||||
# b - conserver has that as 'broadcast message', I'm tempted to use that
|
||||
@@ -557,33 +557,121 @@ def conserver_command(filehandle, command):
|
||||
# d - down a console... never used this...
|
||||
# L - toggle logging
|
||||
# w - who is on console
|
||||
while not command:
|
||||
ready, _, _ = select.select((filehandle,), (), (), 1)
|
||||
if ready:
|
||||
command += filehandle.read()
|
||||
if command[0] == '.':
|
||||
|
||||
cmdlen = 1
|
||||
localcommand = get_command_bytes(filehandle, localcommand, cmdlen)
|
||||
|
||||
if localcommand[0] == '.':
|
||||
print("disconnect]\r")
|
||||
quitconfetty(fullexit=consoleonly)
|
||||
elif command[0] == 'o':
|
||||
elif localcommand[0] == 'o':
|
||||
tlvdata.send(session.connection, {'operation': 'reopen',
|
||||
'path': currconsole})
|
||||
print('reopen]\r')
|
||||
elif command[0] == 'b':
|
||||
elif localcommand[0] == 'b':
|
||||
tlvdata.send(session.connection, {'operation': 'break',
|
||||
'path': currconsole})
|
||||
print("break sent]\r")
|
||||
elif command[0] == '?':
|
||||
elif localcommand[0] == 'p': # print
|
||||
cmdlen += 1
|
||||
localcommand = get_command_bytes(filehandle, localcommand, cmdlen)
|
||||
|
||||
if localcommand[1] == 'o': # off
|
||||
print("powering off...")
|
||||
session.simple_noderange_command(consolename, '/power/state', 'off')
|
||||
print("complete]\r")
|
||||
elif localcommand[1] == 's': # shutdown
|
||||
print("shutting down...")
|
||||
session.simple_noderange_command(consolename, '/power/state', 'shutdown')
|
||||
print("complete]\r")
|
||||
elif localcommand[1] == 'b': # boot
|
||||
cmdlen += 1
|
||||
localcommand = get_command_bytes(filehandle, localcommand, cmdlen)
|
||||
|
||||
if localcommand[2] == 's': # boot to setup
|
||||
print("booting to setup...")
|
||||
|
||||
bootmode = 'uefi'
|
||||
bootdev = 'setup'
|
||||
|
||||
rc = session.simple_noderange_command(consolename, '/boot/nextdevice', bootdev, bootmode=bootmode)
|
||||
|
||||
if rc:
|
||||
print("Error]\r")
|
||||
else:
|
||||
rc = session.simple_noderange_command(consolename, '/power/state', 'boot')
|
||||
if rc:
|
||||
print("Error]\r")
|
||||
else:
|
||||
print("complete]\r")
|
||||
|
||||
elif localcommand[2] == 'n': # boot to network
|
||||
print("booting to network...")
|
||||
|
||||
bootmode = 'uefi'
|
||||
bootdev = 'network'
|
||||
|
||||
rc = session.simple_noderange_command(consolename, '/boot/nextdevice', bootdev, bootmode=bootmode)
|
||||
|
||||
if rc:
|
||||
print("Error]\r")
|
||||
else:
|
||||
rc = session.simple_noderange_command(consolename, '/power/state', 'boot')
|
||||
|
||||
if rc:
|
||||
print("Error]\r")
|
||||
else:
|
||||
print("complete]\r")
|
||||
|
||||
elif localcommand[2] == '\x0d': # boot to default
|
||||
print("booting to default...")
|
||||
|
||||
bootmode = 'uefi'
|
||||
bootdev = 'default'
|
||||
|
||||
rc = session.simple_noderange_command(consolename, '/boot/nextdevice', bootdev, bootmode=bootmode)
|
||||
|
||||
if rc:
|
||||
print("Error]\r")
|
||||
else:
|
||||
rc = session.simple_noderange_command(consolename, '/power/state', 'boot')
|
||||
|
||||
if rc:
|
||||
print("Error]\r")
|
||||
else:
|
||||
print("complete]\r")
|
||||
|
||||
else:
|
||||
print("Unknown boot state.]\r")
|
||||
|
||||
else:
|
||||
print("Unknown power state.]\r")
|
||||
|
||||
elif localcommand[0] == '?':
|
||||
print("help]\r")
|
||||
print(". disconnect\r")
|
||||
print("b break\r")
|
||||
print("o reopen\r")
|
||||
print(". disconnect\r")
|
||||
print("b break\r")
|
||||
print("o reopen\r")
|
||||
print("po power off\r")
|
||||
print("ps shutdown\r")
|
||||
print("pbs boot to setup\r")
|
||||
print("pbn boot to network\r")
|
||||
print("pb<ent> boot to default\r")
|
||||
print("<cr> abort command\r")
|
||||
elif command[0] == '\x0d':
|
||||
elif localcommand[0] == '\x0d':
|
||||
print("ignored]\r")
|
||||
else: # not a command at all..
|
||||
print("unknown -- use '?']\r")
|
||||
|
||||
|
||||
def get_command_bytes(filehandle, localcommand, cmdlen):
|
||||
while len(localcommand) < cmdlen:
|
||||
ready, _, _ = select.select((filehandle,), (), (), 1)
|
||||
if ready:
|
||||
localcommand += filehandle.read()
|
||||
return localcommand
|
||||
|
||||
|
||||
def check_escape_seq(currinput, filehandle):
|
||||
while conserversequence.startswith(currinput):
|
||||
if currinput.startswith(conserversequence): # We have full sequence
|
||||
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015 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 optparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
path = os.path.dirname(os.path.realpath(__file__))
|
||||
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
|
||||
if path.startswith('/opt'):
|
||||
sys.path.append(path)
|
||||
|
||||
import confluent.client as client
|
||||
|
||||
argparser = optparse.OptionParser()
|
||||
argparser.add_option('-b', '--bios', dest='biosmode',
|
||||
action='store_true', default=False,
|
||||
help='Request BIOS style boot (rather than UEFI)')
|
||||
argparser.add_option('-p', '--persist', dest='persist', action='store_true',
|
||||
default=False,
|
||||
help='Request the boot device be persistent rather than '
|
||||
'one time')
|
||||
|
||||
(options, args) = argparser.parse_args()
|
||||
|
||||
try:
|
||||
noderange = args[0]
|
||||
except IndexError:
|
||||
sys.stderr.write(
|
||||
'Usage: {0} <noderange> [default|cd|network|setup|hd]\n'.format(
|
||||
sys.argv[0]))
|
||||
sys.exit(1)
|
||||
bootdev = None
|
||||
if len(sys.argv) > 2:
|
||||
bootdev = sys.argv[2]
|
||||
if bootdev in ('net', 'pxe'):
|
||||
bootdev = 'network'
|
||||
session = client.Command()
|
||||
exitcode = 0
|
||||
if options.biosmode:
|
||||
bootmode = 'bios'
|
||||
else:
|
||||
bootmode = 'uefi'
|
||||
|
||||
rc = session.simple_noderange_command(noderange, '/boot/nextdevice', bootdev,
|
||||
bootmode=bootmode,
|
||||
persistent=options.persist)
|
||||
|
||||
if rc:
|
||||
sys.exit(rc)
|
||||
else:
|
||||
sys.exit(session.simple_noderange_command(noderange, '/power/state', 'boot'))
|
||||
@@ -45,5 +45,6 @@ if len(sys.argv) > 2:
|
||||
|
||||
session = client.Command()
|
||||
exitcode = 0
|
||||
session.add_precede_key('oldstate')
|
||||
sys.exit(
|
||||
session.simple_noderange_command(noderange, '/power/state', setstate))
|
||||
@@ -44,6 +44,7 @@ def _parseserver(string):
|
||||
class Command(object):
|
||||
|
||||
def __init__(self, server=None):
|
||||
self._prevkeyname = None
|
||||
self.connection = None
|
||||
if server is None:
|
||||
if 'CONFLUENT_HOST' in os.environ:
|
||||
@@ -74,6 +75,9 @@ class Command(object):
|
||||
if authdata['authpassed'] == 1:
|
||||
self.authenticated = True
|
||||
|
||||
def add_precede_key(self, keyname):
|
||||
self._prevkeyname = keyname
|
||||
|
||||
def handle_results(self, ikey, rc, res):
|
||||
if 'error' in res:
|
||||
sys.stderr.write('Error: {0}\n'.format(res['error']))
|
||||
@@ -93,7 +97,12 @@ class Command(object):
|
||||
else:
|
||||
rc |= 1
|
||||
elif ikey in res[node]:
|
||||
print('{0}: {1}'.format(node, res[node][ikey]['value']))
|
||||
if self._prevkeyname and self._prevkeyname in res[node]:
|
||||
print('{0}: {2}->{1}'.format(
|
||||
node, res[node][ikey]['value'],
|
||||
res[node][self._prevkeyname]['value']))
|
||||
else:
|
||||
print('{0}: {1}'.format(node, res[node][ikey]['value']))
|
||||
return rc
|
||||
|
||||
def simple_noderange_command(self, noderange, resource, input=None,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
from setuptools import setup
|
||||
import os
|
||||
|
||||
scriptlist = ['bin/{0}'.format(d) for d in os.listdir('bin/')]
|
||||
|
||||
setup(
|
||||
name='confluent_client',
|
||||
@@ -7,9 +10,6 @@ setup(
|
||||
author_email='jjohnson2@lenovo.com',
|
||||
url='http://xcat.sf.net/',
|
||||
packages=['confluent'],
|
||||
scripts=['bin/confetty', 'bin/nodeconsole', 'bin/nodeeventlog',
|
||||
'bin/nodefirmware', 'bin/nodehealth', 'bin/nodeidentify',
|
||||
'bin/nodeinventory', 'bin/nodelist', 'bin/nodepower',
|
||||
'bin/nodesensors', 'bin/nodesetboot', 'bin/noderun'],
|
||||
scripts=scriptlist,
|
||||
data_files=[('/etc/profile.d', ['confluent_env.sh'])],
|
||||
)
|
||||
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2017 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 optparse
|
||||
import sys
|
||||
import os
|
||||
path = os.path.dirname(os.path.realpath(__file__))
|
||||
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
|
||||
if path.startswith('/opt'):
|
||||
# if installed into system path, do not muck with things
|
||||
sys.path.append(path)
|
||||
import confluent.config.configmanager as cfm
|
||||
import confluent.config.conf as conf
|
||||
import confluent.main as main
|
||||
|
||||
argparser = optparse.OptionParser(
|
||||
usage="Usage: %prog [options] [dump|restore] [path]")
|
||||
argparser.add_option('-p', '--password',
|
||||
help='Password to use to protect/unlock a protected dump')
|
||||
argparser.add_option('-r', '--redact', action='store_true',
|
||||
help='Redact potentially sensitive data rather than store')
|
||||
argparser.add_option('-u', '--unprotected', action='store_true',
|
||||
help='Specify that no password should be used to protect'
|
||||
' the key information. Fields will be encrypted, '
|
||||
'but keys.json will contain unencrypted decryption'
|
||||
' keys that may be used to read the dump')
|
||||
(options, args) = argparser.parse_args()
|
||||
if len(args) != 2 or args[0] not in ('dump', 'restore'):
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
dumpdir = args[1]
|
||||
|
||||
|
||||
if args[0] == 'restore':
|
||||
pid = main.is_running()
|
||||
if pid is not None:
|
||||
print("Confluent is running, must shut down to restore db")
|
||||
sys.exit(1)
|
||||
cfm.restore_db_from_directory(dumpdir, options.password)
|
||||
elif args[0] == 'dump':
|
||||
if options.password is None and not (options.unprotected or options.redact):
|
||||
print("Must indicate a password to protect or -u to opt opt of "
|
||||
"secure value protection or -r to skip all protected data")
|
||||
sys.exit(1)
|
||||
os.umask(077)
|
||||
main._initsecurity(conf.get_config())
|
||||
if not os.path.exists(dumpdir):
|
||||
os.makedirs(dumpdir)
|
||||
cfm.dump_db_to_directory(dumpdir, options.password, options.redact)
|
||||
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ import anydbm as dbm
|
||||
import ast
|
||||
import base64
|
||||
import confluent.config.attributes as allattributes
|
||||
import confluent.config.conf as conf
|
||||
import confluent.log
|
||||
import confluent.util
|
||||
import confluent.exceptions as exc
|
||||
@@ -128,6 +129,18 @@ def _get_protected_key(keydict, password, paramname):
|
||||
raise exc.LockedCredentials("No available decryption key")
|
||||
|
||||
|
||||
def _parse_key(keydata, password=None):
|
||||
if keydata.startswith('*unencrypted:'):
|
||||
return base64.b64decode(keydata[13:])
|
||||
elif password:
|
||||
salt, iv, crypt, hmac = [base64.b64decode(x)
|
||||
for x in keydata.split('!')]
|
||||
privkey, integkey = _derive_keys(password, salt)
|
||||
return decrypt_value([iv, crypt, hmac], privkey, integkey)
|
||||
raise(exc.LockedCredentials(
|
||||
"Passphrase protected secret requires password"))
|
||||
|
||||
|
||||
def _format_key(key, password=None):
|
||||
if password is not None:
|
||||
salt = os.urandom(32)
|
||||
@@ -707,6 +720,8 @@ class ConfigManager(object):
|
||||
:param uid: Custom identifier number if desired. Defaults to random.
|
||||
:param displayname: Optional long format name for UI consumption
|
||||
"""
|
||||
if 'idmap' not in _cfgstore['main']:
|
||||
_cfgstore['main']['idmap'] = {}
|
||||
if uid is None:
|
||||
uid = _generate_new_id()
|
||||
else:
|
||||
@@ -720,8 +735,6 @@ class ConfigManager(object):
|
||||
self._cfgstore['users'][name] = {'id': uid}
|
||||
if displayname is not None:
|
||||
self._cfgstore['users'][name]['displayname'] = displayname
|
||||
if 'idmap' not in _cfgstore['main']:
|
||||
_cfgstore['main']['idmap'] = {}
|
||||
_cfgstore['main']['idmap'][uid] = {
|
||||
'tenant': self.tenant,
|
||||
'username': name
|
||||
@@ -1187,6 +1200,70 @@ class ConfigManager(object):
|
||||
self._bg_sync_to_file()
|
||||
#TODO: wait for synchronization to suceed/fail??)
|
||||
|
||||
def _load_from_json(self, jsondata):
|
||||
"""Load fresh configuration data from jsondata
|
||||
|
||||
:param jsondata: String of jsondata
|
||||
:return:
|
||||
"""
|
||||
dumpdata = json.loads(jsondata)
|
||||
tmpconfig = {}
|
||||
for confarea in _config_areas:
|
||||
if confarea not in dumpdata:
|
||||
continue
|
||||
tmpconfig[confarea] = {}
|
||||
for element in dumpdata[confarea]:
|
||||
newelement = copy.deepcopy(dumpdata[confarea][element])
|
||||
for attribute in dumpdata[confarea][element]:
|
||||
if newelement[attribute] == '*REDACTED*':
|
||||
raise Exception(
|
||||
"Unable to restore from redacted backup")
|
||||
elif attribute == 'cryptpass':
|
||||
passparts = newelement[attribute].split('!')
|
||||
newelement[attribute] = tuple([base64.b64decode(x)
|
||||
for x in passparts])
|
||||
elif 'cryptvalue' in newelement[attribute]:
|
||||
bincrypt = newelement[attribute]['cryptvalue']
|
||||
bincrypt = tuple([base64.b64decode(x)
|
||||
for x in bincrypt.split('!')])
|
||||
newelement[attribute]['cryptvalue'] = bincrypt
|
||||
elif attribute in ('nodes', '_expressionkeys'):
|
||||
# A group with nodes
|
||||
# delete it and defer until nodes are being added
|
||||
# which will implicitly fill this up
|
||||
# Or _expressionkeys attribute, which will similarly
|
||||
# be rebuilt
|
||||
del newelement[attribute]
|
||||
tmpconfig[confarea][element] = newelement
|
||||
# We made it through above section without an exception, go ahead and
|
||||
# replace
|
||||
# Start by erasing the dbm files if present
|
||||
for confarea in _config_areas:
|
||||
try:
|
||||
os.unlink(os.path.join(self._cfgdir, confarea))
|
||||
except OSError as e:
|
||||
if e.errno == 2:
|
||||
pass
|
||||
# Now we have to iterate through each fixed up element, using the
|
||||
# set attribute to flesh out inheritence and expressions
|
||||
for confarea in _config_areas:
|
||||
if confarea not in tmpconfig:
|
||||
continue
|
||||
if confarea == 'nodes':
|
||||
self.set_node_attributes(tmpconfig[confarea], True)
|
||||
elif confarea == 'nodegroups':
|
||||
self.set_group_attributes(tmpconfig[confarea], True)
|
||||
elif confarea == 'users':
|
||||
for user in tmpconfig[confarea]:
|
||||
uid = tmpconfig[confarea].get('id', None)
|
||||
displayname = tmpconfig[confarea].get('displayname', None)
|
||||
self.create_user(user, uid=uid, displayname=displayname)
|
||||
if 'cryptpass' in tmpconfig[confarea][user]:
|
||||
self._cfgstore['users'][user]['cryptpass'] = \
|
||||
tmpconfig[confarea][user]['cryptpass']
|
||||
_mark_dirtykey('users', user, self.tenant)
|
||||
self._bg_sync_to_file()
|
||||
|
||||
def _dump_to_json(self, redact=None):
|
||||
"""Dump the configuration in json form to output
|
||||
|
||||
@@ -1344,28 +1421,80 @@ class ConfigManager(object):
|
||||
self._recalculate_expressions(cfgobj[key], formatter, node,
|
||||
changeset)
|
||||
|
||||
|
||||
def _restore_keys(jsond, password, newpassword=None):
|
||||
# the jsond from the restored file, password (if any) used to protect
|
||||
# the file, and newpassword to use, (also check the service.cfg file)
|
||||
global _masterkey
|
||||
global _masterintegritykey
|
||||
keydata = json.loads(jsond)
|
||||
cryptkey = _parse_key(keydata['cryptkey'], password)
|
||||
integritykey = _parse_key(keydata['integritykey'], password)
|
||||
conf.init_config()
|
||||
cfg = conf.get_config()
|
||||
if cfg.has_option('security', 'externalcfgkey'):
|
||||
keyfilename = cfg.get('security', 'externalcfgkey')
|
||||
with open(keyfilename, 'r') as keyfile:
|
||||
newpassword = keyfile.read()
|
||||
set_global('master_privacy_key', _format_key(cryptkey,
|
||||
password=newpassword))
|
||||
set_global('master_integrity_key', _format_key(integritykey,
|
||||
password=newpassword))
|
||||
_masterkey = cryptkey
|
||||
_masterintegritykey = integritykey
|
||||
ConfigManager.wait_for_sync()
|
||||
# At this point, we should have the key situation all sorted
|
||||
|
||||
|
||||
def _dump_keys(password):
|
||||
if _masterkey is None or _masterintegritykey is None:
|
||||
init_masterkey()
|
||||
cryptkey = _format_key(_masterkey, password=password)
|
||||
cryptkey = '!'.join(map(base64.b64encode, cryptkey['passphraseprotected']))
|
||||
if 'passphraseprotected' in cryptkey:
|
||||
cryptkey = '!'.join(map(base64.b64encode,
|
||||
cryptkey['passphraseprotected']))
|
||||
else:
|
||||
cryptkey = '*unencrypted:{0}'.format(base64.b64encode(
|
||||
cryptkey['unencryptedvalue']))
|
||||
integritykey = _format_key(_masterintegritykey, password=password)
|
||||
integritykey = '!'.join(map(base64.b64encode, integritykey['passphraseprotected']))
|
||||
if 'passphraseprotected' in integritykey:
|
||||
integritykey = '!'.join(map(base64.b64encode,
|
||||
integritykey['passphraseprotected']))
|
||||
else:
|
||||
integritykey = '*unencrypted:{0}'.format(base64.b64encode(
|
||||
integritykey['unencryptedvalue']))
|
||||
return json.dumps({'cryptkey': cryptkey, 'integritykey': integritykey},
|
||||
sort_keys=True, indent=4, separators=(',', ': '))
|
||||
|
||||
|
||||
def restore_db_from_directory(location, password):
|
||||
try:
|
||||
with open(os.path.join(location, 'keys.json'), 'r') as cfgfile:
|
||||
keydata = cfgfile.read()
|
||||
json.loads(keydata)
|
||||
_restore_keys(keydata, password)
|
||||
except IOError as e:
|
||||
if e.errno == 2:
|
||||
raise Exception("Cannot restore without keys, this may be a "
|
||||
"redacted dump")
|
||||
with open(os.path.join(location, 'main.json'), 'r') as cfgfile:
|
||||
cfgdata = cfgfile.read()
|
||||
ConfigManager(tenant=None)._load_from_json(cfgdata)
|
||||
|
||||
|
||||
def dump_db_to_directory(location, password, redact=None):
|
||||
with open(os.path.join(location, 'keys.json'), 'w') as cfgfile:
|
||||
cfgfile.write(_dump_keys(password))
|
||||
cfgfile.write('\n')
|
||||
if not redact:
|
||||
with open(os.path.join(location, 'keys.json'), 'w') as cfgfile:
|
||||
cfgfile.write(_dump_keys(password))
|
||||
cfgfile.write('\n')
|
||||
with open(os.path.join(location, 'main.json'), 'w') as cfgfile:
|
||||
cfgfile.write(ConfigManager(tenant=None)._dump_to_json(redact=redact))
|
||||
cfgfile.write('\n')
|
||||
try:
|
||||
for tenant in os.listdir(
|
||||
os.path.join(ConfigManager._cfgdir, '/tenants/')):
|
||||
with open(os.path.join(location, tenant + '.json'), 'w') as cfgfile:
|
||||
with open(os.path.join(location, 'tenants', tenant,
|
||||
'main.json'), 'w') as cfgfile:
|
||||
cfgfile.write(ConfigManager(tenant=tenant)._dump_to_json(
|
||||
redact=redact))
|
||||
cfgfile.write('\n')
|
||||
|
||||
@@ -89,6 +89,26 @@ def _updatepidfile():
|
||||
pidfile.close()
|
||||
|
||||
|
||||
def is_running():
|
||||
# Utility function for utilities to check if confluent is running
|
||||
try:
|
||||
pidfile = open('/var/run/confluent/pid', 'r+')
|
||||
fcntl.flock(pidfile, fcntl.LOCK_SH)
|
||||
pid = pidfile.read()
|
||||
if pid != '':
|
||||
try:
|
||||
os.kill(int(pid), 0)
|
||||
return pid
|
||||
except OSError:
|
||||
# There is no process running by that pid, must be stale
|
||||
pass
|
||||
fcntl.flock(pidfile, fcntl.LOCK_UN)
|
||||
pidfile.close()
|
||||
except IOError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def _checkpidfile():
|
||||
try:
|
||||
pidfile = open('/var/run/confluent/pid', 'r+')
|
||||
|
||||
@@ -797,6 +797,11 @@ class PowerState(ConfluentChoiceMessage):
|
||||
])
|
||||
keyname = 'state'
|
||||
|
||||
def __init__(self, node, state, oldstate=None):
|
||||
super(PowerState, self).__init__(node, state)
|
||||
if oldstate is not None:
|
||||
self.kvpairs[node]['oldstate'] = {'value': oldstate}
|
||||
|
||||
|
||||
class BMCReset(ConfluentChoiceMessage):
|
||||
valid_values = set([
|
||||
|
||||
@@ -795,10 +795,22 @@ class IpmiHandler(object):
|
||||
return
|
||||
elif 'update' == self.op:
|
||||
powerstate = self.inputdata.powerstate(self.node)
|
||||
oldpower = None
|
||||
if powerstate == 'boot':
|
||||
oldpower = self.ipmicmd.get_power()
|
||||
if 'powerstate' in oldpower:
|
||||
oldpower = oldpower['powerstate']
|
||||
self.ipmicmd.set_power(powerstate, wait=30)
|
||||
power = self.ipmicmd.get_power()
|
||||
if powerstate == 'boot' and oldpower == 'on':
|
||||
power = {'powerstate': 'reset'}
|
||||
else:
|
||||
power = self.ipmicmd.get_power()
|
||||
if powerstate == 'reset' and power['powerstate'] == 'on':
|
||||
power['powerstate'] = 'reset'
|
||||
|
||||
self.output.put(msg.PowerState(node=self.node,
|
||||
state=power['powerstate']))
|
||||
state=power['powerstate'],
|
||||
oldstate=oldpower))
|
||||
return
|
||||
|
||||
def handle_reset(self):
|
||||
|
||||
@@ -170,7 +170,8 @@ def process_request(connection, request, cfm, authdata, authname, skipauth):
|
||||
auditlog.log(auditmsg)
|
||||
try:
|
||||
if operation == 'start':
|
||||
return start_term(authname, cfm, connection, params, path)
|
||||
return start_term(authname, cfm, connection, params, path,
|
||||
authdata, skipauth)
|
||||
elif operation == 'shutdown':
|
||||
configmanager.ConfigManager.shutdown()
|
||||
else:
|
||||
@@ -187,7 +188,7 @@ def process_request(connection, request, cfm, authdata, authname, skipauth):
|
||||
return
|
||||
|
||||
|
||||
def start_term(authname, cfm, connection, params, path):
|
||||
def start_term(authname, cfm, connection, params, path, authdata, skipauth):
|
||||
elems = path.split('/')
|
||||
if len(elems) < 4 or elems[1] != 'nodes':
|
||||
raise exc.InvalidArgumentException('Invalid path {0}'.format(path))
|
||||
@@ -233,7 +234,9 @@ def start_term(authname, cfm, connection, params, path):
|
||||
consession.reopen()
|
||||
continue
|
||||
else:
|
||||
raise Exception("TODO")
|
||||
process_request(connection, data, cfm, authdata, authname,
|
||||
skipauth)
|
||||
continue
|
||||
if not data:
|
||||
consession.destroy()
|
||||
return
|
||||
|
||||
@@ -33,6 +33,9 @@ done
|
||||
grep -v confluent/__init__.py INSTALLED_FILES.bare > INSTALLED_FILES
|
||||
cat INSTALLED_FILES
|
||||
|
||||
%post
|
||||
if [ -x /usr/bin/systemctl ]; then /usr/bin/systemctl try-restart confluent; fi
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ setup(
|
||||
name='confluent_server',
|
||||
version='#VERSION#',
|
||||
author='Jarrod Johnson',
|
||||
author_email='jbjohnso@us.ibm.com',
|
||||
author_email='jjohnson2@lenovo.com',
|
||||
url='http://xcat.sf.net/',
|
||||
description='confluent systems management server',
|
||||
packages=['confluent', 'confluent/config', 'confluent/interface',
|
||||
@@ -14,7 +14,7 @@ setup(
|
||||
'confluent/plugins/configuration/'],
|
||||
install_requires=['paramiko', 'pycrypto>=2.6', 'confluent_client>=0.1.0', 'eventlet',
|
||||
'pyghmi>=0.6.5'],
|
||||
scripts=['bin/confluent'],
|
||||
scripts=['bin/confluent', 'bin/confluentdbutil'],
|
||||
data_files=[('/etc/init.d', ['sysvinit/confluent']),
|
||||
('/usr/lib/systemd/system', ['systemd/confluent.service']),
|
||||
('/opt/confluent/lib/python/confluent/plugins/console/', [])],
|
||||
|
||||
Reference in New Issue
Block a user