diff --git a/confluent_server/confluent/core.py b/confluent_server/confluent/core.py index 5b3b555d..d39b8e99 100644 --- a/confluent_server/confluent/core.py +++ b/confluent_server/confluent/core.py @@ -150,6 +150,16 @@ noderesources = { 'pluginattrs': ['hardwaremanagement.method'], 'default': 'ipmi', }), + 'ntp': { + 'enabled': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + 'servers': PluginCollection({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), + }, } }, '_console': { @@ -160,6 +170,10 @@ noderesources = { 'console': { # this is a dummy value, http or socket must handle special 'session': PluginRoute({}), + 'license': PluginRoute({ + 'pluginattrs': ['hardwaremanagement.method'], + 'default': 'ipmi', + }), }, 'events': { 'hardware': { diff --git a/confluent_server/confluent/messages.py b/confluent_server/confluent/messages.py index e8e9a2e0..a274b57b 100644 --- a/confluent_server/confluent/messages.py +++ b/confluent_server/confluent/messages.py @@ -340,6 +340,12 @@ def get_input_message(path, operation, inputdata, nodes=None, multinode=False): elif (path[:3] == ['configuration', 'management_controller', 'domain_name'] and operation != 'retrieve'): return InputDomainName(path, nodes, inputdata) + elif (path[:4] == ['configuration', 'management_controller', 'ntp', + 'enabled'] and operation != 'retrieve'): + return InputNTPEnabled(path, nodes, inputdata) + elif (path[:4] == ['configuration', 'management_controller', 'ntp', + 'servers'] and operation != 'retrieve' and len(path) == 5): + return InputNTPServer(path, nodes, inputdata) elif inputdata: raise exc.InvalidArgumentException() @@ -634,6 +640,37 @@ class InputDomainName(ConfluentInputMessage): def domain_name(self, node): return self.inputbynode[node] + +class InputNTPServer(ConfluentInputMessage): + def __init__(self, path, nodes, inputdata): + self.inputbynode = {} + self.stripped = False + if not inputdata or 'server' not in inputdata: + raise exc.InvalidArgumentException('missing input data') + if len(inputdata['server']) > 256: + raise exc.InvalidArgumentException( + 'identifier must be less than or = 256 chars') + + if nodes is None: + raise exc.InvalidArgumentException( + 'This only supports per-node input') + for node in nodes: + self.inputbynode[node] = inputdata['server'] + + def ntp_server(self, node): + return self.inputbynode[node] + + +class InputNTPEnabled(ConfluentInputMessage): + valid_values = set([ + 'True', + 'False' + ]) + + def ntp_enabled(self, node): + return self.inputbynode[node] + + class BootDevice(ConfluentChoiceMessage): valid_values = set([ 'network', @@ -743,6 +780,21 @@ class BMCReset(ConfluentChoiceMessage): keyname = 'state' +class NTPEnabled(ConfluentChoiceMessage): + valid_values = set([ + 'True', + 'False', + ]) + + def __init__(self, node, enabled): + self.stripped = False + self.kvpairs = { + node: { + 'state': {'value': str(enabled)}, + } + } + + class EventCollection(ConfluentMessage): """A collection of events @@ -1023,6 +1075,51 @@ class DomainName(ConfluentMessage): self.kvpairs = {name: kv} +class NTPServers(ConfluentMessage): + readonly = True + + def __init__(self, name=None, servers=None): + self.notnode = name is None + self.desc = 'NTP Server' + + kv = [] + for idx in range(0, len(servers)): + kv.append({str(idx+1): servers[idx]}) + if self.notnode: + self.kvpairs = {'ntp_servers': kv} + else: + self.kvpairs = {name: {'ntp_servers': kv}} + + +class NTPServer(ConfluentMessage): + def __init__(self, name=None, server=None): + self.notnode = name is None + self.desc = 'NTP Server' + + kv = { + 'server': {'value': server}, + } + if self.notnode: + self.kvpairs = kv + else: + self.kvpairs = {name: kv} + + +class License(ConfluentMessage): + readonly = True + + def __init__(self, name=None, kvm=None): + self.notnode = name is None + self.desc = 'License' + + kv = [] + kv.append({'kvm_availability': str(kvm)}) + if self.notnode: + self.kvpairs = {'License': kv} + else: + self.kvpairs = {name: {'License': kv}} + + class CryptedAttributes(Attributes): defaulttype = 'password' diff --git a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py index 1b243b45..565d01b5 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py @@ -357,6 +357,8 @@ class IpmiHandler(object): self.do_eventlog() elif self.element == ['events', 'hardware', 'decode']: self.decode_alert() + elif self.element == ['console', 'license']: + self.handle_license() else: raise Exception('Not Implemented') @@ -373,6 +375,8 @@ class IpmiHandler(object): return self.handle_identifier() elif self.element[1:3] == ['management_controller', 'domain_name']: return self.handle_domain_name() + elif self.element[1:3] == ['management_controller', 'ntp']: + return self.handle_ntp() raise Exception('Not implemented') def decode_alert(self): @@ -777,6 +781,51 @@ class IpmiHandler(object): self.ipmicmd.set_domain_name(dn) return + def handle_ntp(self): + if self.element[3] == 'enabled': + if 'read' == self.op: + enabled = self.ipmicmd.get_ntp_enabled() + self.output.put(msg.NTPEnabled(self.node, enabled)) + return + elif 'update' == self.op: + enabled = self.inputdata.ntp_enabled(self.node) + self.ipmicmd.set_ntp_enabled(enabled == 'True') + return + elif self.element[3] == 'servers': + if len(self.element) == 4: + self.output.put(msg.ChildCollection('all')) + size = len(self.ipmicmd.get_ntp_servers()) + for idx in range(1, size + 1): + self.output.put(msg.ChildCollection(idx)) + else: + if 'read' == self.op: + if self.element[-1] == 'all': + servers = self.ipmicmd.get_ntp_servers() + self.output.put(msg.NTPServers(self.node, servers)) + return + else: + idx = int(self.element[-1]) - 1 + servers = self.ipmicmd.get_ntp_servers() + self.output.put(msg.NTPServer(self.node, servers[idx])) + return + elif self.op in ('update', 'create'): + if self.element[-1] == 'all': + servers = self.inputdata.ntp_servers(self.node) + for idx in servers: + self.ipmicmd.set_ntp_server(server[idx], + int(idx[-1])-1) + return + else: + idx = int(self.element[-1]) - 1 + server = self.inputdata.ntp_server(self.node) + self.ipmicmd.set_ntp_server(server, idx) + return + + def handle_license(self): + available = self.ipmicmd.get_remote_kvm_available() + self.output.put(msg.License(self.node, available)) + return + def _str_health(health): if health == 'unknown': return health