2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-09-02 07:26:04 +00:00

Merge pull request #278 from Obihoernchen/fix/configurable-endpoints

configurable sockapi path and ipmi port
This commit is contained in:
Jarrod Johnson
2026-08-19 08:33:06 -04:00
committed by GitHub
3 changed files with 72 additions and 22 deletions
+5 -1
View File
@@ -148,7 +148,11 @@ class Console(object):
# some BMCs disagree on the endianness, so do both
valid_ports = (self.port, struct.unpack(
'<H', struct.pack('>H', self.port))[0])
if (data[8] + (data[9] << 8)) not in valid_ports:
solport = data[8] + (data[9] << 8)
# A bmc behind a port forward answers with the port it listens on
# rather than the one it was reached through; payloads ride the
# session, never the advertised port.
if solport not in valid_ports and self.port == 623:
# TODO(jbjohnso): support atypical SOL port number
raise NotImplementedError("Non-standard SOL Port Number")
# ignore data[10:11] for now, the vlan detail, shouldn't matter to this
@@ -263,14 +263,37 @@ def get_conn_params(node, configdata):
kg = configdata['secret.ipmikg']['value']
else:
kg = passphrase
# TODO(jbjohnso): check if the end has some number after a : without []
# for non default port
# Read a port off the address, as the redfish plugin does. Brackets come
# off, unlike there: this address goes to socket.getaddrinfo, which rejects
# a bracketed literal, rather than into a URL where one is required.
bmc = bmc.strip()
port = 623
if bmc.startswith('['):
bracket_end = bmc.find(']')
if bracket_end > 0:
if len(bmc) > bracket_end + 1 and bmc[bracket_end + 1] == ':':
try:
port = int(bmc[bracket_end + 2:])
except (ValueError, TypeError):
pass
bmc = bmc[1:bracket_end]
elif bmc.count(':') == 1:
hostpart, _, portstr = bmc.rpartition(':')
try:
port = int(portstr)
except (ValueError, TypeError):
pass
bmc = hostpart
if not 0 < port <= 65535:
# NOTE: Fallback to 623 if port read is not valid
port = 623
return {
'username': username,
'passphrase': passphrase,
'kg': kg,
'bmc': bmc,
'port': 623,
'port': port,
}
@@ -288,6 +311,11 @@ def _donothing(data):
class IpmiConsole(conapi.Console):
configattributes = frozenset(_configattributes)
bmctonodemapping = {}
# Whether this instance is the one that put its endpoint in the mapping
# above. False until it does, so that an instance rejected as a duplicate,
# or one that failed earlier in __init__, does not remove on the way out an
# entry that belongs to the node holding the endpoint.
claimedbmc = False
def __init__(self, node, config):
self.error = None
@@ -304,20 +332,26 @@ class IpmiConsole(conapi.Console):
self.kg = connparams['kg']
self.bmc = connparams['bmc']
self.port = connparams['port']
# The port is part of the identity: several bmcs may sit behind one
# address on different ports, and they are distinct devices.
self.bmckey = (self.bmc, self.port)
self.connected = False
# ok, is self.bmc unique among nodes already
# ok, is this bmc unique among nodes already
# Cannot actually create console until 'connect', when we get callback
if (self.bmc in self.bmctonodemapping and
self.bmctonodemapping[self.bmc] != node):
if (self.bmckey in self.bmctonodemapping and
self.bmctonodemapping[self.bmckey] != node):
raise Exception(
"Duplicate hardwaremanagement.manager attribute for {0} and {1}".format(
node, self.bmctonodemapping[self.bmc]))
self.bmctonodemapping[self.bmc] = node
node, self.bmctonodemapping[self.bmckey]))
self.bmctonodemapping[self.bmckey] = node
self.claimedbmc = True
def __del__(self):
self.solconnection = None
if not self.claimedbmc:
return
try:
del self.bmctonodemapping[self.bmc]
del self.bmctonodemapping[self.bmckey]
except KeyError:
pass
+24 -12
View File
@@ -438,31 +438,40 @@ async def _tlsstartup(cnn):
raise Exception('Unable to find workable SSL support')
tasks.spawn(sessionhdl(cnn, authname, cert=cert))
def removesocket():
default_socketpath = "/var/run/confluent/api.sock"
def removesocket(socketpath=None):
if socketpath is None:
socketpath = default_socketpath
try:
os.remove("/var/run/confluent/api.sock")
os.remove(socketpath)
except OSError:
pass
async def _unixdomainhandler(bind_group=None, bind_perms=None):
async def _unixdomainhandler(bind_group=None, bind_perms=None,
socketpath=None):
aloop = asyncio.get_running_loop()
if not bind_perms:
bind_perms = 0o666
if socketpath is None:
socketpath = default_socketpath
unixsocket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
unixsocket.settimeout(0)
try:
os.remove("/var/run/confluent/api.sock")
os.remove(socketpath)
except OSError: # if file does not exist, no big deal
pass
if not os.path.isdir("/var/run/confluent"):
os.makedirs('/var/run/confluent', 0o755)
socketdir = os.path.dirname(socketpath)
if socketdir and not os.path.isdir(socketdir):
os.makedirs(socketdir, 0o755)
oldumask = os.umask(0o777 - bind_perms)
unixsocket.bind("/var/run/confluent/api.sock")
os.chmod("/var/run/confluent/api.sock", bind_perms)
unixsocket.bind(socketpath)
os.chmod(socketpath, bind_perms)
if bind_group:
shutil.chown("/var/run/confluent/api.sock", group=bind_group)
shutil.chown(socketpath, group=bind_group)
os.umask(oldumask)
atexit.register(removesocket)
atexit.register(removesocket, socketpath)
unixsocket.listen(5)
while True:
cnn, addr = await aloop.sock_accept(unixsocket)
@@ -491,13 +500,15 @@ async def _unixdomainhandler(bind_group=None, bind_perms=None):
class SockApi(object):
def __init__(self, bindhost=None, bindport=None, bindgroup=None, bindperms=None):
def __init__(self, bindhost=None, bindport=None, bindgroup=None,
bindperms=None, socketpath=None):
self.tlsserver = None
self.unixdomainserver = None
self.bind_host = bindhost or '::'
self.bind_port = bindport or 13001
self.bind_group = bindgroup
self.bind_perms = bindperms
self.socketpath = socketpath or default_socketpath
async def start(self):
global auditlog
@@ -509,7 +520,8 @@ class SockApi(object):
self.start_remoteapi()
else:
tasks.spawn(self.watch_for_cert())
self.unixdomainserver = tasks.spawn_task(_unixdomainhandler(self.bind_group, self.bind_perms))
self.unixdomainserver = tasks.spawn_task(_unixdomainhandler(
self.bind_group, self.bind_perms, self.socketpath))
async def watch_for_cert(self):
watcher = libc.inotify_init1(os.O_NONBLOCK)