mirror of
https://github.com/xcat2/confluent.git
synced 2026-09-02 07:26:04 +00:00
Fix undefined names (F821)
Every one of these raises NameError if its code path is reached: - nodeapply: run_automation accumulated into an exitcode that only existed in run(), so any automation error crashed instead of being reported. It now keeps and returns its own, tracked separately from the exit code of the ssh commands: the early exit after the spawn loop tests that one, and folding automation failures into it would exit with children already running and their pipes abandoned. Both are reported at the real exits. - nodeconsole: redraw() reads firstnodename, which was local to do_screenshot(); promote it to a module global like the other drawing state. - nodedeploy: the redeploy path appended to a lockednodes list that did not exist yet. The block that follows re-reads the same lock state and acts on it, so drop the dead duplicate. - samples/nodeattrib_from_switch.py, misc/filterpasswd: missing import sys. - xcc3: fixuuid was never imported. xcc imports xcc3, so take a local copy the way the smm handler does instead of creating an import cycle. - httpapi: the async session call still passed the WSGI-era env and an extra argument to handle_async(), which has taken only querydict since the aiohttp port. Calling it correctly exposed that handle_async() registers an AsyncSession before raising on the discontinued long poll path, so every request to it would leak a session that is never reaped. It now only creates one when there is a websocket handler to yield it to. - messages: the InputFirmwareUpdate.filename property checked self.filebynode[node] with no node in scope. __init__ already validates every expanded path and nodefile() rechecks per node, so drop the checks. - pam: drop the python2 branches referencing unicode and raw_input. The server has been python3 only since the asyncio port. - cooltera: the sensor-name listing referenced a nonexistent sensors dict. The available sensors depend on the model, which is only known after reading the device, so list them from the same status data the readings use. - deltapdu, eatonpdu, geist: the not-implemented response in update() used node outside the loop, unlike retrieve() in the same files and unlike raritan/enlogic. - confluentdbgcli: stray self. on a module-level socket connect.
This commit is contained in:
@@ -37,6 +37,7 @@ import confluent.sortutil as sortutil
|
||||
devnull = None
|
||||
|
||||
def run_automation(noderange, category, c):
|
||||
exitcode = 0
|
||||
automationbynode = {}
|
||||
for res in c.update('/noderange/{0}/deployment/remote_config/run'.format(noderange), {
|
||||
'category': category,
|
||||
@@ -64,7 +65,8 @@ def run_automation(noderange, category, c):
|
||||
if res.get('complete', False):
|
||||
del automationbynode[node]
|
||||
sys.stdout.write('{0}: Automation complete\n'.format(node))
|
||||
|
||||
return exitcode
|
||||
|
||||
|
||||
def run():
|
||||
global devnull
|
||||
@@ -104,10 +106,13 @@ def run():
|
||||
pipedesc = {}
|
||||
pendingexecs = deque()
|
||||
exitcode = 0
|
||||
# Kept apart from exitcode: a failed automation run must not trip the
|
||||
# early exit below, which would abandon ssh children already spawned.
|
||||
autoexitcode = 0
|
||||
|
||||
c.stop_if_noderange_over(args[0], options.maxnodes)
|
||||
if options.automation:
|
||||
run_automation(args[0], options.automation, c)
|
||||
autoexitcode = run_automation(args[0], options.automation, c)
|
||||
|
||||
nodemap = {}
|
||||
cmdparms = []
|
||||
@@ -124,7 +129,7 @@ def run():
|
||||
cmdstorun.append(['run_remote', script])
|
||||
if not cmdstorun:
|
||||
if options.automation:
|
||||
sys.exit(0)
|
||||
sys.exit(autoexitcode)
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
for res in c.read('/noderange/{0}/nodes/'.format(args[0])):
|
||||
@@ -145,7 +150,7 @@ def run():
|
||||
else:
|
||||
pendingexecs.append((sshnode, cmdv))
|
||||
if not all or exitcode:
|
||||
sys.exit(exitcode)
|
||||
sys.exit(exitcode | autoexitcode)
|
||||
rdy = poller.poll(10)
|
||||
while all:
|
||||
pernodeout = {}
|
||||
@@ -193,7 +198,7 @@ def run():
|
||||
sys.stdout.flush()
|
||||
if all:
|
||||
rdy = poller.poll(10)
|
||||
sys.exit(exitcode)
|
||||
sys.exit(exitcode | autoexitcode)
|
||||
|
||||
|
||||
def run_cmdv(node, cmdv, all, poller, pipedesc):
|
||||
|
||||
@@ -790,6 +790,7 @@ numrows = 0
|
||||
cwidth = 0
|
||||
cheight = 0
|
||||
imagedatabynode = {}
|
||||
firstnodename = None
|
||||
|
||||
def redraw():
|
||||
for node in imagedatabynode:
|
||||
@@ -818,6 +819,7 @@ async def do_screenshot():
|
||||
global streaming
|
||||
global resized
|
||||
global numrows
|
||||
global firstnodename
|
||||
sess = client.Command()
|
||||
if streaming:
|
||||
asyncio.create_task(watch_input())
|
||||
|
||||
@@ -133,11 +133,6 @@ def main(args):
|
||||
curr = nodeinfo[attr].get('value', '')
|
||||
if curr and node not in profilebynode:
|
||||
profilebynode[node] = curr
|
||||
for lockinfo in c.read('/noderange/{0}/deployment/lock'.format(args.noderange)):
|
||||
for node in lockinfo.get('databynode', {}):
|
||||
lockstate = lockinfo['databynode'][node]['lock']['value']
|
||||
if lockstate == 'locked':
|
||||
lockednodes.append(node)
|
||||
if args.profile and profilebynode:
|
||||
sys.stderr.write('The -r/--redeploy option cannot be used with a profile, it redeploys the current or pending profile\n')
|
||||
return 1
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
import confluent.client as cl
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
c = cl.Command()
|
||||
macs = []
|
||||
interface = sys.argv[1]
|
||||
|
||||
@@ -119,12 +119,12 @@ def handle_async(querydict, wshandler=None):
|
||||
# This may be one of two things, a request for a new async stream
|
||||
# or a request for next data from async stream
|
||||
# httpapi otherwise handles requests an injecting them to queue
|
||||
if 'asyncid' not in querydict or not querydict['asyncid']:
|
||||
if wshandler and ('asyncid' not in querydict or not querydict['asyncid']):
|
||||
# This is a new request, create a new multiplexer
|
||||
currsess = AsyncSession(wshandler)
|
||||
if wshandler:
|
||||
yield currsess
|
||||
return
|
||||
yield AsyncSession(wshandler)
|
||||
return
|
||||
# Without a websocket handler there is nobody to hand a session to, so do
|
||||
# not register one that would never be reaped.
|
||||
raise Exception("Long polling asynchttp is discontinued")
|
||||
|
||||
|
||||
|
||||
@@ -12,11 +12,27 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import codecs
|
||||
import confluent.discovery.handlers.redfishbmc as redfishbmc
|
||||
import confluent.util as util
|
||||
import socket
|
||||
import struct
|
||||
import aiohmi.util.webclient as webclient
|
||||
|
||||
|
||||
# Duplicated from the xcc handler rather than imported: xcc imports this
|
||||
# module, so importing it back would be circular. smm carries its own copy of
|
||||
# this for the same reason.
|
||||
def fixuuid(baduuid):
|
||||
# SMM dumps it out in hex
|
||||
uuidprefix = (baduuid[:8], baduuid[9:13], baduuid[14:18])
|
||||
a = codecs.encode(struct.pack('<IHH', *[int(x, 16) for x in uuidprefix]),
|
||||
'hex')
|
||||
a = util.stringify(a)
|
||||
uuid = (a[:8], a[8:12], a[12:16], baduuid[19:23], baduuid[24:])
|
||||
return '-'.join(uuid).lower()
|
||||
|
||||
|
||||
class NodeHandler(redfishbmc.NodeHandler):
|
||||
devname = 'XCC'
|
||||
|
||||
|
||||
@@ -799,9 +799,7 @@ async def resourcehandler_backend(req, make_response):
|
||||
pagecontent = ""
|
||||
try:
|
||||
async for rsp in _assemble_json(
|
||||
confluent.asynchttp.handle_async(
|
||||
env, querydict,
|
||||
httpsessions[authorized['sessionid']]['inflight'])):
|
||||
confluent.asynchttp.handle_async(querydict)):
|
||||
pagecontent += rsp
|
||||
rsp = await make_response(mimetype, 200, cookies=cookies)
|
||||
if not isinstance(pagecontent, bytes):
|
||||
|
||||
@@ -687,12 +687,8 @@ class InputFirmwareUpdate(ConfluentMessage):
|
||||
raise Exception('User requested substitutions, but code is '
|
||||
'written against old api, code must be fixed or '
|
||||
'skip {} expansion')
|
||||
if self.filebynode[node].startswith('/etc/confluent'):
|
||||
raise Exception(
|
||||
'File transfer with /etc/confluent is not supported')
|
||||
if self.filebynode[node].startswith('/var/log/confluent'):
|
||||
raise Exception(
|
||||
'File transfer with /var/log/confluent is not supported')
|
||||
# The per-node paths were already checked in __init__, and nodefile()
|
||||
# rechecks them when handing a path out for a specific node.
|
||||
return self._filename
|
||||
|
||||
def nodefile(self, node):
|
||||
|
||||
@@ -178,16 +178,8 @@ class pam():
|
||||
return 0
|
||||
|
||||
# python3 ctypes prefers bytes
|
||||
if sys.version_info >= (3,):
|
||||
if isinstance(username, str): username = username.encode(encoding)
|
||||
if isinstance(service, str): service = service.encode(encoding)
|
||||
else:
|
||||
if isinstance(username, unicode):
|
||||
username = username.encode(encoding)
|
||||
if isinstance(password, unicode):
|
||||
password = password.encode(encoding)
|
||||
if isinstance(service, unicode):
|
||||
service = service.encode(encoding)
|
||||
if isinstance(username, str): username = username.encode(encoding)
|
||||
if isinstance(service, str): service = service.encode(encoding)
|
||||
|
||||
if b'\x00' in username or b'\x00' in service:
|
||||
self.code = 4 # PAM_SYSTEM_ERR in Linux-PAM
|
||||
@@ -242,11 +234,7 @@ if __name__ == "__main__":
|
||||
readline.redisplay()
|
||||
readline.set_pre_input_hook(hook)
|
||||
|
||||
if sys.version_info >= (3,):
|
||||
getinput = input
|
||||
else:
|
||||
getinput = raw_input
|
||||
result = getinput(prompt)
|
||||
result = input(prompt)
|
||||
readline.set_pre_input_hook()
|
||||
return result
|
||||
|
||||
|
||||
@@ -151,12 +151,9 @@ _sensors_by_node = {}
|
||||
async def read_sensors(element, node, configmanager):
|
||||
category, name = element[-2:]
|
||||
if len(element) == 3:
|
||||
# just get names
|
||||
# the request is for the names under a category, so that is the last
|
||||
# element rather than the one before it
|
||||
category = name
|
||||
name = 'all'
|
||||
for sensor in sensors:
|
||||
yield msg.ChildCollection(simplify_name(sensors[sensor][0]))
|
||||
return
|
||||
if category in ('leds, fans'):
|
||||
return
|
||||
sn = _sensors_by_node.get(node, None)
|
||||
@@ -166,6 +163,12 @@ async def read_sensors(element, node, configmanager):
|
||||
statinfo = xml2stateinfo(statdata)
|
||||
_sensors_by_node[node] = (statinfo, time.time() + 1)
|
||||
sn = _sensors_by_node.get(node, None)
|
||||
if len(element) == 3:
|
||||
# the names are only known after reading the device, as the sensor
|
||||
# set depends on the model
|
||||
for sensor in sn[0] if sn else ():
|
||||
yield msg.ChildCollection(simplify_name(sensor['name']))
|
||||
return
|
||||
if sn:
|
||||
yield msg.SensorReadings(sn[0], name=node)
|
||||
|
||||
|
||||
@@ -195,7 +195,8 @@ async def retrieve(nodes, element, configmanager, inputdata):
|
||||
|
||||
async def update(nodes, element, configmanager, inputdata):
|
||||
if 'outlets' not in element:
|
||||
yield msg.ConfluentResourceUnavailable(node, 'Not implemented')
|
||||
for node in nodes:
|
||||
yield msg.ConfluentResourceUnavailable(node, 'Not implemented')
|
||||
return
|
||||
timeout = 4
|
||||
for node in nodes:
|
||||
|
||||
@@ -327,7 +327,8 @@ async def retrieve(nodes, element, configmanager, inputdata):
|
||||
|
||||
async def update(nodes, element, configmanager, inputdata):
|
||||
if 'outlets' not in element:
|
||||
yield msg.ConfluentResourceUnavailable(node, 'Not implemented')
|
||||
for node in nodes:
|
||||
yield msg.ConfluentResourceUnavailable(node, 'Not implemented')
|
||||
return
|
||||
for node in nodes:
|
||||
gc = PDUClient(node, configmanager)
|
||||
|
||||
@@ -336,7 +336,8 @@ async def retrieve(nodes, element, configmanager, inputdata):
|
||||
|
||||
async def update(nodes, element, configmanager, inputdata):
|
||||
if 'outlets' not in element:
|
||||
yield msg.ConfluentResourceUnavailable(node, 'Not implemented')
|
||||
for node in nodes:
|
||||
yield msg.ConfluentResourceUnavailable(node, 'Not implemented')
|
||||
return
|
||||
for node in nodes:
|
||||
gc = GeistClient(node, configmanager)
|
||||
|
||||
@@ -20,7 +20,7 @@ import readline
|
||||
import socket
|
||||
|
||||
connection = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
self.connection.connect('/var/run/confluent/dbg.sock')
|
||||
connection.connect('/var/run/confluent/dbg.sock')
|
||||
|
||||
readline.parse_and_bind("tab: complete")
|
||||
readline.parse_and_bind("set bell-style none")
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import sys
|
||||
|
||||
uidmin = 1000
|
||||
uidmax = 60000
|
||||
gidmin = 1000
|
||||
|
||||
Reference in New Issue
Block a user