From d0bd275cb379b6152c79f6a25a24d0d864815d38 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Thu, 7 Jan 2016 11:25:25 -0500 Subject: [PATCH] Instrument sessions/ collection This causes some additional features into core. Namely the ability to use a fixed module rather than a string defined plugin. This allows shellserver to implement the 'plugin' interface without living in 'plugins'. 'plugins' implies modularity and potential eventual choice, but this functionality is core. It would make sense for the 'attributes' plugin to be changed to match this strategy. --- confluent_server/confluent/auth.py | 4 +- .../confluent/config/configmanager.py | 3 +- confluent_server/confluent/core.py | 280 +++++++++--------- confluent_server/confluent/shellserver.py | 15 +- confluent_server/confluent/sockapi.py | 2 +- 5 files changed, 163 insertions(+), 141 deletions(-) diff --git a/confluent_server/confluent/auth.py b/confluent_server/confluent/auth.py index 709ac3ca..452cdc40 100644 --- a/confluent_server/confluent/auth.py +++ b/confluent_server/confluent/auth.py @@ -116,7 +116,7 @@ def authorize(name, element, tenant=False, operation='create', user, tenant = _get_usertenant(name, tenant) if tenant is not None and not configmanager.is_tenant(tenant): return None - manager = configmanager.ConfigManager(tenant) + manager = configmanager.ConfigManager(tenant, username=user) if skipuserobj: return None, manager, user, tenant, skipuserobj userobj = manager.get_user(user) @@ -178,7 +178,7 @@ def check_user_passphrase(name, passphrase, element=None, tenant=False): # invalidate cache and force the slower check del _passcache[(user, tenant)] return None - cfm = configmanager.ConfigManager(tenant) + cfm = configmanager.ConfigManager(tenant, username=user) ucfg = cfm.get_user(user) if ucfg is None or 'cryptpass' not in ucfg: eventlet.sleep(0.05) # stall even on test for existence of a username diff --git a/confluent_server/confluent/config/configmanager.py b/confluent_server/confluent/config/configmanager.py index 71462573..d241df9d 100644 --- a/confluent_server/confluent/config/configmanager.py +++ b/confluent_server/confluent/config/configmanager.py @@ -429,9 +429,10 @@ class ConfigManager(object): _nodecollwatchers = {} _notifierids = {} - def __init__(self, tenant, decrypt=False): + def __init__(self, tenant, decrypt=False, username=None): global _cfgstore self.decrypt = decrypt + self.current_user = username if tenant is None: self.tenant = None if 'main' not in _cfgstore: diff --git a/confluent_server/confluent/core.py b/confluent_server/confluent/core.py index dac3c29e..5bd29bbd 100644 --- a/confluent_server/confluent/core.py +++ b/confluent_server/confluent/core.py @@ -70,6 +70,7 @@ def nested_lookup(nestdict, key): def load_plugins(): # To know our plugins directory, we get the parent path of 'bin' + _init_core() path = os.path.dirname(os.path.realpath(__file__)) plugintop = os.path.realpath(os.path.join(path, 'plugins')) plugins = set() @@ -109,157 +110,163 @@ class PluginCollection(object): def __init__(self, routedict): self.routeinfo = routedict -# _ prefix indicates internal use (e.g. special console scheme) and should not -# be enumerated in any collection -noderesources = { - 'attributes': { - 'all': PluginRoute({'handler': 'attributes'}), - 'current': PluginRoute({'handler': 'attributes'}), - }, - 'boot': { - 'nextdevice': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - }, - 'configuration': { - 'management_controller': { - 'alerts': { - 'destinations': PluginCollection({ +def _init_core(): + global noderesources + global nodegroupresources + import confluent.shellserver as shellserver + # _ prefix indicates internal use (e.g. special console scheme) and should not + # be enumerated in any collection + noderesources = { + 'attributes': { + 'all': PluginRoute({'handler': 'attributes'}), + 'current': PluginRoute({'handler': 'attributes'}), + }, + 'boot': { + 'nextdevice': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + }, + 'configuration': { + 'management_controller': { + 'alerts': { + 'destinations': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + }, + 'users': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'net_interfaces': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'reset': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'identifier': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'domain_name': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'ntp': { + 'enabled': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'servers': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + }, + } + }, + '_console': { + 'session': PluginRoute({ + 'pluginattrs': ['console.method'], + }), + }, + '_shell': { + 'session': PluginRoute({ + # For now, not configurable, wait until there's demand + 'handler': 'ssh', + }), + }, + 'shell': { + # another special case similar to console + 'sessions': PluginCollection({ + 'handler': shellserver, + }), + }, + 'console': { + # this is a dummy value, http or socket must handle special + 'session': None, + 'license': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + }, + 'events': { + 'hardware': { + 'log': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'decode': PluginRoute({ 'pluginattrs': ['hardwaremanagement.method'], 'default': 'ipmi', }), }, - 'users': PluginCollection({ + }, + 'health': { + 'hardware': PluginRoute({ 'pluginattrs': ['hardwaremanagement.method'], 'default': 'ipmi', }), - 'net_interfaces': PluginCollection({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'reset': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'identifier': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'domain_name': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'ntp': { - 'enabled': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'servers': PluginCollection({ + }, + 'identify': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'inventory': { + 'hardware': { + 'all': PluginCollection({ 'pluginattrs': ['hardwaremanagement.method'], 'default': 'ipmi', }), }, - } - }, - '_console': { - 'session': PluginRoute({ - 'pluginattrs': ['console.method'], - }), - }, - '_shell': { - 'session': PluginRoute({ - # For now, not configurable, wait until there's demand - 'handler': 'ssh', - }) - }, - 'shell': { - # another special case similar to console - 'sessions': {}, - }, - 'console': { - # this is a dummy value, http or socket must handle special - 'session': None, - 'license': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - }, - 'events': { - 'hardware': { - 'log': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'decode': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - }, - }, - 'health': { - 'hardware': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - }, - 'identify': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'inventory': { - 'hardware': { - 'all': PluginCollection({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - }, - 'firmware': { - 'all': PluginCollection({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - }, - }, - 'power': { - 'state': PluginRoute({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - }, - 'sensors': { - 'hardware': { - 'all': PluginCollection({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'temperature': PluginCollection({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'power': PluginCollection({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'fans': PluginCollection({ - 'pluginattrs': ['hardwaremanagement.method'], - 'default': 'ipmi', - }), - 'leds': PluginCollection({ + 'firmware': { + 'all': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + }, + }, + 'power': { + 'state': PluginRoute({ 'pluginattrs': ['hardwaremanagement.method'], 'default': 'ipmi', }), }, + 'sensors': { + 'hardware': { + 'all': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'temperature': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'power': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'fans': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'leds': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + }, - }, -} + }, + } -nodegroupresources = { - 'attributes': { - 'all': PluginRoute({'handler': 'attributes'}), - 'current': PluginRoute({'handler': 'attributes'}), - }, -} + nodegroupresources = { + 'attributes': { + 'all': PluginRoute({'handler': 'attributes'}), + 'current': PluginRoute({'handler': 'attributes'}), + }, + } def create_user(inputdata, configmanager): @@ -525,7 +532,10 @@ def handle_node_request(configmanager, inputdata, operation, inputdata = msg.get_input_message( pathcomponents, operation, inputdata, nodes, isnoderange) if 'handler' in plugroute: # fixed handler definition, easy enough - hfunc = getattr(pluginmap[plugroute['handler']], operation) + if isinstance(plugroute['handler'], str): + hfunc = getattr(pluginmap[plugroute['handler']], operation) + else: + hfunc = getattr(plugroute['handler'], operation) passvalue = hfunc( nodes=nodes, element=pathcomponents, configmanager=configmanager, diff --git a/confluent_server/confluent/shellserver.py b/confluent_server/confluent/shellserver.py index 6ba2cfd5..1a8aaeb5 100644 --- a/confluent_server/confluent/shellserver.py +++ b/confluent_server/confluent/shellserver.py @@ -20,8 +20,8 @@ import confluent.consoleserver as consoleserver -import uuid - +import confluent.exceptions as exc +import confluent.messages as msg activesessions = {} @@ -99,3 +99,14 @@ class ShellSession(consoleserver.ConsoleSession): activesessions[(tenant, self.node)][self.sessionid] = _ShellHandler(self.node, self.configmanager) self.conshdl = activesessions[(self.configmanager.tenant, self.node)][self.sessionid] +def create(nodes, element, configmanager, inputdata): + # For creating a resource, it really has to be handled + # in httpapi/sockapi specially, like a console. + raise exc.InvalidArgumentException('Special client code required') + +def retrieve(nodes, element, configmanager, inputdata): + tenant = configmanager.tenant + user = configmanager.current_user + if (tenant, nodes[0]) in activesessions: + for sessionid in activesessions[(tenant, nodes[0])]: + yield msg.ChildCollection(sessionid) diff --git a/confluent_server/confluent/sockapi.py b/confluent_server/confluent/sockapi.py index 4c819b66..38bf589c 100644 --- a/confluent_server/confluent/sockapi.py +++ b/confluent_server/confluent/sockapi.py @@ -89,7 +89,7 @@ def sessionhdl(connection, authname, skipauth=False): cfm = None if skipauth: authenticated = True - cfm = configmanager.ConfigManager(tenant=None) + cfm = configmanager.ConfigManager(tenant=None, username=authname) elif authname: authdata = auth.authorize(authname, element=None) if authdata is not None: