From: rmccabe@sourceware.org <rmccabe@sourceware.org>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] conga/luci/site/luci/Extensions LuciValidation.py
Date: 12 Dec 2007 15:43:15 -0000 [thread overview]
Message-ID: <20071212154315.848.qmail@sourceware.org> (raw)
CVSROOT: /cvs/cluster
Module name: conga
Changes by: rmccabe at sourceware.org 2007-12-12 15:43:15
Added files:
luci/site/luci/Extensions: LuciValidation.py
Log message:
Separate out cluster form post validation to allow async validation
Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/LuciValidation.py.diff?cvsroot=cluster&r1=NONE&r2=1.1
/cvs/cluster/conga/luci/site/luci/Extensions/LuciValidation.py,v --> standard output
revision 1.1
--- conga/luci/site/luci/Extensions/LuciValidation.py
+++ - 2007-12-12 15:43:15.733027000 +0000
@@ -0,0 +1,1185 @@
+# Copyright (C) 2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute
+# it and/or modify it under the terms of version 2 of the
+# GNU General Public License as published by the
+# Free Software Foundation.
+
+from ClusterModel.RefObject import RefObject
+from ClusterModel.Service import Service
+from ClusterModel.Method import Method
+from ClusterModel.Fence import Fence
+from ClusterModel.FailoverDomain import FailoverDomain
+from ClusterModel.FailoverDomainNode import FailoverDomainNode
+from ClusterModel.QuorumD import QuorumD
+from ClusterModel.Heuristic import Heuristic
+from ClusterModel.FenceXVMd import FenceXVMd
+from ClusterModel.Lockserver import Lockserver
+from ClusterModel.Vm import Vm
+
+from conga_constants import LUCI_DEBUG_MODE, FDOM, FDOM_ADD, SERVICE_CONFIG, SERVICE_ADD, VM_CONFIG, VM_ADD
+from FenceHandler import validateFenceDevice, validateNewFenceDevice, validate_fenceinstance, FD_VAL_SUCCESS
+
+from LuciSyslog import get_logger
+from xml.dom import minidom
+from ResourceHandler import create_resource
+from LuciZope import GetReqVars
+
+luci_log = get_logger()
+
+def validate_node_fence_config(model, request):
+ errors = list()
+
+ fvar = GetReqVars(request,
+ [ 'fence_xml', 'fence_level', 'nodename', 'clustername' ])
+
+ if fvar['fence_xml'] is None:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC0: no fence_xml for node %s' \
+ % fvar['nodename'])
+ return (False, {'errors': ['No fence data was supplied']})
+
+ if fvar['fence_level'] is None:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC1: no fence level for %s' \
+ % fvar['nodename'])
+ return (False, {'errors': ['No fence level was supplied']})
+
+ try:
+ fence_level = int(fvar['fence_level'])
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC2: invalid fence level: %s: %r %s' \
+ % (fvar['fence_level'], e, str(e)))
+ return (False, {'errors': ['"%s" is an invalid fence level' % fvar['fence_level'] ]})
+
+ nodename = fvar['nodename']
+ if nodename is None:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC3: no nodename: %r %s' % (e, str(e)))
+ return (False, {'errors': ['No node name was given']})
+
+ clustername = fvar['clustername']
+ if clustername is None:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC4: no clustername: %r %s' % (e, str(e)))
+ return (False, {'errors': ['No cluster name was given']})
+
+ try:
+ doc = minidom.parseString(fvar['fence_xml'])
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC7: error: %r %s' % (e, str(e)))
+ return (False, {'errors': ['The fence data submitted is not properly formed']})
+
+ try:
+ node = model.retrieveNodeByName(nodename)
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC8: unable to find node name %s in current node list: %r %s' % (nodename, e, str(e)))
+ return (False, {'errors': ['Unable to find the cluster node %s in the node list' % nodename ]})
+
+ levels = node.getFenceLevels()
+ try:
+ method_id = levels[fence_level - 1].getAttribute('name')
+ if not method_id:
+ raise Exception, 'No method ID'
+ fence_method = Method()
+ fence_method.addAttribute('name', str(method_id))
+ levels[fence_level - 1] = fence_method
+ except Exception, e:
+ method_id = fence_level
+ fence_method = Method()
+ fence_method.addAttribute('name', str(method_id))
+
+ forms = doc.getElementsByTagName('form')
+ if len(forms) < 1:
+ delete_target = None
+ for l in levels:
+ # delete the fence level
+ if l.getAttribute('name') == method_id:
+ delete_target = l
+ break
+ if delete_target is not None:
+ try:
+ node.getChildren()[0].removeChild(delete_target)
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC9: %s: %r %s' \
+ % (method_id, e, str(e)))
+ return (False, {'errors': ['An error occurred while deleting fence method %s' % method_id ]})
+ else:
+ return (True, {'messages': ['No changes were made'] })
+
+ form_hash = {}
+ for i in forms:
+ form_id = i.getAttribute('id')
+ if not form_id:
+ continue
+ ielems = i.getElementsByTagName('input')
+ if not ielems or len(ielems) < 1:
+ continue
+
+ dummy_form = {}
+
+ for i in ielems:
+ try:
+ input_type = str(i.getAttribute('type'))
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC10: input type: %r %s' \
+ % (e, str(e)))
+ continue
+
+ if not input_type or input_type == 'button':
+ continue
+
+ try:
+ dummy_form[str(i.getAttribute('name'))] = str(i.getAttribute('value'))
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC11: parsing XML: %r %s' \
+ % (e, str(e)))
+
+ if len(dummy_form) < 1:
+ continue
+
+ if dummy_form.has_key('fence_instance'):
+ try:
+ parent = dummy_form['parent_fencedev']
+ except:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC12: no parent for instance')
+ return (False, {'errors': [ 'Unable to determine what device the current instance uses' ]})
+
+ try:
+ form_hash[parent][1].append(dummy_form)
+ del dummy_form['fence_instance']
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC13: no parent for instance')
+ return (False, {'errors': [ 'Unable to determine what device the current instance uses' ]})
+ else:
+ form_hash[form_id] = (dummy_form, list())
+
+ fh_keys = form_hash.keys()
+ fh_keys.sort()
+ for i in fh_keys:
+ fencedev_name = None
+ fencedev_unknown = False
+
+ try:
+ fence_form, instance_list = form_hash[i]
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC14: %r %s' % (e, str(e)))
+ continue
+
+ try:
+ fence_type = fence_form['fence_type']
+ if not fence_type:
+ raise Exception, 'fence type is blank'
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vNFC15: %s: %r %s' % (i, e, str(e)))
+ fence_type = None
+
+ if fence_form.has_key('existing_device'):
+ try:
+ fencedev_name = fence_form['name']
+ if not fencedev_name.strip():
+ raise Exception, 'no fence name'
+ except Exception, e:
+ errors.append('You must provide a unique name for all fence devices')
+ continue
+
+ if fence_type is None:
+ # An unknown fence device agent. Pull the data out of
+ # the model and persist it and all instances.
+ # All we care about is its name.
+ fencedev_unknown = True
+ else:
+ if not fence_form.has_key('sharable'):
+ # If it's a shared fence device that already exists, the
+ # user could not have edited it (without playing dirty
+ # games), so it's safe to pull the existing entry from
+ # the model. All we need is the device name, and nothing
+ # else needs to be done here.
+ #
+ # For an existing non-shared device update the device
+ # in the model, since the user could have edited it.
+ retcode, retmsg = validateFenceDevice(fence_form, model)
+ if retcode != FD_VAL_SUCCESS:
+ errors.extend(retmsg)
+ continue
+ else:
+ fencedev_name = retmsg
+
+ # Add back the tags under the method block
+ # for the fence instance
+ if type == 'fence_manual':
+ instance_list.append({'name': fencedev_name, 'nodename': nodename })
+ else:
+ instance_list.append({'name': fencedev_name })
+ else:
+ # The user created a new fence device.
+ retcode, retmsg = validateNewFenceDevice(fence_form, model)
+ if retcode != FD_VAL_SUCCESS:
+ errors.extend(retmsg)
+ continue
+ else:
+ fencedev_name = retmsg
+
+ # If it's not shared, we need to create an instance form
+ # so the appropriate XML goes into the <method> block inside
+ # <node><fence>. All we need for that is the device name.
+ if not fence_form.has_key('sharable'):
+ if type == 'fence_manual':
+ instance_list.append({'name': fencedev_name, 'nodename': nodename })
+ else:
+ instance_list.append({'name': fencedev_name })
+
+ if fencedev_unknown is True:
+ # Save any instances for this fence device.
+ # XXX FIX ME - instances must be saved.
+ pass
+
+ for inst in instance_list:
+ retcode, retobj = validate_fenceinstance(inst, fencedev_name, fence_type)
+ if retcode != FD_VAL_SUCCESS:
+ errors.extend(retobj)
+ continue
+ fence_method.addChild(retobj)
+
+ if len(node.getChildren()) > 0:
+ # There's already a <fence> block
+ found_target = False
+ for idx in xrange(len(levels)):
+ if levels[idx].getAttribute('name') == method_id:
+ found_target = True
+ break
+
+ if found_target is False:
+ # There's a fence block, but no relevant method
+ # block
+ node.getChildren()[0].addChild(fence_method)
+ else:
+ # There is no <fence> tag under the node yet.
+ fence_node = Fence()
+ fence_node.addChild(fence_method)
+ node.addChild(fence_node)
+
+ if len(errors) > 0:
+ return (False, {'errors': errors })
+ return (True, {})
+
+def validate_clusvc_add(model, request):
+ errors = list()
+ fvar = GetReqVars(request, [ 'form_xml', 'domain', 'recovery', 'svc_name', 'action' ])
+
+ form_xml = fvar['form_xml']
+ if form_xml is None:
+ form_xml = ''
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA0: no form_xml')
+
+ forms = []
+ if form_xml.strip():
+ try:
+ doc = minidom.parseString(form_xml)
+ forms = doc.getElementsByTagName('form')
+ if len(forms) < 1:
+ raise Exception, 'invalid XML'
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA1: error: %r %s: %r' % (e, str(e), form_xml))
+ return (False, { 'errors': [ 'The resource data submitted for this service is not properly formed' ]})
+
+ form_hash = {}
+ form_hash['toplevel'] = { 'form': None, 'kids': [] }
+ for i in forms:
+ form_id = i.getAttribute('id')
+ form_parent = i.getAttribute('parent')
+ if not form_id or not form_parent:
+ continue
+ ielems = i.getElementsByTagName('input')
+ if not ielems or len(ielems) < 1:
+ continue
+ if not form_id in form_hash:
+ form_hash[form_id] = {'form': i, 'kids': []}
+ elif not form_hash[form_id]['form']:
+ form_hash[form_id]['form'] = i
+ if not form_parent in form_hash:
+ form_hash[form_parent] = {'form': None, 'kids': []}
+ form_hash[form_parent]['kids'].append(form_id)
+ dummy_form = {}
+
+ for i in ielems:
+ try:
+ input_type = str(i.getAttribute('type'))
+ except:
+ continue
+ if not input_type or input_type == 'button':
+ continue
+ try:
+ dummy_form[str(i.getAttribute('name'))] = str(i.getAttribute('value'))
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA2: parsing XML: %r %s' \
+ % (e, str(e)))
+
+ try:
+ res_type = dummy_form['type'].strip()
+ if not res_type:
+ raise Exception, 'no resource type'
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA3: %r %s' % (e, str(e)))
+ return (False, { 'errors': [ 'No resource type was specified' ]})
+
+ try:
+ if res_type == 'ip':
+ dummy_form['resourceName'] = dummy_form['ip_address']
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA3a: type is ip but no addr: %r %s' \
+ % (e, str(e)))
+ return (False, { 'errors': [ 'No IP address was given' ]})
+
+ try:
+ if dummy_form.has_key('immutable'):
+ newRes = model.getResourceByName(dummy_form['resourceName'])
+ resObj = RefObject(newRes)
+ resObj.setRef(newRes.getName())
+ else:
+ resObj = create_resource(res_type, dummy_form, model)
+ except Exception, e:
+ resObj = None
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA4: type %s: %r %s' \
+ % (res_type, e, str(e)))
+
+ if resObj is None:
+ return (False, { 'errors': [ 'An error occurred while adding %s' % res_type ]})
+
+ if dummy_form.has_key('__independent_subtree'):
+ resObj.addAttribute('__independent_subtree', '1')
+ else:
+ resObj.removeAttribute('__independent_subtree')
+ form_hash[form_id]['obj'] = resObj
+
+ if len(errors) > 0:
+ return (False, {'errors': errors})
+
+ fdom = fvar['domain']
+
+ recovery = fvar['recovery']
+ if recovery is not None and recovery != 'restart' and recovery != 'relocate' and recovery != 'disable':
+ errors.append('You entered an invalid recovery option: "%s" Valid options are "restart" "relocate" and "disable."')
+
+ service_name = fvar['svc_name']
+ if service_name is None:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA5: no service name')
+ errors.append('No service name was given')
+
+ autostart = '1'
+ try:
+ if not request.form.has_key('autostart') or request.form['autostart'] == '0':
+ autostart = '0'
+ except Exception, e:
+ autostart = None
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA5a: error getting autostart: %r %s' \
+ % (e, str(e)))
+
+ exclusive = '0'
+ try:
+ if not request.form.has_key('exclusive') or request.form['exclusive'] != '1':
+ exclusive = '0'
+ else:
+ exclusive = '1'
+ except Exception, e:
+ exclusive = '0'
+
+ try:
+ cur_service = model.retrieveServiceByName(service_name)
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA5c: no service named %s found: %r %s' \
+ % (service_name, e, str(e)))
+ cur_service = None
+
+ action = fvar['action']
+ if action is None:
+ return (False, {'errors': [ 'No action was given for service %s' % service_name ] })
+
+ if action == 'edit':
+ if cur_service is None:
+ return (False, {'errors': [ 'The service %s could not be found for editing' % service_name ]})
+ model.deleteService(service_name)
+ elif action == 'add':
+ if cur_service is not None:
+ return (False, {'errors': [ 'A service with the name %s already exists' % service_name ]})
+ else:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA4a: unknown action %s' \
+ % request.form['action'])
+ return (False, {'errors': [ 'An unknown action was specified' ]})
+
+ def buildSvcTree(parent, child_id_list):
+ for i in child_id_list:
+ try:
+ child = form_hash[i]['obj']
+ if not child:
+ raise Exception, 'No object for %s' % i
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('bST0: %r %s' % (e, str(e)))
+ continue
+ parent.addChild(child)
+ if 'kids' in form_hash[i]:
+ buildSvcTree(child, form_hash[i]['kids'])
+
+ new_service = Service()
+ new_service.addAttribute('name', service_name)
+ if fdom:
+ new_service.addAttribute('domain', fdom)
+ if recovery:
+ new_service.addAttribute('recovery', recovery)
+ new_service.addAttribute('exclusive', str(exclusive))
+ if autostart is not None:
+ new_service.attr_hash['autostart'] = autostart
+
+ buildSvcTree(new_service, form_hash['toplevel']['kids'])
+ model.resourcemanager_ptr.addChild(new_service)
+ model.setModified(True)
+
+ if action == 'edit':
+ action_type = SERVICE_CONFIG
+ action_msg = 'Configuring service "%s"' % service_name
+ else:
+ action_type = SERVICE_ADD
+ action_msg = 'Creating service "%s"' % service_name
+
+ return (True, { 'action_type': action_type, 'action_msg': action_msg })
+
+def validate_clures_add(model, request):
+ fvar = GetReqVars(request, [ 'type' ])
+
+ res_type = fvar['type']
+ if res_type is None:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('VRA0: type is blank')
+ return (False, { 'errors': [ 'No resource type was given']})
+
+ try:
+ res = create_resource(res_type, request.form, model)
+ except Exception, e:
+ return (False, { 'errors': e } )
+
+ resname = ''
+ try:
+ resname = res.getName()
+ model.getResourcesPtr().addChild(res)
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('EditResource0: %r %s' % (e, str(e)))
+ return (False, { 'errors': [ 'Error configuring resource %s %s: ' % (resname, str(e)) ] })
+ return (True, { 'res_name': resname })
+
+def validate_fdom(model, request):
+ errors = list()
+ fvar = GetReqVars(request, [ 'clustername', 'name', 'oldname' ])
+
+ name = fvar['name']
+ if name is None:
+ errors.append('No name was given for this failover domain')
+
+ prioritized = False
+ try:
+ prioritized = request.form.has_key('prioritized')
+ except:
+ prioritized = False
+
+ restricted = False
+ try:
+ restricted = request.form.has_key('restricted')
+ except:
+ restricted = False
+
+ nofailback = False
+ try:
+ nofailback = request.form.has_key('nofailback')
+ except:
+ nofailback = False
+
+ oldname = fvar['oldname']
+
+ if oldname is None or oldname != name:
+ if model.getFailoverDomainByName(name) is not None:
+ errors.append('A failover domain named "%s" already exists' % name)
+
+ fdom = None
+ if oldname is not None:
+ fdom = model.getFailoverDomainByName(oldname)
+ if fdom is None:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('validateFdom1: No fdom named %s exists' % oldname)
+ errors.append('No failover domain named "%s" exists' % oldname)
+ else:
+ fdom.addAttribute('name', name)
+ fdom.children = list()
+ else:
+ fdom = FailoverDomain()
+ fdom.addAttribute('name', name)
+
+ if fdom is None or len(errors) > 0:
+ return (False, {'errors': errors })
+
+ if prioritized:
+ fdom.addAttribute('ordered', '1')
+ else:
+ fdom.addAttribute('ordered', '0')
+
+ if restricted:
+ fdom.addAttribute('restricted', '1')
+ else:
+ fdom.addAttribute('restricted', '0')
+
+ if nofailback:
+ fdom.addAttribute('nofailback', '1')
+ else:
+ fdom.addAttribute('nofailback', '0')
+
+ for i in model.getNodeNames():
+ if request.form.has_key(i):
+ fdn = FailoverDomainNode()
+ fdn.addAttribute('name', i)
+ if prioritized:
+ priority = 1
+ try:
+ priority = int(request.form['__PRIORITY__%s' % i].strip())
+ if priority < 1:
+ priority = 1
+ except Exception, e:
+ priority = 1
+ fdn.addAttribute('priority', str(priority))
+ fdom.addChild(fdn)
+
+ try:
+ fdom_ptr = model.getFailoverDomainPtr()
+ if not oldname:
+ fdom_ptr.addChild(fdom)
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('validateFdom2: %r %s' % (e, str(e)))
+ errors.append('Unable to update the cluster configuration')
+
+ if len(errors) > 0:
+ return (False, { 'errors': errors })
+
+ if oldname:
+ action = FDOM
+ status_msg = 'Updating failover domain "%s"' % oldname
+ else:
+ action = FDOM_ADD
+ status_msg = 'Creating failover domain "%s"' % name
+
+ return (True, { 'msg': status_msg, 'action': action })
+
+def validate_config_mcast(model, form):
+ gulm_ptr = model.getGULMPtr()
+ if gulm_ptr:
+ return (False, { 'errors': ['Multicast cannot be used with GULM locking']})
+ errors = list()
+ try:
+ mcast_val = form['mcast'].strip().lower()
+ if mcast_val != 'true' and mcast_val != 'false':
+ raise KeyError, mcast_val
+ if mcast_val == 'true':
+ mcast_manual = True
+ else:
+ mcast_manual = False
+ except KeyError, e:
+ errors.append('An invalid multicast selection was made')
+ return (False, {'errors': errors})
+
+ mcast_interface = None
+ if form.has_key('mcast_interface'):
+ mcast_interface = form['mcast_interface'].strip()
+
+ if mcast_manual is True and form.has_key('cluster_version') and form['cluster_version'].strip() == 'rhel4' and not mcast_interface:
+ errors.append('No multicast interface was specified')
+ return (False, {'errors': errors})
+
+ if mcast_manual is True:
+ import socket
+ try:
+ addr_str = form['mcast_address'].strip()
+ socket.inet_pton(socket.AF_INET, addr_str)
+ except KeyError, e:
+ addr_str = None
+ errors.append('No multicast address was given')
+ except socket.error, e:
+ try:
+ socket.inet_pton(socket.AF_INET6, addr_str)
+ except socket.error, e:
+ addr_str = None
+ errors.append('An invalid multicast address was given: %s')
+ else:
+ addr_str = None
+
+ try:
+ if not addr_str:
+ if mcast_interface:
+ errors.append('A multicast interface was specified, but no multicast address was given')
+ return (False, {'errors': errors})
+ model.del_cluster_multicast()
+ else:
+ model.set_cluster_multicast(addr_str, mcast_if=mcast_interface)
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug('Error updating mcast properties: %r %s' \
+ % (e, str(e)))
+ errors.append('Unable to update cluster multicast properties')
+
+ if len(errors) > 0:
+ return (False, {'errors': errors})
+
+ return (True, {})
+
+def validate_config_qdisk(model, form):
+ errors = list()
+
+ gulm_ptr = model.getGULMPtr()
+ if gulm_ptr is not None:
+ return (False, { 'errors': ['Quorum disk cannot be used with GULM locking']})
+
+ try:
+ qdisk_val = form['quorumd'].strip().lower()
+ if qdisk_val != 'true' and qdisk_val != 'false':
+ raise KeyError(qdisk_val)
+ if qdisk_val == 'true':
+ qdisk_val = 1
+ else:
+ qdisk_val = 0
+ except KeyError, e:
+ return (False, {'errors': ['An invalid quorum partition selection was made']})
+
+ cp = model.getClusterPtr()
+ qdp = model.getQuorumdPtr()
+
+ if not qdisk_val:
+ if qdp:
+ try:
+ cp.removeChild(qdp)
+ except Exception, e:
+ return (False, {'errors': [ 'Error disabling quorum partition: %s' % str(e) ] })
+ return (True, {})
+
+ try:
+ interval = int(form['interval'])
+ if interval < 0:
+ raise ValueError, 'Interval must be 0 or greater'
+ except KeyError, e:
+ errors.append('No Interval value was given')
+ except ValueError, e:
+ errors.append('An invalid Interval value was given: %s' % str(e))
+
+ try:
+ votes = int(form['votes'])
+ if votes < 1:
+ raise ValueError, 'Votes must be greater than 0'
+ except KeyError, e:
+ errors.append('No Votes value was given')
+ except ValueError, e:
+ errors.append('An invalid Votes value was given: %s' % str(e))
+
+ try:
+ tko = int(form['tko'])
+ if tko < 0:
+ raise ValueError, 'TKO must be 0 or greater'
+ except KeyError, e:
+ errors.append('No TKO value was given')
+ except ValueError, e:
+ errors.append('An invalid TKO value was given: %s' % str(e))
+
+ try:
+ min_score = int(form['min_score'])
+ if min_score < 1:
+ raise ValueError('Minimum Score must be greater than 0')
+ except KeyError, e:
+ errors.append('No Minimum Score value was given')
+ except ValueError, e:
+ errors.append('An invalid Minimum Score value was given: %s' % str(e))
+
+ # Either device or label must be present
+ device = None
+ try:
+ device = form['device'].strip()
+ except:
+ device = None
+
+ label = None
+ try:
+ label = form['label'].strip()
+ except:
+ label = None
+
+ if not device and not label:
+ errors.append('No Device or Label value was given')
+
+ num_heuristics = 0
+ try:
+ num_heuristics = int(form['num_heuristics']) + 1
+ if num_heuristics < 1:
+ raise ValueError, form['num_heuristics']
+ except KeyError, e:
+ errors.append('No number of heuristics was given')
+ except ValueError, e:
+ errors.append('An invalid number of heuristics was given: %s' % str(e))
+
+ heuristics = list()
+ for i in xrange(num_heuristics):
+ try:
+ h = form['heuristic%d' % i]
+ if not h or len(h) != 3 or not (h[0].strip() and h[1].strip() and h[2].strip()):
+ continue
+ except:
+ continue
+
+ try:
+ hprog = h[0]
+ if not hprog:
+ raise Exception, 'no hprog'
+ except Exception, e:
+ errors.append('No program was given for heuristic %d' % (i + 1))
+ try:
+ hint = int(h[1])
+ if hint < 1:
+ raise ValueError, 'Heuristic interval values must be greater than 0'
+ except KeyError, e:
+ errors.append('No interval was given for heuristic %d' % (i + 1))
+ except ValueError, e:
+ errors.append('An invalid interval was given for heuristic %d: %s' \
+ % ((i + 1), str(e)))
+
+ try:
+ hscore = int(h[2])
+ if hscore < 1:
+ raise ValueError, 'Heuristic scores must be greater than 0'
+ except KeyError, e:
+ errors.append('No score was given for heuristic %d' % (i + 1))
+ except ValueError, e:
+ errors.append('An invalid score was given for heuristic %d: %s' \
+ % ((i + 1), str(e)))
+
+ heuristics.append([ hprog, hint, hscore ])
+
+ if len(errors) > 0:
+ return (False, {'errors': errors })
+
+ qd = QuorumD()
+ qd.addAttribute('interval', str(interval))
+ qd.addAttribute('votes', str(votes))
+ qd.addAttribute('tko', str(tko))
+ qd.addAttribute('min_score', str(min_score))
+
+ if device:
+ qd.addAttribute('device', str(device))
+ else:
+ qd.addAttribute('label', str(label))
+
+ if qdp:
+ try:
+ cp.removeChild(qdp)
+ except:
+ pass
+ cp.addChild(qd)
+
+ for h in heuristics:
+ new_h = Heuristic()
+ new_h.addAttribute('program', str(h[0]))
+ new_h.addAttribute('interval', str(h[1]))
+ new_h.addAttribute('score', str(h[2]))
+ qd.addChild(new_h)
+
+ if len(errors) > 0:
+ return (False, {'errors': errors })
+
+ return (True, {})
+
+def validate_config_fence(model, form):
+ errors = list()
+
+ if model.getGULMPtr() is not None:
+ return (False, {'errors': [ 'GULM clusters do not support fenced' ]})
+
+ try:
+ post_fail_delay = int(form['post_fail_delay'])
+ if post_fail_delay < 0:
+ raise ValueError('post fail delay values must be 0 or greater')
+ except KeyError, e:
+ errors.append('No post fail delay was given')
+ except ValueError, e:
+ errors.append('Invalid post fail delay: %s' % str(e))
+
+ try:
+ post_join_delay = int(form['post_join_delay'])
+ if post_join_delay < 0:
+ raise ValueError('post join delay values must be 0 or greater')
+ except KeyError, e:
+ errors.append('No post join delay was given')
+ except ValueError, e:
+ errors.append('Invalid post join delay: %s' % str(e))
+
+ run_xvmd = form.has_key('run_xvmd')
+
+ if run_xvmd is True and not model.hasFenceXVM():
+ fenceXVMd = FenceXVMd()
+ model.addFenceXVM(fenceXVMd)
+ elif not run_xvmd:
+ model.delFenceXVM()
+
+ try:
+ fd = model.getFenceDaemonPtr()
+ old_pj_delay = fd.getPostJoinDelay()
+ old_pf_delay = fd.getPostFailDelay()
+
+ if post_join_delay == old_pj_delay and post_fail_delay == old_pf_delay:
+ errors.append('No fence daemon properties were changed')
+ else:
+ fd.setPostJoinDelay(str(post_join_delay))
+ fd.setPostFailDelay(str(post_fail_delay))
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('Unable to update fence daemon properties: %r %s' % (e, str(e)))
+ errors.append('An error occurred while attempting to update fence daemon properties: %s' % str(e))
+
+ if len(errors) > 0:
+ return (False, {'errors': errors })
+
+ return (True, {})
+
+def validate_config_gulm(model, form):
+ gulm_ptr = model.getGULMPtr()
+ if not gulm_ptr:
+ return (False, {'errors': [ 'This cluster is not using GULM locking' ]})
+
+ node_list = map(lambda x: x.getName(), gulm_ptr.getChildren())
+ for i in model.getNodeNames():
+ if not i in node_list:
+ node_list.append(i)
+
+ gulm_lockservers = list()
+ for node in node_list:
+ if form.has_key(node) and form[node] == 'on':
+ ls = Lockserver()
+ ls.addAttribute('name', node)
+ gulm_lockservers.append(ls)
+
+ try:
+ xlockservers = filter(lambda x: x.strip(), form['__GULM__'])
+ except:
+ xlockservers = list()
+
+ for i in xlockservers:
+ if not i in node_list:
+ ls = Lockserver()
+ ls.addAttribute('name', i)
+ gulm_lockservers.append(ls)
+
+ num_ls = len(gulm_lockservers)
+ if not num_ls in (1, 3, 5):
+ return (False, {'errors': [ 'You must have exactly 1, 3, or 5 GULM lock servers. You submitted %d lock servers' % num_ls ]})
+
+ model.GULM_ptr.children = gulm_lockservers
+ return (True, {})
+
+def validate_config_general(model, form):
+ errors = list()
+
+ try:
+ cp = model.getClusterPtr()
+ old_name = model.getClusterAlias()
+ old_ver = int(cp.getConfigVersion())
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('getConfigVersion: %s' % str(e))
+ errors.append('unable to determine the current configuration version')
+ return (False, {'errors': errors})
+
+ try:
+ cluster_name = form['cluname'].strip()
+ if not cluster_name:
+ raise KeyError('cluname')
+ except KeyError, e:
+ errors.append('No cluster name was given')
+
+ if len(cluster_name) > 15:
+ errors.append('A cluster\'s name must be less than 16 characters long')
+
+ try:
+ version_num = int(form['cfgver'])
+ if version_num < old_ver:
+ raise ValueError, 'configuration version number must be %d or greater' % old_ver
+ except KeyError, e:
+ errors.append('No cluster configuration version was given')
+ except ValueError, e:
+ errors.append('An invalid configuration version was given: %s' % str(e))
+
+ if len(errors) < 1:
+ try:
+ if cluster_name != old_name:
+ cp.addAttribute('alias', cluster_name)
+ cp.setConfigVersion(str(version_num))
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('unable to update general properties: %r %s' % (e, str(e)))
+ errors.append('Unable to update the cluster configuration')
+
+ try:
+ cluster_version = form['cluster_version'].strip()
+ if cluster_version != 'rhel5':
+ raise Exception, 'not rhel5'
+ except:
+ if len(errors) > 0:
+ return (False, {'errors': errors})
+ return (True, {})
+
+ totem = model.getTotemPtr()
+ if totem is None:
+ totem = model.addTotemPtr()
+
+ try:
+ token = form['token'].strip()
+ if not token:
+ raise KeyError, 'token'
+ token = int(token)
+ if token < 1:
+ raise ValueError, '%d is an invalid value for token timeout' % token
+ totem.addAttribute('token', str(token))
+ except KeyError, e:
+ try:
+ totem.removeAttribute('token')
+ except:
+ pass
+ except Exception, e:
+ errors.append(str(e))
+
+ try:
+ trblc = form['token_retransmits_before_loss_const'].strip()
+ if not trblc:
+ raise KeyError, 'token_retransmits_before_loss_const'
+ trblc = int(trblc)
+ if trblc < 1:
+ raise ValueError, '%d is an invalid value for number of token retransmits before loss' % trblc
+ totem.addAttribute('token_retransmits_before_loss_const', str(trblc))
+ except KeyError, e:
+ try:
+ totem.removeAttribute('token_retransmits_before_loss_const')
+ except:
+ pass
+ except Exception, e:
+ errors.append(str(e))
+
+ try:
+ join = form['join'].strip()
+ if not join:
+ raise KeyError, 'join'
+ join = int(join)
+ if join < 1:
+ raise ValueError, '%d is an invalid value for join timeout' % join
+ totem.addAttribute('join', str(join))
+ except KeyError, e:
+ try:
+ totem.removeAttribute('join')
+ except:
+ pass
+ except Exception, e:
+ errors.append(str(e))
+
+ try:
+ consensus = form['consensus'].strip()
+ if not consensus:
+ raise KeyError, 'consensus'
+ consensus = int(consensus)
+ if consensus < 1:
+ raise ValueError, '%d is an invalid value for consensus timeout' % consensus
+ totem.addAttribute('consensus', str(consensus))
+ except KeyError, e:
+ try:
+ totem.removeAttribute('consensus')
+ except:
+ pass
+ except Exception, e:
+ errors.append(str(e))
+
+ if len(errors) > 0:
+ return (False, {'errors': errors})
+ return (True, {})
+
+def validate_cluster_daemon_form(self, request):
+ errors = list()
+
+ fvar = GetReqVars(request, [ 'nodename' ])
+ nodename = fvar['nodename']
+ if nodename is None:
+ errors.append('Unable to determine the current node name')
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('VDP1: no nodename was given')
+
+ disable_list = list()
+ enable_list = list()
+
+ for i in request.form.items():
+ try:
+ if i[0][:11] == '__daemon__:':
+ daemon_prop = i[1]
+ if len(daemon_prop) == 2:
+ if daemon_prop[1] == '1':
+ disable_list.append(daemon_prop[0])
+ else:
+ if daemon_prop[1] == '0' and daemon_prop[2] == 'on':
+ enable_list.append(daemon_prop[0])
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('VDP3: error: %s: %r %s' \
+ % (str(i), e, str(e)))
+
+ if len(enable_list) < 1 and len(disable_list) < 1:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('VDP4: no changes made')
+ errors.append('No changes to daemon properies were made on node "%s"' \
+ % nodename)
+
+ if len(errors) > 0:
+ return (False, {'errors': errors})
+
+ return (True, { 'enable_list': enable_list, 'disable_list': disable_list })
+
+def validate_vmsvc_form(model, request):
+ errors = list()
+
+ fvar = GetReqVars(request, [ 'vmname', 'oldname', 'vmpath', 'recovery', 'domain', ])
+
+ vm_name = fvar['vmname']
+ if vm_name is None:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('validateVM2: no vm name')
+ errors.append('No virtual machine name was given')
+
+ vm_path = fvar['vmpath']
+ if vm_path is None:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('validateVM3: no vm path')
+ errors.append('No path to the virtual machine configuration directory was given for VM service "%s"' % vm_name)
+
+ autostart = 1
+ if request.form.has_key('autostart'):
+ autostart = 1
+ else:
+ autostart = 0
+
+ exclusive = 0
+ if request.form.has_key('exclusive'):
+ exclusive = 1
+ else:
+ exclusive = 0
+
+ recovery = fvar['recovery']
+ if recovery is not None and recovery != 'restart' and recovery != 'relocate' and recovery != 'disable':
+ errors.append('You entered an invalid recovery option "%s" for VM service "%s". Valid options are "restart" "relocate" and "disable"' % (recovery, vm_name))
+
+ if len(errors) > 0:
+ return (False, {'errors': errors })
+
+ isNew = False
+ old_name = fvar['oldname']
+ if old_name is None:
+ isNew = True
+
+ delete_vm = False
+ if request.form.has_key('delete'):
+ try:
+ xvm = model.retrieveVMsByName(old_name)
+ if not xvm:
+ raise Exception, 'not found'
+ rmptr = model.getResourceManagerPtr()
+ rmptr.removeChild(xvm)
+ delete_vm = True
+ except:
+ return (False, { 'errors': [ 'No virtual machine service named "%s" exists' % old_name ]})
+ else:
+ if isNew is True:
+ xvm = Vm()
+ xvm.addAttribute('name', vm_name)
+ xvm.addAttribute('path', vm_path)
+ rmptr = model.getResourceManagerPtr()
+ rmptr.addChild(xvm)
+ else:
+ try:
+ xvm = model.retrieveVMsByName(old_name)
+ if not xvm:
+ raise Exception, 'not found'
+ except:
+ return (False, { 'errors': [ 'No virtual machine service named "%s" exists' % old_name ]})
+ xvm.addAttribute('name', vm_name)
+ xvm.addAttribute('path', vm_path)
+
+ xvm.addAttribute('autostart', str(autostart))
+ xvm.addAttribute('exclusive', str(exclusive))
+
+ fdom = fvar['domain']
+ if fdom:
+ xvm.addAttribute('domain', fdom)
+ else:
+ try:
+ xvm.removeAttribute('domain')
+ except:
+ pass
+
+ if recovery:
+ xvm.addAttribute('recovery', recovery)
+ else:
+ try:
+ xvm.removeAttribute('recovery')
+ except:
+ pass
+
+ if delete_vm is True:
+ action = VM_CONFIG
+ status_msg = 'Deleting virtual machine service "%s"' % vm_name
+ elif isNew is True:
+ action = VM_ADD
+ status_msg = 'Creating virtual machine service "%s"' % vm_name
+ else:
+ action = VM_CONFIG
+ status_msg = 'Configuring virtual machine service "%s"' % vm_name
+
+ return (True, { 'action_type': action, 'action_msg': status_msg })
+
+def validate_fence_del(model, request):
+ fvar = GetReqVars(request, [ 'orig_name' ])
+
+ fencedev_name = fvar['orig_name']
+ if fencedev_name is None:
+ return (False, { 'errors': [ 'No fence device name in form submission' ] })
+
+ try:
+ fdev = model.getFenceDeviceByName(fencedev_name)
+ if fdev:
+ if model.deleteFenceDevice(fdev) is not True:
+ raise Exception, 'failed to remove %s' % fdev.getName()
+ model.removeFenceInstancesForFenceDevice(fencedev_name)
+ else:
+ raise Exception, 'no fence device named "%s" was found' \
+ % fencedev_name
+ except Exception, e:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('DFD3: %s: %r %s' \
+ % (fencedev_name, e, str(e)))
+ return (False, { 'errors': [ 'Error removing fence device %s: %s' \
+ % (fencedev_name, str(e)) ]})
+ return (True, { 'name': fencedev_name })
next reply other threads:[~2007-12-12 15:43 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-12-12 15:43 rmccabe [this message]
-- strict thread matches above, loose matches on Subject: below --
2008-07-31 18:46 [Cluster-devel] conga/luci/site/luci/Extensions LuciValidation.py rmccabe
2010-08-05 19:32 rmccabe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20071212154315.848.qmail@sourceware.org \
--to=rmccabe@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.