diff --git a/confluent/config/attributes.py b/confluent/config/attributes.py
index baece07e..72abc999 100644
--- a/confluent/config/attributes.py
+++ b/confluent/config/attributes.py
@@ -52,105 +52,106 @@ nic = {
# 'node', which can be considered a 'system' or a 'vm'
node = {
'groups': {
+ 'type': (list, tuple),
'default': 'all',
'description': ('List of static groups for which this node is'
'considered a member'),
},
- 'type': {
- 'description': ('Classification of node as system, vm, etc')
- },
- 'id': {
- 'description': ('Numeric identifier for node')
- },
- 'location.timezone': {
- 'description': 'POSIX timezone to apply to this node',
- },
- 'status.summary': {
- 'description': ('An assessment of the overall health of the node. It'
- 'can be "optimal", "warning", "critical"'),
- },
- 'status.lastheartbeat': {
- 'description': 'Timestamp of last received heartbeat',
- },
- 'status.heartbeatexpiry': {
- 'description': 'Time when Heartbeat will be considered expired',
- },
- 'status.deployment': {
- 'description': 'State of any deployment activity in progress',
- },
- 'status.faultdetails': {
- 'description': 'Detailed problem data, if any',
- },
- 'network.gateway': {
- 'description': 'Default gateway to configure node with',
- },
- 'network.nameservers': {
- 'description': '''DNS servers for node to use''',
- },
- 'network.domain': {
- 'description': 'Value to append to nodename, if any, to get FQDN',
- },
- 'network.interfaces': {
- 'dictof': 'nic',
- 'description': ('Dict of network interfaces to configure on node. '
- 'Keyed on hardware address.'),
- },
- 'storage.osvolume': {
- 'default': 'auto',
- 'description': 'Description of storage to target when deploying OS',
- },
- 'storage.clientiqn': {
- 'description': ('Indicates IQN used by this node when communicating'
- 'with iSCSI servers'),
- },
- 'storage.iscsiserver': {
- 'description': 'Address of iSCSI server used for boot if applicable',
- },
- 'storage.pool': {
- 'description': ('For scenarios like SAN boot and virtualization, this'
- 'describes the pool to allocate boot volume from'),
- },
- 'os.imagename': {
- 'description': 'The OS Image applied or to be applied to node',
- },
- 'console.speed': {
- 'default': 'auto',
- 'description': ('Indicate the speed at which to run serial port.'
- 'Default behavior is to autodetect the appropriate'
- 'value as possible')
- },
- 'console.port': {
- 'default': 'auto',
- 'description': ('Indicate which port to use for text console. Default'
- 'behavior is to auto detect the value appropriate for'
- 'the platform. "Disable" can be used to suppress'
- 'serial console configuration')
- },
+ #'type': {
+ # 'description': ('Classification of node as system, vm, etc')
+ #},
+ #'id': {
+ # 'description': ('Numeric identifier for node')
+ #},
+# 'location.timezone': {
+# 'description': 'POSIX timezone to apply to this node',
+# },
+# 'status.summary': {
+# 'description': ('An assessment of the overall health of the node. It'
+# 'can be "optimal", "warning", "critical"'),
+# },
+# 'status.lastheartbeat': {
+# 'description': 'Timestamp of last received heartbeat',
+# },
+# 'status.heartbeatexpiry': {
+# 'description': 'Time when Heartbeat will be considered expired',
+# },
+# 'status.deployment': {
+# 'description': 'State of any deployment activity in progress',
+# },
+# 'status.faultdetails': {
+# 'description': 'Detailed problem data, if any',
+# },
+# 'network.gateway': {
+# 'description': 'Default gateway to configure node with',
+# },
+# 'network.nameservers': {
+# 'description': '''DNS servers for node to use''',
+# },
+# 'network.domain': {
+# 'description': 'Value to append to nodename, if any, to get FQDN',
+# },
+# 'network.interfaces': {
+# 'dictof': 'nic',
+# 'description': ('Dict of network interfaces to configure on node. '
+# 'Keyed on hardware address.'),
+# },
+# 'storage.osvolume': {
+# 'default': 'auto',
+# 'description': 'Description of storage to target when deploying OS',
+# },
+# 'storage.clientiqn': {
+# 'description': ('Indicates IQN used by this node when communicating'
+# 'with iSCSI servers'),
+# },
+# 'storage.iscsiserver': {
+# 'description': 'Address of iSCSI server used for boot if applicable',
+# },
+# 'storage.pool': {
+# 'description': ('For scenarios like SAN boot and virtualization, this'
+# 'describes the pool to allocate boot volume from'),
+# },
+# 'os.imagename': {
+# 'description': 'The OS Image applied or to be applied to node',
+# },
+# 'console.speed': {
+# 'default': 'auto',
+# 'description': ('Indicate the speed at which to run serial port.'
+# 'Default behavior is to autodetect the appropriate'
+# 'value as possible')
+# },
+# 'console.port': {
+# 'default': 'auto',
+# 'description': ('Indicate which port to use for text console. Default'
+# 'behavior is to auto detect the value appropriate for'
+# 'the platform. "Disable" can be used to suppress'
+# 'serial console configuration')
+# },
'console.method': {
'description': ('Indicate the method used to access the console of'
'The managed node.')
},
- 'virtualization.host': {
- 'description': ('Hypervisor where this node does/should reside'),
- 'appliesto': ['vm'],
- },
- 'virtualization.computepool': {
- 'description': ('Set of compute resources this node is permitted to'
- ' be created on/be migrated to'),
- 'appliesto': ['vm'],
- },
- 'virtualization.storagemodel': {
- 'description': ('The model of storage adapter to emulate in a virtual'
- 'machine. Defaults to virtio-blk for KVM, vmscsi for'
- 'VMware'),
- 'appliesto': ['vm'],
- },
- 'virtualization.nicmodel': {
- 'description': ('The model of NIC adapter to emulate in a virtual'
- 'machine. Defaults to virtio-net for KVM, vmxnet3 for'
- 'VMware'),
- 'appliesto': ['vm'],
- },
+# 'virtualization.host': {
+# 'description': ('Hypervisor where this node does/should reside'),
+# 'appliesto': ['vm'],
+# },
+# 'virtualization.computepool': {
+# 'description': ('Set of compute resources this node is permitted to'
+# ' be created on/be migrated to'),
+# 'appliesto': ['vm'],
+# },
+# 'virtualization.storagemodel': {
+# 'description': ('The model of storage adapter to emulate in a virtual'
+# 'machine. Defaults to virtio-blk for KVM, vmscsi for'
+# 'VMware'),
+# 'appliesto': ['vm'],
+# },
+# 'virtualization.nicmodel': {
+# 'description': ('The model of NIC adapter to emulate in a virtual'
+# 'machine. Defaults to virtio-net for KVM, vmxnet3 for'
+# 'VMware'),
+# 'appliesto': ['vm'],
+# },
'hardwaremanagement.manager': {
'description': 'The management address dedicated to this node',
},
@@ -158,56 +159,56 @@ node = {
'description': 'The method used to perform operations such as power '
'control, get sensor data, get inventory, and so on. '
},
- 'enclosure.manager': {
- 'description': "The management device for this node's chassis",
- 'appliesto': ['system'],
- },
- 'enclosure.bay': {
- 'description': 'The bay in the enclosure, if any',
- 'appliesto': ['system'],
- },
- 'enclosure.type': {
- 'description': '''The type of enclosure in use (e.g. IBM BladeCenter,
-IBM Flex)''',
- 'appliesto': ['system'],
- },
- 'inventory.serialnumber': {
- 'description': 'The manufacturer serial number of node',
- },
- 'inventory.uuid': {
- 'description': 'The UUID of the node as presented in DMI',
- },
- 'inventory.modelnumber': {
- 'description': 'The manufacturer dictated model number for the node',
- },
- 'inventory.snmpengineid': {
- 'description': 'The SNMP Engine id used by this node',
- },
- 'secret.snmpuser': {
- 'description': 'The user to use for SNMPv3 access to this node',
- },
- 'secret.snmppassphrase': {
- 'description': 'The passphrase to use for SNMPv3 access to this node',
- },
- 'secret.snmplocalizedkey': {
- 'description': ("SNMPv3 key localized to this node's SNMP Engine id"
- 'This can be used in lieu of snmppassphrase to avoid'
- 'retaining the passphrase TODO: document procedure'
- 'to commit passphrase to localized key'),
- },
- 'secret.snmpcommunity': {
- 'description': ('SNMPv1 community string, it is highly recommended to'
- 'step up to SNMPv3'),
- },
- 'secret.localadminpassphrase': {
- 'description': ('The passphrase to apply to local root/administrator '
- 'account. '
- 'If the environment is 100% Linux, the value may be '
- 'one-way crypted as in /etc/shadow. For Windows, if '
- 'the value is not set or is one-way crypted, the '
- 'local '
- 'Administrator account will be disabled, requiring AD')
- },
+# 'enclosure.manager': {
+# 'description': "The management device for this node's chassis",
+# 'appliesto': ['system'],
+# },
+# 'enclosure.bay': {
+# 'description': 'The bay in the enclosure, if any',
+# 'appliesto': ['system'],
+# },
+# 'enclosure.type': {
+# 'description': '''The type of enclosure in use (e.g. IBM BladeCenter,
+#IBM Flex)''',
+# 'appliesto': ['system'],
+# },
+# 'inventory.serialnumber': {
+# 'description': 'The manufacturer serial number of node',
+# },
+# 'inventory.uuid': {
+# 'description': 'The UUID of the node as presented in DMI',
+# },
+# 'inventory.modelnumber': {
+# 'description': 'The manufacturer dictated model number for the node',
+# },
+# 'inventory.snmpengineid': {
+# 'description': 'The SNMP Engine id used by this node',
+# },
+# 'secret.snmpuser': {
+# 'description': 'The user to use for SNMPv3 access to this node',
+# },
+# 'secret.snmppassphrase': {
+# 'description': 'The passphrase to use for SNMPv3 access to this node',
+# },
+# 'secret.snmplocalizedkey': {
+# 'description': ("SNMPv3 key localized to this node's SNMP Engine id"
+# 'This can be used in lieu of snmppassphrase to avoid'
+# 'retaining the passphrase TODO: document procedure'
+# 'to commit passphrase to localized key'),
+# },
+# 'secret.snmpcommunity': {
+# 'description': ('SNMPv1 community string, it is highly recommended to'
+# 'step up to SNMPv3'),
+# },
+# 'secret.localadminpassphrase': {
+# 'description': ('The passphrase to apply to local root/administrator '
+# 'account. '
+# 'If the environment is 100% Linux, the value may be '
+# 'one-way crypted as in /etc/shadow. For Windows, if '
+# 'the value is not set or is one-way crypted, the '
+# 'local '
+# 'Administrator account will be disabled, requiring AD')
+# },
'secret.ipmikg': {
'description': 'Optional Integrity key for IPMI communication'
},
@@ -224,19 +225,19 @@ IBM Flex)''',
'to connect over the network and value is not set, '
'PASSW0RD is attempted')
},
- 'secret.managementuser': {
- 'description': ('Username to be set and used by protocols like SSH and '
- 'HTTP where client provides passphrase over the network.'
- 'Given the distinct security models betwen this class '
- 'of protocols and SNMP and IPMI, snmp and ipmi utilize '
- 'dedicated values.'),
- },
- 'secret.managementpassphrase': {
- 'description': ('Passphrase to be set and used by protocols like SSH '
- 'and HTTP, where client sends passphrase over the '
- 'network. Given distinct security models between '
- 'this class of protocols, SNMP, and IPMI, SNMP and '
- 'IPMI are given their own settings with distinct '
- 'behaviors'),
- },
+# 'secret.managementuser': {
+# 'description': ('Username to be set and used by protocols like SSH and '
+# 'HTTP where client provides passphrase over the network.'
+# 'Given the distinct security models betwen this class '
+# 'of protocols and SNMP and IPMI, snmp and ipmi utilize '
+# 'dedicated values.'),
+# },
+# 'secret.managementpassphrase': {
+# 'description': ('Passphrase to be set and used by protocols like SSH '
+# 'and HTTP, where client sends passphrase over the '
+# 'network. Given distinct security models between '
+# 'this class of protocols, SNMP, and IPMI, SNMP and '
+# 'IPMI are given their own settings with distinct '
+# 'behaviors'),
+# },
}
diff --git a/confluent/config/configmanager.py b/confluent/config/configmanager.py
index 4feebcce..c09c7f6c 100644
--- a/confluent/config/configmanager.py
+++ b/confluent/config/configmanager.py
@@ -554,6 +554,15 @@ class ConfigManager(object):
nodecfg = self._cfgstore['nodes'][node]
self._do_inheritance(nodecfg, attr, group)
+ def del_nodes(self, nodes):
+ if 'nodes' not in self._cfgstore:
+ return
+ for node in nodes:
+ if node in self._cfgstore['nodes']:
+ self._sync_groups_to_node(node=node, groups=[])
+ del self._cfgstore['nodes'][node]
+ self._bg_sync_to_file()
+
def set_node_attributes(self, attribmap):
if 'nodes' not in self._cfgstore:
self._cfgstore['nodes'] = {}
diff --git a/confluent/httpapi.py b/confluent/httpapi.py
index 318f4757..357fe81e 100644
--- a/confluent/httpapi.py
+++ b/confluent/httpapi.py
@@ -6,6 +6,7 @@
import base64
import Cookie
import confluent.auth as auth
+import confluent.config.attributes as attribs
import confluent.consoleserver as consoleserver
import confluent.exceptions as exc
import confluent.messages
@@ -31,6 +32,22 @@ opmap = {
'DELETE': 'delete',
}
+def node_creation_resources():
+ yield confluent.messages.Attributes(
+ kv={ 'name': None}, desc="Name of the node").html() + '
'
+ for attr in sorted(attribs.node.iterkeys()):
+ if attr.startswith("secret."):
+ yield confluent.messages.CryptedAttributes(
+ kv={ attr: None }, desc=attribs.node[attr]['description']).html() + \
+ '
'
+ else:
+ yield confluent.messages.Attributes(
+ kv={ attr: None }, desc=attribs.node[attr]['description']).html() + \
+ '
'
+
+create_resource_functions = {
+ '/node/': node_creation_resources,
+}
def _sessioncleaner():
while (1):
@@ -149,13 +166,18 @@ def _assign_consessionid(consolesession):
def resourcehandler(env, start_response):
"""Function to handle new wsgi requests
"""
- authorized = _authorize_request(env)
mimetype = _pick_mimetype(env)
reqbody = None
reqtype = None
if 'CONTENT_LENGTH' in env and int(env['CONTENT_LENGTH']) > 0:
reqbody = env['wsgi.input'].read(int(env['CONTENT_LENGTH']))
reqtype = env['CONTENT_TYPE']
+ operation = opmap[env['REQUEST_METHOD']]
+ querydict = _get_query_dict(env, reqbody, reqtype)
+ if 'restexplorerop' in querydict:
+ operation = querydict['restexplorerop']
+ del querydict['restexplorerop']
+ authorized = _authorize_request(env)
if authorized['code'] == 401:
start_response('401 Authentication Required',
[('Content-type', 'text/plain'),
@@ -174,11 +196,6 @@ def resourcehandler(env, start_response):
headers.extend(("Set-Cookie", m.OutputString())
for m in authorized['cookie'].values())
cfgmgr = authorized['cfgmgr']
- operation = opmap[env['REQUEST_METHOD']]
- querydict = _get_query_dict(env, reqbody, reqtype)
- if 'restexplorerop' in querydict:
- operation = querydict['restexplorerop']
- del querydict['restexplorerop']
if '/console/session' in env['PATH_INFO']:
#hard bake JSON into this path, do not support other incarnations
prefix, _, _ = env['PATH_INFO'].partition('/console/session')
@@ -235,46 +252,60 @@ def resourcehandler(env, start_response):
start_response('400 Bad Request', headers)
yield '400 - Bad Request'
return
- start_response('200 OK', headers)
+ pagecontent = ""
if mimetype == 'text/html':
for datum in _assemble_html(hdlr, resource, querydict, url):
- yield datum
+ pagecontent += datum
else:
for datum in _assemble_json(hdlr, resource, url):
- yield datum
+ pagecontent += datum
+ start_response('200 OK', headers)
+ yield pagecontent
def _assemble_html(responses, resource, querydict, url):
- yield '