2
0
mirror of https://github.com/xcat2/confluent.git synced 2025-04-18 19:18:59 +00:00
confluent/confluent/messages.py
Jarrod Johnson 9bf68c1639 Fix expression detection with unicode strings
If data was coming in as unicode strings (as is the case in the json
parser), it failed to treat the data as equivalent to string.  Correct
by checking both str and unicode for now
2014-03-01 10:48:08 -05:00

335 lines
11 KiB
Python

#Copyright 2013 IBM All rights reserved
# This module implements client/server messages emitted from plugins.
# Things are defined here to 'encourage' developers to coordinate information
# format. This is also how different data formats are supported
import confluent.exceptions as exc
import json
class ConfluentMessage(object):
defaultvalue = ''
defaulttype = 'text'
def __init__(self):
raise NotImplementedError("Must be subclassed!")
def json(self):
# This will create the canonical json representation of this message
jsonsnippet = json.dumps(self.kvpairs, separators=(',', ':'))[1:-1]
return jsonsnippet
def raw(self):
"""Return pythonic representation of the response.
Used by httpapi while assembling data prior to json serialization"""
return self.kvpairs
def strip_node(self, node):
self.kvpairs = self.kvpairs[node]
def html(self):
#this is used to facilitate the api explorer feature
snippet = ""
for key in self.kvpairs.iterkeys():
val = self.kvpairs[key]
value = self.defaultvalue
type = self.defaulttype
notes = []
if val is not None and 'value' in val:
value = val['value']
if 'inheritedfrom' in val:
notes.append('Inherited from %s' % val['inheritedfrom'])
if 'expression' in val:
notes.append('Derived from expression "%s"' % val['expression'])
elif val is not None and 'expression' in val:
value = val['expression']
if value is None:
value = ''
if val is not None and value == '' and 'isset' in val and val['isset'] is True:
# an encrypted value, put some *** to show it is set
# in the explorer
if 'inheritedfrom' in val:
notes.append('Inherited from %s' % val['inheritedfrom'])
value = '********'
if isinstance(val, list):
snippet += key + ":"
if len(val) == 0:
snippet += ('<input type="{0}" name="{1}" value="" '
' "title="{2}">'
).format(type, key, self.desc)
for v in val:
snippet += ('<input type="{0}" name="{1}" value="{2}" '
' "title="{3}">'
).format(type, key, v, self.desc)
snippet += (
'<input type="{0}" name="{1}" value="" title="{2}">'
'<input type="checkbox" name="restexplorerhonorkey" '
'value="{1}">').format(type, key, self.desc)
return snippet
snippet += (key + ":" +
'<input type="{0}" name="{1}" value="{2}" '
'title="{3}"><input type="checkbox" '
'name="restexplorerhonorkey" value="{1}">'
).format(type, key, value, self.desc)
if len(notes) > 0:
snippet += '(' + ','.join(notes) + ')'
return snippet
class DeletedResource(ConfluentMessage):
def __init__(self, resource):
self.kvpairs = {}
class ConfluentChoiceMessage(ConfluentMessage):
def html(self):
snippet = ""
for key in self.kvpairs.iterkeys():
val = self.kvpairs[key]
snippet += key + ':<select name="%s">' % key
for opt in self.valid_values:
snippet += opt + ":"
if opt == val['value']:
snippet += '<option value="%s" selected>%s</option>' % (
opt, opt)
else:
snippet += '<option value="%s">%s</option>' % (opt, opt)
snippet += '</select>'
snippet += '<input type="checkbox" name="restexplorerhonorkey" '
snippet += 'value="%s">' % (key)
return snippet
class LinkRelation(ConfluentMessage):
def json(self):
"""Provide json_hal style representation of the relation.
This currently only makes sense for the socket api.
"""
return {self.rel: '{ "href": "%s" }' % self.href}
def raw(self):
"""Provide python structure of the relation.
This currently is only sensible to consume from httpapi.
"""
return {self.rel: {"href": self.href}}
def html(self):
"""Provide an html representation of the link relation.
This is used by the API explorer aspect of httpapi"""
return '<a href="{0}" rel="{1}">{0}</a>'.format(self.href, self.rel)
# return '<a href="%s" rel="%s">%s</a><input type="submit"
# name="restexprerorop" value="delete:%s"' % (self.href, self.rel,
# self.href, self.href)
class ChildCollection(LinkRelation):
def __init__(self, collname, candelete=False):
self.rel = 'item'
self.href = collname
self.candelete = candelete
def html(self):
if self.candelete:
return ('<a href="{0}" rel="{1}">{0}</a> . . . . . . . . . . . . '
'<button type="submit" name="restexplorerop" '
'value="delete" formaction="{0}">delete'
'</button>').format(self.href, self.rel)
else:
return '<a href="{0}" rel="{0}">{0}</a>'.format(self.href)
def get_input_message(path, operation, inputdata, nodes=None):
if path[0] == 'power' and path[1] == 'state' and operation != 'retrieve':
return InputPowerMessage(path, nodes, inputdata)
elif path[0] == 'attributes' and operation != 'retrieve':
return InputAttributes(path, inputdata, nodes)
elif path == ['boot', 'nextdevice'] and operation != 'retrieve':
return InputBootDevice(path, nodes, inputdata)
elif inputdata:
raise exc.InvalidArgumentException()
class InputAttributes(ConfluentMessage):
def __init__(self, path, inputdata, nodes=None):
self.nodeattribs = {}
nestedmode = False
if not inputdata:
raise exc.InvalidArgumentException
if nodes is None:
self.attribs = inputdata
for attrib in self.attribs:
if (type(self.attribs[attrib]) in (str, unicode) and
'{' in self.attribs[attrib]):
self.attribs[attrib] = {'expression': self.attribs[attrib]}
return
for node in nodes:
if node in inputdata:
nestedmode = True
self.nodeattribs[node] = inputdata[node]
if nestedmode:
for key in inputdata:
if key not in nodes:
raise exc.InvalidArgumentException
else:
for node in nodes:
self.nodeattribs[node] = inputdata
def get_attributes(self, node):
if node not in self.nodeattribs:
return {}
nodeattr = self.nodeattribs[node]
for attr in nodeattr:
if type(nodeattr[attr]) in (str, unicode) and '{' in nodeattr[attr]:
nodeattr[attr] = {'expression': nodeattr[attr]}
return nodeattr
class InputPowerMessage(ConfluentMessage):
valid_values = set([
'on',
'off',
'reset',
'boot',
])
def __init__(self, path, nodes, inputdata):
self.powerbynode = {}
if not inputdata:
raise exc.InvalidArgumentException()
if 'state' not in inputdata:
#assume we have nested information
for key in nodes:
if key not in inputdata:
raise exc.InvalidArgumentException()
datum = inputdata[key]
if ('state' not in datum or
datum['state'] not in self.valid_values):
raise exc.InvalidArgumentException()
self.powerbynode[key] = datum['state']
else: # we have a state argument not by node
datum = inputdata
if ('state' not in datum or
datum['state'] not in self.valid_values):
raise exc.InvalidArgumentException()
for node in nodes:
self.powerbynode[node] = datum['state']
def powerstate(self, node):
return self.powerbynode[node]
class BootDevice(ConfluentChoiceMessage):
valid_values = set([
'network',
'hd',
'setup',
'default',
'cd',
])
def __init__(self, node, device):
if device not in self.valid_values:
raise Exception("Invalid boot device argument passed in:" + device)
self.kvpairs = {
node: {
'nextdevice': {'value': device},
}
}
class InputBootDevice(BootDevice):
def __init__(self, path, nodes, inputdata):
self.bootdevbynode = {}
if not inputdata:
raise exc.InvalidArgumentException()
if 'nextdevice' not in inputdata:
for key in nodes:
if key not in inputdata:
raise exc.InvalidArgumentException()
datum = inputdata[key]
if ('state' not in datum or
datum['state'] not in self.valid_values):
raise exc.InvalidArgumenTException()
self.bootdevbynode[key] = datum['nextdevice']
else:
datum = inputdata
if ('nextdevice' not in datum or
datum['nextdevice'] not in self.valid_values):
raise exc.InvalidArgumentException()
for node in nodes:
self.bootdevbynode[node] = datum['nextdevice']
def bootdevice(self, node):
return self.bootdevbynode[node]
class PowerState(ConfluentChoiceMessage):
valid_values = set([
'on',
'off',
'reset',
'boot',
])
def __init__(self, node, state):
self.kvpairs = {
node: {
'state': {'value': state},
}
}
class Attributes(ConfluentMessage):
def __init__(self, node=None, kv=None, desc=''):
self.desc = desc
nkv = {}
for key in kv.iterkeys():
if type(kv[key]) in (str, unicode):
nkv[key] = {'value': kv[key]}
else:
nkv[key] = kv[key]
if node is None:
self.kvpairs = nkv
else:
self.kvpairs = {
node: nkv
}
class ListAttributes(ConfluentMessage):
def __init__(self, node=None, kv=None, desc=''):
self.desc = desc
if node is None:
self.kvpairs = kv
else:
self.kvpairs = {node: kv}
class CryptedAttributes(Attributes):
defaulttype = 'password'
def __init__(self, node=None, kv=None, desc=''):
# for now, just keep the dictionary keys and discard crypt value
self.desc = desc
nkv = {}
for key in kv.iterkeys():
nkv[key] = {'isset': False}
try:
if kv[key] is not None and kv[key]['cryptvalue'] != '':
nkv[key] = {'isset': True}
nkv[key]['inheritedfrom'] = kv[key]['inheritedfrom']
except KeyError:
pass
if node is None:
self.kvpairs = nkv
else:
self.kvpairs = {
node: nkv
}