mirror of
https://github.com/xcat2/confluent.git
synced 2026-01-11 02:22:31 +00:00
Add deployment lock mechanism
This allows users to opt into disabling setting further profile changes. Nodes may be 'unlocked' (normal), 'autolock' (will lock on next completion), or 'locked' (unable to change the pending OS profile)
This commit is contained in:
@@ -117,6 +117,16 @@ def main(args):
|
||||
else:
|
||||
sys.stderr.write('No deployment profiles available, try osdeploy import or imgutil capture\n')
|
||||
sys.exit(1)
|
||||
lockednodes = []
|
||||
for lockinfo in c.read('/noderange/{0}/deployment/lock'.format(args.noderange)):
|
||||
for node in lockinfo.get('databynode', {}):
|
||||
lockstate = lockinfo['databynode'][node]['lock']['value']
|
||||
if lockstate == 'locked':
|
||||
lockednodes.append(node)
|
||||
if lockednodes:
|
||||
sys.stderr.write('Requested noderange has nodes with locked deployment: ' + ','.join(lockednodes))
|
||||
sys.stderr.write('\n')
|
||||
sys.exit(1)
|
||||
armonce(args.noderange, c)
|
||||
setpending(args.noderange, args.profile, c)
|
||||
else:
|
||||
|
||||
@@ -215,6 +215,13 @@ node = {
|
||||
'Using this requires that collective members be '
|
||||
'defined as nodes for noderange expansion')
|
||||
},
|
||||
'deployment.lock': {
|
||||
'description': ('Indicates whether deployment actions should be impeded. '
|
||||
'If locked, it indicates that a pending profile should not be applied. '
|
||||
'If "autolock", then locked will be set when current pending deployment completes. '
|
||||
),
|
||||
'validlist': ('autolock', 'locked')
|
||||
},
|
||||
'deployment.pendingprofile': {
|
||||
'description': ('An OS profile that is pending deployment. This indicates to '
|
||||
'the network boot subsystem what should be offered when a potential '
|
||||
|
||||
@@ -453,6 +453,9 @@ def _init_core():
|
||||
'default': 'ipmi',
|
||||
}),
|
||||
'deployment': {
|
||||
'lock': PluginRoute({
|
||||
'handler': 'attributes'
|
||||
}),
|
||||
'ident_image': PluginRoute({
|
||||
'handler': 'identimage'
|
||||
})
|
||||
|
||||
@@ -574,6 +574,8 @@ def get_input_message(path, operation, inputdata, nodes=None, multinode=False,
|
||||
elif '/'.join(path).startswith(
|
||||
'configuration/management_controller/licenses') and inputdata:
|
||||
return InputLicense(path, nodes, inputdata, configmanager)
|
||||
elif path == ['deployment', 'lock'] and inputdata:
|
||||
return InputDeploymentLock(path, nodes, inputdata)
|
||||
elif path == ['deployment', 'ident_image']:
|
||||
return InputIdentImage(path, nodes, inputdata)
|
||||
elif path == ['console', 'ikvm']:
|
||||
@@ -957,6 +959,18 @@ class InputIdentImage(ConfluentInputMessage):
|
||||
keyname = 'ident_image'
|
||||
valid_values = ['create']
|
||||
|
||||
class InputDeploymentLock(ConfluentInputMessage):
|
||||
keyname = 'lock'
|
||||
valid_values = ['autolock', 'unlocked', 'locked']
|
||||
|
||||
class DeploymentLock(ConfluentChoiceMessage):
|
||||
valid_values = set([
|
||||
'autolock',
|
||||
'locked',
|
||||
'unlocked',
|
||||
])
|
||||
keyname = 'lock'
|
||||
|
||||
class InputIkvmParams(ConfluentInputMessage):
|
||||
keyname = 'method'
|
||||
valid_values = ['unix', 'wss', 'url']
|
||||
|
||||
@@ -109,6 +109,13 @@ def retrieve_nodegroup(nodegroup, element, configmanager, inputdata, clearwarnby
|
||||
|
||||
def retrieve_nodes(nodes, element, configmanager, inputdata, clearwarnbynode):
|
||||
attributes = configmanager.get_node_attributes(nodes)
|
||||
if element[-1] == 'lock':
|
||||
for node in nodes:
|
||||
lockstate = attributes.get(node, {}).get('deployment.lock', {}).get('value', None)
|
||||
if lockstate not in ('locked', 'autolock'):
|
||||
lockstate = 'unlocked'
|
||||
yield msg.DeploymentLock(node, lockstate)
|
||||
return
|
||||
if element[-1] == 'all':
|
||||
for node in util.natural_sort(nodes):
|
||||
if clearwarnbynode and node in clearwarnbynode:
|
||||
@@ -247,12 +254,20 @@ def yield_rename_resources(namemap, isnode):
|
||||
else:
|
||||
yield msg.RenamedResource(node, namemap[node])
|
||||
|
||||
def update_locks(nodes, configmanager, inputdata):
|
||||
for node in nodes:
|
||||
updatestate = inputdata.inputbynode[node]
|
||||
configmanager.set_node_attributes({node: {'deployment.lock': updatestate}})
|
||||
yield msg.DeploymentLock(node, updatestate)
|
||||
|
||||
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 element[-1] == 'lock':
|
||||
return update_locks(nodes, configmanager, inputdata)
|
||||
if element[-1] == 'check':
|
||||
for node in nodes:
|
||||
check = inputdata.get_attributes(node, allattributes.node)
|
||||
@@ -273,6 +288,15 @@ def update_nodes(nodes, element, configmanager, inputdata):
|
||||
configmanager.rename_nodes(namemap)
|
||||
return yield_rename_resources(namemap, isnode=True)
|
||||
clearwarnbynode = {}
|
||||
for node in nodes:
|
||||
updatenode = inputdata.get_attributes(node, allattributes.node)
|
||||
if updatenode and 'deployment.lock' in updatenode:
|
||||
raise exc.InvalidArgumentException('Deployment lock must be manipulated by {node}/deployment/lock api')
|
||||
if updatenode and ('deployment.pendingprofile' in updatenode or 'deployment.apiarmed' in updatenode):
|
||||
lockcheck = configmanager.get_node_attributes(node, 'deployment.lock')
|
||||
lockstate = lockcheck.get(node, {}).get('deployment.lock', {}).get('value', None)
|
||||
if lockstate == 'locked':
|
||||
raise exc.InvalidArgumentException('Request to set deployment for a node that has locked deployment')
|
||||
for node in nodes:
|
||||
updatenode = inputdata.get_attributes(node, allattributes.node)
|
||||
clearattribs = []
|
||||
|
||||
@@ -490,6 +490,10 @@ def handle_request(env, start_response):
|
||||
updates['deployment.pendingprofile'] = {'value': ''}
|
||||
if targattr == 'deployment.profile':
|
||||
updates['deployment.stagedprofile'] = {'value': ''}
|
||||
dls = cfg.get_node_attributes(nodename, 'deployment.lock')
|
||||
dls = dls.get(nodename, {}).get('deployment.lock', {}).get('value', None)
|
||||
if dls == 'autolock':
|
||||
updates['deployment.lock'] = 'locked'
|
||||
currprof = currattr.get(targattr, {}).get('value', '')
|
||||
if currprof != pending:
|
||||
updates[targattr] = {'value': pending}
|
||||
|
||||
Reference in New Issue
Block a user