2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-09-29 00:31:09 +00:00

Compare commits

...

14 Commits

Author SHA1 Message Date
Jarrod Johnson 40c74699f0 Check for some issues in a manual assign request
One is to provide clear feedback when a nodename is requested
that was not previously defined, to make it more clear that
it is a requirement and/or guard against going too far while
the config function will be missing data it needs to complete
onboarding.

Another is to break if the request is trying to assign a node
to a different definition when it already exists under a different
name.
2020-11-03 09:32:55 -05:00
Jarrod Johnson 3903cda789 Do not clear the entire nodes lookup on remap
remap may only amend part of the map,
do not cause that to clear out the good data.
2020-11-03 09:32:48 -05:00
Jarrod Johnson 72049657d7 Fix issues with leftover ssh sessions
Upon connection loss, even though confluent internally
decides it is done with it, it fails to close the session.

Catch a number of these scenarios and ensure the connection closes.
2020-11-02 13:20:55 -05:00
Jarrod Johnson 247a7f5d8a Fix problem when domain was not set
domain was checked even if domain not defined,
make sure domain is defined before trying
to use it.
2020-10-08 13:38:43 -04:00
Jarrod Johnson 61f793040e Avoid setting uuid and mac in pxe if already set
Notably the uuid change can end up recursing. Fix the behavior that will cause never ending
loops, which in some IO situations
can end in recursion limits.
2020-10-06 17:14:48 -04:00
Jarrod Johnson 5a24619560 Recognize a different m.2 name 2020-10-06 10:37:20 -04:00
Jarrod Johnson e186eb7319 Fix problem with autocons
autocons needed to open the devnode earlier
to have the correct name. Fixes TSM autocons
behavior
2020-09-24 08:31:20 -04:00
Jarrod Johnson 4b7d042f2d Have a clause for redfish not yet ready
We need redfish, but redfish is slow to boot on TSM..
2020-09-23 08:24:18 -04:00
Jarrod Johnson 99f533b4cb Implement redfish resilient discovery for TSM
TSM redfish stack has an issue where it refuses to recognize any
non-redfish password change. Use redfish to change.

Regretably, it takes about 10 seconds for that change to propogate
to the practical API, so we have a discovery delay now.
2020-09-23 08:24:07 -04:00
Jarrod Johnson 9828ea5898 Fix chained smm discovery on cumulus 2020-09-14 11:02:00 -04:00
Jarrod Johnson 7bdf7afb80 Fix another mistake in chained SMM discovery 2020-09-14 08:04:41 -04:00
Jarrod Johnson cd20a69eb6 Fix typo in function name in chained smm discovery 2020-09-14 08:03:18 -04:00
Jarrod Johnson c3d14977f2 Update attributes documentation 2020-09-11 09:56:35 -04:00
Jarrod Johnson 31d19e9398 Fix deployment.useinsecureprotocols
If explicitly set to 'never', it would behave as 'firmware'.
2020-09-11 09:44:09 -04:00
14 changed files with 73 additions and 24 deletions
@@ -49,7 +49,7 @@ class DiskInfo(object):
@property
def priority(self):
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2'):
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2', 'thinksystem_m.2'):
return 0
if 'imsm' in self.mdcontainer:
return 1
@@ -49,7 +49,7 @@ class DiskInfo(object):
@property
def priority(self):
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2'):
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2', 'thinksystem_m.2'):
return 0
if 'imsm' in self.mdcontainer:
return 1
@@ -49,7 +49,7 @@ class DiskInfo(object):
@property
def priority(self):
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2'):
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2', 'thinksystem_m.2'):
return 0
if 'imsm' in self.mdcontainer:
return 1
@@ -49,7 +49,7 @@ class DiskInfo(object):
@property
def priority(self):
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2'):
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2', 'thinksystem_m.2'):
return 0
if 'imsm' in self.mdcontainer:
return 1
@@ -49,7 +49,7 @@ class DiskInfo(object):
@property
def priority(self):
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2'):
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2', 'thinksystem_m.2'):
return 0
if 'imsm' in self.mdcontainer:
return 1
+2 -2
View File
@@ -51,6 +51,7 @@ int main(int argc, char* argv[]) {
} else {
exit(0);
}
ttyf = open(buff, O_RDWR | O_NOCTTY);
if (currspeed == SPEED9600) {
cspeed = B9600;
strcpy(offset, ",9600");
@@ -66,8 +67,6 @@ int main(int argc, char* argv[]) {
} else {
exit(0);
}
printf("%s\n", buff);
ttyf = open(buff, O_RDWR | O_NOCTTY);
tcgetattr(ttyf, &tty);
if (cspeed) {
cfsetospeed(&tty, B115200);
@@ -75,6 +74,7 @@ int main(int argc, char* argv[]) {
}
tcsetattr(ttyf, TCSANOW, &tty);
ioctl(ttyf, TIOCCONS, 0);
printf("%s\n", buff);
}
@@ -209,14 +209,14 @@ node = {
},
'deployment.useinsecureprotocols': {
'description': ('What phase(s) of boot are permitted to use insecure protocols '
'(TFTP and HTTP without TLS. By default, HTTPS is allowed. However '
'(TFTP and HTTP without TLS. By default, only HTTPS is used. However '
'this is not compatible with most firmware in most scenarios. Using '
'"firmware" as the setting will still use HTTPS after the initial download, '
'though be aware that a successful compromise during the firmware phase '
'though be aware that a successful attack during the firmware phase '
'will negate future TLS protections. The value "always" will result in '
'tftp/http being used for entire deployment. Note that ONIE does not '
'support secure protocols, and in that case this setting must be "always" '
'or "firmware"'),
'tftp/http being used for most of the deployment. The value "never" will '
'allow HTTPS only. Note that Ubuntu will still use HTTP without TLS for '
'a phase of the installation process.'),
'validlist': ('always', 'firmware', 'never'),
},
'discovery.passwordrules': {
+29 -7
View File
@@ -1020,9 +1020,13 @@ def eval_node(cfg, handler, info, nodename, manual=False):
if nl:
# The candidate nodename is the head of a chain, we must
# validate the smm certificate by the switch
macmap.get_node_fingerprint(nodename, cfg)
util.handler.cert_matches(fprint, handler.https_cert)
return
fprints = macmap.get_node_fingerprints(nodename, cfg)
for fprint in fprints:
if util.cert_matches(fprint[0], handler.https_cert):
if not discover_node(cfg, handler, info,
nodename, manual):
pending_nodes[nodename] = info
return
if (info.get('maccount', False) and
not handler.discoverable_by_switch(info['maccount'])):
errorstr = 'The detected node {0} was detected using switch, ' \
@@ -1036,6 +1040,20 @@ def eval_node(cfg, handler, info, nodename, manual=False):
def discover_node(cfg, handler, info, nodename, manual):
if manual:
if not cfg.is_node(nodename):
raise exc.InvalidArgumentException(
'{0} is not a defined node, must be defined before an '
'endpoint may be assigned to it'.format(nodename))
if handler.https_supported:
currcert = handler.https_cert
if currcert:
currprint = util.get_fingerprint(currcert, 'sha256')
prevnode = nodes_by_fprint.get(currprint, None)
if prevnode and prevnode != nodename:
raise exc.InvalidArgumentException(
'Attempt to assign {0} conflicts with existing node {1} '
'based on TLS certificate.'.format(nodename, prevnode))
known_nodes[nodename][info['hwaddr']] = info
if info['hwaddr'] in unknown_info:
del unknown_info[info['hwaddr']]
@@ -1125,11 +1143,13 @@ def do_pxe_discovery(cfg, handler, info, manual, nodename, policies):
# use uuid based scheme in lieu of tls cert, ideally only
# for stateless 'discovery' targets like pxe, where data does not
# change
uuidinfo = cfg.get_node_attributes(nodename, ['id.uuid', 'id.serial', 'id.model', 'net*.bootable'])
uuidinfo = cfg.get_node_attributes(nodename, ['id.uuid', 'id.serial', 'id.model', 'net*.hwaddr', 'net*.bootable'])
if manual or policies & set(('open', 'pxe')):
enrich_pxe_info(info)
attribs = {}
olduuid = uuidinfo.get(nodename, {}).get('id.uuid', None)
if isinstance(olduuid, dict):
olduuid = olduuid.get('value', None)
uuid = info.get('uuid', None)
if uuid and uuid != olduuid:
attribs['id.uuid'] = info['uuid']
@@ -1142,7 +1162,9 @@ def do_pxe_discovery(cfg, handler, info, manual, nodename, policies):
for attrname in uuidinfo.get(nodename, {}):
if attrname.endswith('.bootable') and uuidinfo[nodename][attrname].get('value', None):
newattrname = attrname[:-8] + 'hwaddr'
attribs[newattrname] = info['hwaddr']
oldhwaddr = uuidinfo.get(nodename, {}).get(newattrname, {}).get('value', None)
if info['hwaddr'] != oldhwaddr:
attribs[newattrname] = info['hwaddr']
if attribs:
cfg.set_node_attributes({nodename: attribs})
if info['uuid'] in known_pxe_uuids:
@@ -1274,11 +1296,11 @@ known_pxe_uuids = {}
def _map_unique_ids(nodes=None):
global nodes_by_uuid
global nodes_by_fprint
nodes_by_uuid = {}
nodes_by_fprint = {}
# Map current known ids based on uuid and fingperprints for fast lookup
cfg = cfm.ConfigManager(None)
if nodes is None:
nodes_by_uuid = {}
nodes_by_fprint = {}
nodes = cfg.list_nodes()
bigmap = cfg.get_node_attributes(nodes,
('id.uuid',
@@ -16,6 +16,7 @@ import confluent.discovery.handlers.generic as generic
import confluent.exceptions as exc
import confluent.netutil as netutil
import confluent.util as util
import eventlet
import eventlet.support.greendns
import json
try:
@@ -85,7 +86,24 @@ class NodeHandler(generic.NodeHandler):
'username': self.DEFAULT_USER
}
if authmode == 2:
rsp, status = wc.grab_json_response_with_status('/api/reset-pass', passchange)
passchange = {
'Password': self.targpass,
}
rwc = webclient.SecureHTTPConnection(
self.ipaddr, 443,
verifycallback=self.validate_cert)
rwc.set_basic_credentials(authdata['username'],
authdata['password'])
rwc.set_header('If-Match', '*')
rwc.set_header('Content-Type', 'application/json')
rsp, status = rwc.grab_json_response_with_status(
'/redfish/v1/AccountService/Accounts/1',
passchange, method='PATCH')
if status >= 200 and status < 300:
authdata['password'] = self.targpass
eventlet.sleep(10)
else:
raise Exception("Redfish may not have been ready yet")
else:
rsp, status = wc.grab_json_response_with_status('/api/reset-pass', urlencode(passchange))
authdata['password'] = self.targpass
@@ -441,7 +441,7 @@ def check_reply(node, info, packet, sock, cfg, reqview):
return
rqtype = packet[53][0]
insecuremode = cfd.get(node, {}).get('deployment.useinsecureprotocols',
'never')
{}).get('value', 'never')
if not insecuremode:
insecuremode = 'never'
if insecuremode == 'never' and not httpboot:
@@ -199,6 +199,7 @@ def _extract_neighbor_data_affluent(switch, user, password, cfm, lldpdata):
'port': record['localport'],
'peerid': peerid,
}
_extract_extended_desc(portdata, portdata['peerdescription'], True)
_neighbypeerid[peerid] = portdata
lldpdata[localport] = portdata
neighdata[switch] = lldpdata
@@ -100,7 +100,9 @@ class SshShell(conapi.Console):
while self.connected:
pendingdata = self.shell.recv(8192)
if not pendingdata:
self.datacallback(conapi.ConsoleEvent.Disconnect)
self.ssh.close()
if self.datacallback:
self.datacallback(conapi.ConsoleEvent.Disconnect)
return
self.datacallback(pendingdata)
@@ -110,7 +112,7 @@ class SshShell(conapi.Console):
# that would rather not use the nodename as anything but an opaque
# identifier
self.datacallback = callback
if self.username is not '':
if self.username is not b'':
self.logon()
else:
self.inputmode = 0
@@ -126,12 +128,14 @@ class SshShell(conapi.Console):
password=self.password, allow_agent=False,
look_for_keys=False)
except paramiko.AuthenticationException:
self.ssh.close()
self.inputmode = 0
self.username = b''
self.password = b''
self.datacallback('\r\nlogin as: ')
return
except paramiko.ssh_exception.NoValidConnectionsError as e:
self.ssh.close()
self.datacallback(str(e))
self.inputmode = 0
self.username = b''
@@ -139,6 +143,7 @@ class SshShell(conapi.Console):
self.datacallback('\r\nlogin as: ')
return
except cexc.PubkeyInvalid as pi:
self.ssh.close()
self.keyaction = ''
self.candidatefprint = pi.fingerprint
self.datacallback(pi.message)
@@ -148,6 +153,7 @@ class SshShell(conapi.Console):
self.datacallback('\r\nEnter "disconnect" or "accept": ')
return
except paramiko.SSHException as pi:
self.ssh.close()
self.inputmode = -2
warn = str(pi)
if warnhostkey:
+1 -1
View File
@@ -33,7 +33,7 @@ def get_extra_names(nodename, cfg):
currnames = currnames.split(',')
for currname in currnames:
names.add(currname)
if domain not in currname:
if domain and domain not in currname:
names.add('{0}.{1}'.format(currname, domain))
return names
@@ -111,6 +111,8 @@ class ShellSession(consoleserver.ConsoleSession):
def destroy(self):
try:
activesessions[(self.configmanager.tenant, self.node,
self.username)][self.sessionid].close()
del activesessions[(self.configmanager.tenant, self.node,
self.username)][self.sessionid]
except KeyError: