mirror of
https://github.com/xcat2/confluent.git
synced 2024-11-25 19:10:10 +00:00
Merge branch 'master' of github.com:jjohnson42/confluent
This commit is contained in:
commit
45b8a18f14
62
confluent_client/bin/nodereseat
Normal file
62
confluent_client/bin/nodereseat
Normal file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015-2017 Lenovo
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import optparse
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
try:
|
||||
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
path = os.path.dirname(os.path.realpath(__file__))
|
||||
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
|
||||
if path.startswith('/opt'):
|
||||
sys.path.append(path)
|
||||
|
||||
import confluent.client as client
|
||||
|
||||
argparser = optparse.OptionParser(usage="Usage: %prog <noderange>")
|
||||
(options, args) = argparser.parse_args()
|
||||
try:
|
||||
noderange = args[0]
|
||||
except IndexError:
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
session = client.Command()
|
||||
exitcode = 0
|
||||
|
||||
errorNodes = set([])
|
||||
|
||||
success = session.simple_noderange_command(noderange, 'power/reseat', 'reseat', key='reseat', errnodes=errorNodes) # = 0 if successful
|
||||
|
||||
# Determine which nodes were successful and print them
|
||||
|
||||
allNodes = set([])
|
||||
|
||||
for node in session.read('/noderange/{0}/nodes/'.format(noderange)):
|
||||
allNodes.add(node['item']['href'].replace("/", ""))
|
||||
|
||||
goodNodes = allNodes - errorNodes
|
||||
|
||||
for node in goodNodes:
|
||||
print node + ": Reseat successful"
|
||||
|
||||
|
||||
sys.exit(success)
|
@ -185,6 +185,11 @@ def _init_core():
|
||||
'handler': 'ssh',
|
||||
}),
|
||||
},
|
||||
'_enclosure': {
|
||||
'reseat_bay': PluginRoute(
|
||||
{'pluginattrs': ['hardwaremanagement.method'],
|
||||
'default': 'ipmi'}),
|
||||
},
|
||||
'shell': {
|
||||
# another special case similar to console
|
||||
'sessions': PluginCollection({
|
||||
@ -250,6 +255,7 @@ def _init_core():
|
||||
'pluginattrs': ['hardwaremanagement.method'],
|
||||
'default': 'ipmi',
|
||||
}),
|
||||
'reseat': PluginRoute({'handler': 'enclosure'}),
|
||||
},
|
||||
'sensors': {
|
||||
'hardware': {
|
||||
|
@ -364,6 +364,9 @@ class ChildCollection(LinkRelation):
|
||||
def get_input_message(path, operation, inputdata, nodes=None, multinode=False):
|
||||
if path[0] == 'power' and path[1] == 'state' and operation != 'retrieve':
|
||||
return InputPowerMessage(path, nodes, inputdata)
|
||||
elif (path in (['power', 'reseat'], ['_enclosure', 'reseat_bay']) and
|
||||
operation != 'retrieve'):
|
||||
return InputReseatMessage(path, nodes, inputdata)
|
||||
elif path == ['attributes', 'expression']:
|
||||
return InputExpression(path, inputdata, nodes)
|
||||
elif path[0] in ('attributes', 'users') and operation != 'retrieve':
|
||||
@ -624,7 +627,7 @@ class ConfluentInputMessage(ConfluentMessage):
|
||||
if self.keyname not in datum:
|
||||
raise exc.InvalidArgumentException(
|
||||
'missing {0} argument'.format(self.keyname))
|
||||
elif datum[self.keyname] not in self.valid_values:
|
||||
elif not self.is_valid_key(datum[self.keyname]):
|
||||
raise exc.InvalidArgumentException(
|
||||
datum[self.keyname] + ' is not one of ' +
|
||||
','.join(self.valid_values))
|
||||
@ -634,13 +637,15 @@ class ConfluentInputMessage(ConfluentMessage):
|
||||
if self.keyname not in datum:
|
||||
raise exc.InvalidArgumentException(
|
||||
'missing {0} argument'.format(self.keyname))
|
||||
elif datum[self.keyname] not in self.valid_values:
|
||||
elif not self.is_valid_key(datum[self.keyname]):
|
||||
raise exc.InvalidArgumentException(datum[self.keyname] +
|
||||
' is not one of ' +
|
||||
','.join(self.valid_values))
|
||||
for node in nodes:
|
||||
self.inputbynode[node] = datum[self.keyname]
|
||||
|
||||
def is_valid_key(self, key):
|
||||
return key in self.valid_values
|
||||
|
||||
class InputIdentifyMessage(ConfluentInputMessage):
|
||||
valid_values = set([
|
||||
@ -664,6 +669,16 @@ class InputPowerMessage(ConfluentInputMessage):
|
||||
def powerstate(self, node):
|
||||
return self.inputbynode[node]
|
||||
|
||||
class InputReseatMessage(ConfluentInputMessage):
|
||||
valid_values = set([
|
||||
'reseat',
|
||||
])
|
||||
|
||||
keyname = 'reseat'
|
||||
|
||||
def is_valid_key(self, key):
|
||||
return key in self.valid_values or isinstance(key, int)
|
||||
|
||||
|
||||
class InputBMCReset(ConfluentInputMessage):
|
||||
valid_values = set([
|
||||
@ -875,6 +890,13 @@ class IdentifyState(ConfluentChoiceMessage):
|
||||
keyname = 'identify'
|
||||
|
||||
|
||||
class ReseatResult(ConfluentChoiceMessage):
|
||||
valid_values = set([
|
||||
'success',
|
||||
])
|
||||
keyname = 'reseat'
|
||||
|
||||
|
||||
class PowerState(ConfluentChoiceMessage):
|
||||
valid_values = set([
|
||||
'on',
|
||||
|
@ -0,0 +1,26 @@
|
||||
# Copyright 2017 Lenovo
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import confluent.core as core
|
||||
|
||||
def update(nodes, element, configmanager, inputdata):
|
||||
emebs = configmanager.get_node_attributes(
|
||||
nodes, (u'enclosure.manager', u'enclosure.bay'))
|
||||
for node in nodes:
|
||||
em = emebs[node]['enclosure.manager']['value']
|
||||
eb = emebs[node]['enclosure.bay']['value']
|
||||
for rsp in core.handle_path(
|
||||
'/nodes/{0}/_enclosure/reseat_bay'.format(em),
|
||||
'update', configmanager,
|
||||
inputdata={'reseat': int(eb)}):
|
||||
yield rsp
|
@ -432,6 +432,8 @@ class IpmiHandler(object):
|
||||
raise Exception(self.error)
|
||||
if self.element == ['power', 'state']:
|
||||
self.power()
|
||||
elif self.element == ['_enclosure', 'reseat_bay']:
|
||||
self.reseat_bay()
|
||||
elif self.element == ['boot', 'nextdevice']:
|
||||
self.bootdevice()
|
||||
elif self.element == ['health', 'hardware']:
|
||||
@ -820,6 +822,11 @@ class IpmiHandler(object):
|
||||
else:
|
||||
raise exc.InvalidArgumentException('health is read-only')
|
||||
|
||||
def reseat_bay(self):
|
||||
bay = self.inputdata.inputbynode[self.node]
|
||||
self.ipmicmd.reseat_bay(bay)
|
||||
self.output.put(msg.ReseatResult(self.node, 'success'))
|
||||
|
||||
def bootdevice(self):
|
||||
if 'read' == self.op:
|
||||
bootdev = self.ipmicmd.get_bootdev()
|
||||
|
Loading…
Reference in New Issue
Block a user