2
0
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:
Jarrod Johnson 2019-03-01 15:27:40 -05:00
commit 5481da269e
8 changed files with 264 additions and 10 deletions

View 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()

View 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))

View File

@ -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',

View File

@ -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):

View File

@ -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'}),
},

View File

@ -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]:

View File

@ -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)

View File

@ -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 = []