mirror of
https://github.com/xcat2/confluent.git
synced 2025-01-27 19:37:57 +00:00
Merge branch 'master' into 2.2
This commit is contained in:
commit
5481da269e
63
confluent_client/bin/nodegrouprename
Normal file
63
confluent_client/bin/nodegrouprename
Normal file
@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2019 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.
|
||||
|
||||
__author__ = 'jjohnson2,alin37,andywray'
|
||||
|
||||
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
|
||||
|
||||
def main():
|
||||
argparser = optparse.OptionParser(
|
||||
usage="Usage: %prog <group> <new group name>\n")
|
||||
(options, args) = argparser.parse_args()
|
||||
noderange=""
|
||||
nodelist=""
|
||||
nodelist = '/nodegroups/'
|
||||
session = client.Command()
|
||||
exitcode = 0
|
||||
requestargs=args[1:]
|
||||
nodetype='noderange'
|
||||
if len(args) != 2:
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
else:
|
||||
for res in session.update(
|
||||
'/nodegroups/{0}/attributes/rename'.format(args[0]),
|
||||
{'rename': args[1]}):
|
||||
if 'error' in res:
|
||||
sys.stderr.write(res['error'] + '\n')
|
||||
exitcode = 1
|
||||
else:
|
||||
print('{0}: {1}'.format(res['oldname'], res['newname']))
|
||||
|
||||
sys.exit(exitcode)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
52
confluent_client/bin/noderename
Normal file
52
confluent_client/bin/noderename
Normal file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2019 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> <newname>")
|
||||
(options, args) = argparser.parse_args()
|
||||
try:
|
||||
noderange = args[0]
|
||||
except IndexError:
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
client.check_globbing(noderange)
|
||||
identifystate = None
|
||||
if len(sys.argv) > 2:
|
||||
newname = sys.argv[2]
|
||||
else:
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
session = client.Command()
|
||||
exitcode = 0
|
||||
sys.exit(
|
||||
session.simple_noderange_command(noderange, 'attributes/rename', newname))
|
||||
|
@ -181,6 +181,14 @@ def _rpc_master_set_node_attributes(tenant, attribmap, autocreate):
|
||||
ConfigManager(tenant).set_node_attributes(attribmap, autocreate)
|
||||
|
||||
|
||||
def _rpc_master_rename_nodes(tenant, renamemap):
|
||||
ConfigManager(tenant).rename_nodes(renamemap)
|
||||
|
||||
|
||||
def _rpc_master_rename_nodegroups(tenant, renamemap):
|
||||
ConfigManager(tenant).rename_nodegroups(renamemap)
|
||||
|
||||
|
||||
def _rpc_master_clear_node_attributes(tenant, nodes, attributes):
|
||||
ConfigManager(tenant).clear_node_attributes(nodes, attributes)
|
||||
|
||||
@ -234,6 +242,14 @@ def _rpc_set_node_attributes(tenant, attribmap, autocreate):
|
||||
ConfigManager(tenant)._true_set_node_attributes(attribmap, autocreate)
|
||||
|
||||
|
||||
def _rpc_rename_nodes(tenant, renamemap):
|
||||
ConfigManager(tenant)._true_rename_nodes(renamemap)
|
||||
|
||||
|
||||
def _rpc_rename_nodegroups(tenant, renamemap):
|
||||
ConfigManager(tenant)._true_rename_nodegroups(renamemap)
|
||||
|
||||
|
||||
def _rpc_set_group_attributes(tenant, attribmap, autocreate):
|
||||
ConfigManager(tenant)._true_set_group_attributes(attribmap, autocreate)
|
||||
|
||||
@ -288,9 +304,9 @@ def logException():
|
||||
event=confluent.log.Events.stacktrace)
|
||||
|
||||
|
||||
def _do_add_watcher(watcher, added, configmanager):
|
||||
def _do_add_watcher(watcher, added, configmanager, renamed=()):
|
||||
try:
|
||||
watcher(added=added, deleting=[], configmanager=configmanager)
|
||||
watcher(added=added, deleting=(), renamed=renamed, configmanager=configmanager)
|
||||
except Exception:
|
||||
logException()
|
||||
|
||||
@ -1705,7 +1721,7 @@ class ConfigManager(object):
|
||||
def _true_del_nodes(self, nodes):
|
||||
if self.tenant in self._nodecollwatchers:
|
||||
for watcher in self._nodecollwatchers[self.tenant].itervalues():
|
||||
watcher(added=[], deleting=nodes, configmanager=self)
|
||||
watcher(added=(), deleting=nodes, renamed=(), configmanager=self)
|
||||
changeset = {}
|
||||
for node in nodes:
|
||||
# set a reserved attribute for the sake of the change notification
|
||||
@ -1789,6 +1805,86 @@ class ConfigManager(object):
|
||||
attribmap[node]['groups'] = []
|
||||
self.set_node_attributes(attribmap, autocreate=True)
|
||||
|
||||
def rename_nodes(self, renamemap):
|
||||
if cfgleader:
|
||||
return exec_on_leader('_rpc_master_rename_nodes', self.tenant,
|
||||
renamemap)
|
||||
if cfgstreams:
|
||||
exec_on_followers('_rpc_rename_nodes', self.tenant, renamemap)
|
||||
self._true_rename_nodes(renamemap)
|
||||
|
||||
def _true_rename_nodes(self, renamemap):
|
||||
oldnames = set(renamemap)
|
||||
exprmgr = None
|
||||
currnodes = set(self._cfgstore['nodes'])
|
||||
missingnodes = oldnames - currnodes
|
||||
if missingnodes:
|
||||
raise ValueError(
|
||||
'The following nodes to rename do not exist: {0}'.format(
|
||||
','.join(missingnodes)))
|
||||
newnames = set([])
|
||||
for name in renamemap:
|
||||
newnames.add(renamemap[name])
|
||||
if newnames & currnodes:
|
||||
raise ValueError(
|
||||
'The following requested new names conflict with existing nodes: {0}'.format(
|
||||
','.join(newnames & currnodes)))
|
||||
for name in renamemap:
|
||||
self._cfgstore['nodes'][renamemap[name]] = self._cfgstore['nodes'][name]
|
||||
del self._cfgstore['nodes'][name]
|
||||
_mark_dirtykey('nodes', name, self.tenant)
|
||||
_mark_dirtykey('nodes', renamemap[name], self.tenant)
|
||||
for group in self._cfgstore['nodes'][renamemap[name]].get('groups', []):
|
||||
self._cfgstore['nodegroups'][group]['nodes'].discard(name)
|
||||
self._cfgstore['nodegroups'][group]['nodes'].add(renamemap[name])
|
||||
_mark_dirtykey('nodegroups', group, self.tenant)
|
||||
cfgobj = self._cfgstore['nodes'][renamemap[name]]
|
||||
node = renamemap[name]
|
||||
changeset = {}
|
||||
if exprmgr is None:
|
||||
exprmgr = _ExpressionFormat(cfgobj, node)
|
||||
self._recalculate_expressions(cfgobj, formatter=exprmgr, node=renamemap[name], changeset=changeset)
|
||||
if self.tenant in self._nodecollwatchers:
|
||||
nodecollwatchers = self._nodecollwatchers[self.tenant]
|
||||
for watcher in nodecollwatchers.itervalues():
|
||||
eventlet.spawn_n(_do_add_watcher, watcher, (), self, renamemap)
|
||||
self._bg_sync_to_file()
|
||||
|
||||
def rename_nodegroups(self, renamemap):
|
||||
if cfgleader:
|
||||
return exec_on_leader('_rpc_master_rename_nodegroups', self.tenant, renamemap)
|
||||
if cfgstreams:
|
||||
exec_on_followers('_rpc_rename_nodegroups', self.tenant, renamemap)
|
||||
self._true_rename_groups(renamemap)
|
||||
|
||||
def _true_rename_groups(self, renamemap):
|
||||
oldnames = set(renamemap)
|
||||
currgroups = set(self._cfgstore['nodegroups'])
|
||||
missinggroups = oldnames - currgroups
|
||||
if missinggroups:
|
||||
raise ValueError(
|
||||
'The following groups to rename do not exist: {0}'.format(
|
||||
','.join(missinggroups)))
|
||||
newnames = set([])
|
||||
for name in renamemap:
|
||||
newnames.add(renamemap[name])
|
||||
if newnames & currgroups:
|
||||
raise ValueError(
|
||||
'The following requested new names conflict with existing groups: {0}'.format(
|
||||
','.join(newnames & currgroups)))
|
||||
for name in renamemap:
|
||||
self._cfgstore['nodegroups'][renamemap[name]] = self._cfgstore['nodegroups'][name]
|
||||
del self._cfgstore['nodegroups'][name]
|
||||
_mark_dirtykey('nodegroups', name, self.tenant)
|
||||
_mark_dirtykey('nodegroups', renamemap[name], self.tenant)
|
||||
for node in self._cfgstore['nodegroups'][renamemap[name]].get('nodes', []):
|
||||
lidx = self._cfgstore['nodes'][node]['groups'].index(name)
|
||||
self._cfgstore['nodes'][node]['groups'][lidx] = renamemap[name]
|
||||
_mark_dirtykey('nodes', node, self.tenant)
|
||||
self._bg_sync_to_file()
|
||||
|
||||
|
||||
|
||||
def set_node_attributes(self, attribmap, autocreate=False):
|
||||
if cfgleader: # currently config slave to another
|
||||
return exec_on_leader('_rpc_master_set_node_attributes',
|
||||
|
@ -621,11 +621,14 @@ def disconnect_node(node, configmanager):
|
||||
del _handled_consoles[consk]
|
||||
|
||||
|
||||
def _nodechange(added, deleting, configmanager):
|
||||
for node in added:
|
||||
connect_node(node, configmanager)
|
||||
def _nodechange(added, deleting, renamed, configmanager):
|
||||
for node in deleting:
|
||||
disconnect_node(node, configmanager)
|
||||
for node in renamed:
|
||||
disconnect_node(node, configmanager)
|
||||
connect_node(renamed[node], configmanager)
|
||||
for node in added:
|
||||
connect_node(node, configmanager)
|
||||
|
||||
|
||||
def _start_tenant_sessions(cfm):
|
||||
|
@ -144,6 +144,7 @@ def _init_core():
|
||||
# be enumerated in any collection
|
||||
noderesources = {
|
||||
'attributes': {
|
||||
'rename': PluginRoute({'handler': 'attributes'}),
|
||||
'all': PluginRoute({'handler': 'attributes'}),
|
||||
'current': PluginRoute({'handler': 'attributes'}),
|
||||
'expression': PluginRoute({'handler': 'attributes'}),
|
||||
@ -379,6 +380,7 @@ def _init_core():
|
||||
|
||||
nodegroupresources = {
|
||||
'attributes': {
|
||||
'rename': PluginRoute({'handler': 'attributes'}),
|
||||
'all': PluginRoute({'handler': 'attributes'}),
|
||||
'current': PluginRoute({'handler': 'attributes'}),
|
||||
},
|
||||
|
@ -1129,11 +1129,12 @@ def _handle_nodelist_change(configmanager):
|
||||
nodeaddhandler = None
|
||||
|
||||
|
||||
def newnodes(added, deleting, configmanager):
|
||||
def newnodes(added, deleting, renamed, configmanager):
|
||||
global attribwatcher
|
||||
global needaddhandled
|
||||
global nodeaddhandler
|
||||
for node in deleting:
|
||||
alldeleting = set(deleting) | set(renamed)
|
||||
for node in alldeleting:
|
||||
if node not in known_nodes:
|
||||
continue
|
||||
for mac in known_nodes[node]:
|
||||
|
@ -267,6 +267,24 @@ class CreatedResource(ConfluentMessage):
|
||||
pass
|
||||
|
||||
|
||||
class RenamedResource(ConfluentMessage):
|
||||
notnode = True
|
||||
readonly = True
|
||||
|
||||
def __init__(self, oldname, newname):
|
||||
self.kvpairs = {'oldname': oldname, 'newname': newname}
|
||||
|
||||
def strip_node(self, node):
|
||||
pass
|
||||
|
||||
|
||||
class RenamedNode(ConfluentMessage):
|
||||
def __init__(self, name, rename):
|
||||
self.desc = 'New Name'
|
||||
kv = {'rename': {'value': rename}}
|
||||
self.kvpairs = {name: kv}
|
||||
|
||||
|
||||
class AssignedResource(ConfluentMessage):
|
||||
notnode = True
|
||||
readonly = True
|
||||
@ -381,6 +399,8 @@ def get_input_message(path, operation, inputdata, nodes=None, multinode=False,
|
||||
return InputReseatMessage(path, nodes, inputdata)
|
||||
elif path == ['attributes', 'expression']:
|
||||
return InputExpression(path, inputdata, nodes)
|
||||
elif path == ['attributes', 'rename']:
|
||||
return InputConfigChangeSet(path, inputdata, nodes, configmanager)
|
||||
elif path[0] in ('attributes', 'users') and operation != 'retrieve':
|
||||
return InputAttributes(path, inputdata, nodes)
|
||||
elif path == ['boot', 'nextdevice'] and operation != 'retrieve':
|
||||
@ -539,8 +559,6 @@ class InputConfigClear(ConfluentMessage):
|
||||
raise exc.InvalidArgumentException('Input must be {"clear":true}')
|
||||
|
||||
class InputConfigChangeSet(InputExpression):
|
||||
# For now, this is identical to InputExpression, later it may
|
||||
# internalize formula expansion, but not now..
|
||||
def __init__(self, path, inputdata, nodes=None, configmanager=None):
|
||||
self.cfm = configmanager
|
||||
super(InputConfigChangeSet, self).__init__(path, inputdata, nodes)
|
||||
|
@ -161,6 +161,11 @@ def update(nodes, element, configmanager, inputdata):
|
||||
|
||||
|
||||
def update_nodegroup(group, element, configmanager, inputdata):
|
||||
if 'rename' in element:
|
||||
namemap = {}
|
||||
namemap[group] = inputdata.attribs['rename']
|
||||
configmanager.rename_nodegroups(namemap)
|
||||
return yield_rename_resources(namemap, isnode=False)
|
||||
try:
|
||||
clearattribs = []
|
||||
for attrib in inputdata.attribs.iterkeys():
|
||||
@ -200,12 +205,26 @@ def create(nodes, element, configmanager, inputdata):
|
||||
if nodes is not None and element[-1] == 'expression':
|
||||
return _expand_expression(nodes, configmanager, inputdata)
|
||||
|
||||
def yield_rename_resources(namemap, isnode):
|
||||
for node in namemap:
|
||||
if isnode:
|
||||
yield msg.RenamedNode(node, namemap[node])
|
||||
else:
|
||||
yield msg.RenamedResource(node, namemap[node])
|
||||
|
||||
def update_nodes(nodes, element, configmanager, inputdata):
|
||||
updatedict = {}
|
||||
if not nodes:
|
||||
raise exc.InvalidArgumentException(
|
||||
'No action to take, noderange is empty (if trying to define '
|
||||
'group attributes, use nodegroupattrib)')
|
||||
if 'rename' in element:
|
||||
namemap = {}
|
||||
for node in nodes:
|
||||
rename = inputdata.get_attributes(node)
|
||||
namemap[node] = rename['rename']
|
||||
configmanager.rename_nodes(namemap)
|
||||
return yield_rename_resources(namemap, isnode=True)
|
||||
for node in nodes:
|
||||
updatenode = inputdata.get_attributes(node, allattributes.node)
|
||||
clearattribs = []
|
||||
|
Loading…
x
Reference in New Issue
Block a user