def load_content( self, cib, returncode=0, stderr=None, name="runner.cib.load_content", instead=None, before=None, ): """ Create call for loading CIB specified by its full content string cib -- CIB data (stdout of the loading process) string stderr -- error returned from the loading process int returncode -- exit code of the loading process string name -- key of the call string instead -- key of call instead of which this new call is to be placed string before -- key of call before which this new call is to be placed """ command = "cibadmin --local --query" if returncode != 0: call = RunnerCall(command, stderr=stderr, returncode=returncode) else: call = RunnerCall(command, stdout=cib) self.__calls.place(name, call, before=before, instead=instead)
def load( self, modifiers=None, name="runner.cib.load", filename=None, before=None, returncode=0, stderr=None, instead=None, **modifier_shortcuts ): """ Create call for loading cib. string name -- key of the call list of callable modifiers -- every callable takes etree.Element and returns new etree.Element with desired modification. string filename -- points to file with cib in the content string before -- key of call before which this new call is to be placed int returncode string stderr string instead -- key of call instead of which this new call is to be placed dict modifier_shortcuts -- a new modifier is generated from each modifier shortcut. As key there can be keys of MODIFIER_GENERATORS. Value is passed into appropriate generator from MODIFIER_GENERATORS. For details see pcs.test.tools.fixture_cib (mainly the variable MODIFIER_GENERATORS - please refer it when you are adding params here) """ if(returncode != 0 or stderr is not None) and ( modifiers is not None or filename is not None or modifier_shortcuts ): raise AssertionError( "Do not combine parameters 'returncode' and 'stderr' with" " parameters 'modifiers', 'filename' and 'modifier_shortcuts'" ) command = "cibadmin --local --query" if returncode != 0: call = RunnerCall(command, stderr=stderr, returncode=returncode) else: cib = modify_cib( open(rc(filename if filename else self.cib_filename)).read(), modifiers, **modifier_shortcuts ) call = RunnerCall(command, stdout=cib) self.__calls.place(name, call, before=before, instead=instead)
def wait(self, name="runner.pcmk.wait", stderr="", returncode=None, timeout=None): """ Create call for waiting to pacemaker idle string name -- key of the call string stderr -- stderr of wait command int returncode -- has default value 0 if stderr is empty and has default configured value (62) if stderr is not empty. However the explicitly specified returncode is used if the returncode is specified. """ if returncode is None: returncode = self.default_wait_error_returncode if stderr else 0 self.__calls.place( name, RunnerCall( "crm_resource --wait --timeout={0}".format( timeout if timeout else self.default_wait_timeout), stderr=stderr, returncode=returncode, ))
def load_state(self, name="runner.pcmk.load_state", filename="crm_mon.minimal.xml", resources=None, raw_resources=None): """ Create call for loading pacemaker state. string name -- key of the call string filename -- points to file with the status in the content string resources -- xml - resources section, will be put to state """ if resources and raw_resources is not None: raise AssertionError( "Cannot use 'resources' and 'raw_resources' together") state = etree.fromstring(open(rc(filename)).read()) if raw_resources is not None: resources = fixture_state_resources_xml(**raw_resources) if resources: state.append(complete_state_resources(etree.fromstring(resources))) self.__calls.place( name, RunnerCall( "crm_mon --one-shot --as-xml --inactive", stdout=etree_to_str(state), ))
def diff( self, cib_old_file, cib_new_file, name="runner.cib.diff", stdout="resulting diff", stderr="", returncode=0 ): """ Create a call for diffing two CIBs stored in two files string cib_old_file -- path to a file with an old CIB string cib_new_file -- path to a file with a new CIB string name -- key of the call string stdout -- resulting diff string stderr -- error returned from the diff process int returncode -- exit code of the diff process """ self.__calls.place( name, RunnerCall( "crm_diff --original {old} --new {new} --no-version".format( old=cib_old_file, new=cib_new_file ), stdout=stdout, stderr=stderr, returncode=returncode, ), )
def load_fenced_metadata( self, name="runner.pcmk.load_fenced_metadata", stdout=None, stderr="", returncode=0, instead=None, before=None, ): """ Create a call for loading fenced metadata - additional fence options string name -- the key of this call string stdout -- fenced stdout, default metadata if None string stderr -- fenced stderr int returncode -- fenced returncode string instead -- the key of a call instead of which this new call is to be placed string before -- the key of a call before which this new call is to be placed """ self.__calls.place( name, RunnerCall( "/usr/libexec/pacemaker/pacemaker-fenced metadata", stdout=( stdout if stdout is not None else open(rc("fenced_metadata.xml")).read() ), stderr=stderr, returncode=returncode ), before=before, instead=instead, )
def local_node_name( self, name="runner.pcmk.local_node_name", instead=None, before=None, node_name="", stdout="", stderr="", returncode=0 ): """ Create a call for crm_node --name string name -- the key of this call string instead -- the key of a call instead of which this new call is to be placed string before -- the key of a call before which this new call is to be placed string node_name -- resulting node name string stdout -- crm_node's stdout string stderr -- crm_node's stderr int returncode -- crm_node's returncode """ if node_name and (stdout or stderr or returncode): raise AssertionError( "Cannot specify node_name when stdout, stderr or returncode is " "specified" ) cmd = ["crm_node", "--name"] self.__calls.place( name, RunnerCall( " ".join(cmd), stdout=(node_name if node_name else stdout), stderr=stderr, returncode=returncode ), before=before, instead=instead, )
def place(self, command, name="", stdout="", stderr="", returncode=0, check_stdin=None, before=None, instead=None): """ Place new call to a config. string command -- cmdline call (e.g. "crm_mon --one-shot --as-xml") string name -- name of the call; it is possible to get it by the method "get" string stdout -- stdout of the call string stderr -- stderr of the call int returncode -- returncode of the call callable check_stdin -- callable that can check if stdin is as expected string before -- name of another call to insert this call before it string instead -- name of another call to replace it by this call """ call = RunnerCall(command, stdout, stderr, returncode, check_stdin) self.__calls.place(name, call, before, instead) return self
def reload(self, name="runner.corosync.reload"): self.__calls.place( name, RunnerCall("corosync-cfgtool -R", stdout=outdent("""\ Reloading corosync.conf... Done """)))
def version(self, name="runner.corosync.version", version="2.4.0"): self.__calls.place( name, RunnerCall("corosync -v", stdout=outdent("""\ Corosync Cluster Engine, version '{0}' Copyright... """.format(version))))
def reload(self, name="runner.corosync.reload", instead=None, before=None): self.__calls.place(name, RunnerCall("corosync-cfgtool -R", stdout=outdent("""\ Reloading corosync.conf... Done """)), before=before, instead=instead)
def upgrade(self, name="runner.cib.upgrade", before=None): """ Create call for upgrading cib. string name -- key of the call string before -- key of call before which this new call is to be placed """ self.__calls.place(name, RunnerCall("cibadmin --upgrade --force"), before=before)
def remove_node( self, node_name, stderr="", returncode=0, name="runner.pcmk.remove_node", ): self.__calls.place( name, RunnerCall( "crm_node --force --remove {0}".format(node_name), stderr=stderr, returncode=returncode, ), )
def can_wait(self, name="runner.pcmk.can_wait", before=None, stdout="--wait"): """ Create call that checks that wait for idle is supported string name -- key of the call string before -- key of call before which this new call is to be placed """ self.__calls.place(name, RunnerCall("crm_resource -?", stdout=stdout), before=before)
def list_watchdogs(self, output, name="runner.sbd.list_watchdogs", stderr="", returncode=0, instead=None, before=None): self.__calls.place(name, RunnerCall( "{} query-watchdog".format(settings.sbd_binary), stdout=output, stderr=stderr, returncode=returncode, ), before=before, instead=instead)
def quorum_status( self, node_list=None, stdout=None, stderr="", returncode=0, name="runner.corosync.quorum_status", ): if bool(node_list) == bool(stdout): raise AssertionError( "Exactly one of 'node_list', 'stdout' must be specified") if node_list: stdout = outdent("""\ Quorum information ------------------ Date: Fri Jan 16 13:03:28 2015 Quorum provider: corosync_votequorum Nodes: {nodes_num} Node ID: 1 Ring ID: 19860 Quorate: Yes\n Votequorum information ---------------------- Expected votes: {nodes_num} Highest expected: {nodes_num} Total votes: {nodes_num} Quorum: {quorum_num} Flags: Quorate\n Membership information ---------------------- Nodeid Votes Qdevice Name {nodes}\ """).format(nodes_num=len(node_list), quorum_num=(len(node_list) // 2) + 1, nodes="".join([ _quorum_status_node_fixture(node_id, node) for node_id, node in enumerate(node_list, 1) ])) self.__calls.place( name, RunnerCall("{binary} -p".format(binary=os.path.join( settings.corosync_binaries, "corosync-quorumtool"), ), stdout=stdout, stderr=stderr, returncode=returncode), )
def push( self, modifiers=None, name="runner.cib.push", load_key="runner.cib.load", instead=None, stderr="", returncode=0, **modifier_shortcuts ): """ Create call for pushing cib. Cib is taken from the load call by default. string name -- key of the call list of callable modifiers -- every callable takes etree.Element and returns new etree.Element with desired modification. string load_key -- key of a call from which stdout can be cib taken string instead -- key of call instead of which this new call is to be placed dict modifier_shortcuts -- a new modifier is generated from each modifier shortcut. As key there can be keys of MODIFIER_GENERATORS. Value is passed into appropriate generator from MODIFIER_GENERATORS. For details see pcs.test.tools.fixture_cib (mainly the variable MODIFIER_GENERATORS - please refer it when you are adding params here) """ cib = modify_cib( self.__calls.get(load_key).stdout, modifiers, **modifier_shortcuts ) self.__calls.place( name, RunnerCall( "cibadmin --replace --verbose --xml-pipe --scope configuration", stderr=stderr, returncode=returncode, check_stdin=create_check_stdin_xml(cib), ), instead=instead, )
def load_agent( self, name="runner.pcmk.load_agent", agent_name="ocf:heartbeat:Dummy", agent_filename=None, instead=None, ): """ Create call for loading resource agent metadata. string name -- key of the call string agent_name string agent_filename -- points to file with the agent metadata in the content string instead -- key of call instead of which this new call is to be placed """ if agent_filename: agent_metadata_filename = agent_filename elif agent_name in AGENT_FILENAME_MAP: agent_metadata_filename = AGENT_FILENAME_MAP[agent_name] else: raise AssertionError(( "Filename with metadata of agent '{0}' not specified.\n" "Please specify file with metadata for agent:\n" " a) explicitly for this test:" " config.runner.pcmk.load_agent(agent_name='{0}'," " filename='FILENAME_HERE.xml')\n" " b) implicitly for agent '{0}' in 'AGENT_FILENAME_MAP' in" " '{1}'\n" "Place agent metadata into '{2}FILENAME_HERE.xml'" ).format(agent_name, os.path.realpath(__file__), rc(""))) self.__calls.place( name, RunnerCall( "crm_resource --show-metadata {0}".format(agent_name), stdout=open(rc(agent_metadata_filename)).read() ), instead=instead, )
def is_active(self, service, name="runner_systemctl.is_active", is_active=True): args = dict( stdout="unknown\n", returncode=3, ) if is_active: args = dict( stdout="active\n", returncode=0, ) self.__calls.place( name, RunnerCall( "{bin_path} is-active {service}.service".format( bin_path=settings.systemctl_binary, service=service, ), **args))
def resource_cleanup( self, name="runner.pcmk.cleanup", instead=None, before=None, resource=None, node=None, stdout="", stderr="", returncode=0 ): """ Create a call for crm_resource --cleanup string name -- the key of this call string instead -- the key of a call instead of which this new call is to be placed string before -- the key of a call before which this new call is to be placed string resource -- the id of a resource to be cleaned string node -- the name of the node where resources should be cleaned string stdout -- crm_resource's stdout string stderr -- crm_resource's stderr int returncode -- crm_resource's returncode """ cmd = ["crm_resource", "--cleanup"] if resource: cmd.extend(["--resource", resource]) if node: cmd.extend(["--node", node]) self.__calls.place( name, RunnerCall( " ".join(cmd), stdout=stdout, stderr=stderr, returncode=returncode ), before=before, instead=instead, )
def push_diff(self, name="runner.cib.push_diff", cib_diff="resulting diff", stdout="", stderr="", returncode=0): """ Create a call for pushing a diff of CIBs string name -- key of the call string cib_diff -- the diff of CIBs """ self.__calls.place( name, RunnerCall( "cibadmin --patch --verbose --xml-pipe", check_stdin=create_check_stdin_xml(cib_diff), stdout=stdout, stderr=stderr, returncode=returncode, ), )
def fence_history_update( self, name="runner.pcmk.fence_history_update", stdout="", stderr="", returncode=0 ): """ Create call for updating fencing history. string name -- key of the call string stdout -- pacemaker's stdout string stderr -- pacemaker's stderr int returncode -- pacemaker's returncode """ self.__calls.place( name, RunnerCall( "/usr/sbin/stonith_admin --history * --broadcast", stdout=stdout, stderr=stderr, returncode=returncode, ), )
def load_state(self, name="runner.pcmk.load_state", filename="crm_mon.minimal.xml", resources=None): """ Create call for loading pacemaker state. string name -- key of the call string filename -- points to file with the status in the content string resources -- xml - resources section, will be put to state """ state = etree.fromstring(open(rc(filename)).read()) if resources: state.append(complete_state_resources(etree.fromstring(resources))) self.__calls.place( name, RunnerCall( "crm_mon --one-shot --as-xml --inactive", stdout=etree_to_str(state), ))
def verify( self, name="runner.pcmk.verify", cib_tempfile=None, stderr=None, verbose=False ): """ Create call that checks that wait for idle is supported string name -- key of the call string before -- key of call before which this new call is to be placed """ self.__calls.place( name, RunnerCall( "crm_verify{0} {1}".format( " -V" if verbose else "", "--xml-file {0}".format(cib_tempfile) if cib_tempfile else "--live-check" ), stderr=("" if stderr is None else stderr), returncode=(0 if stderr is None else 55), ), )
def qdevice_get_pk12(self, cert_path="cert path", output_path="output_path", stdout=None, stderr="", returncode=0, name="runner.corosync.qdevice_get_pk12"): if stdout is not None and output_path is not None: raise AssertionError( "Cannot specify both 'output_path' and 'stdout'") self.__calls.place( name, RunnerCall("{binary} -M -c {cert_path}".format( binary=os.path.join(settings.corosync_binaries, "corosync-qdevice-net-certutil"), cert_path=cert_path, ), stdout=(stdout if stdout is not None else f"Certificate stored in {output_path}\n"), stderr=stderr, returncode=returncode), )
def fence_history_get( self, name="runner.pcmk.fence_history_get", node=None, stdout="", stderr="", returncode=0 ): """ Create call for getting plain text fencing history. string name -- key of the call string node -- a node to get a history from string stdout -- pacemaker's stdout string stderr -- pacemaker's stderr int returncode -- pacemaker's returncode """ self.__calls.place( name, RunnerCall( "/usr/sbin/stonith_admin --history {0} --verbose".format(node), stdout=stdout, stderr=stderr, returncode=returncode, ), )
def fence_history_cleanup( self, name="runner.pcmk.fence_history_cleanup", node=None, stdout="", stderr="", returncode=0 ): """ Create call for cleaning fencing history up. string name -- key of the call string node -- a node to clean a history from string stdout -- pacemaker's stdout string stderr -- pacemaker's stderr int returncode -- pacemaker's returncode """ self.__calls.place( name, RunnerCall( "/usr/sbin/stonith_admin --history {0} --cleanup".format(node), stdout=stdout, stderr=stderr, returncode=returncode, ), )
def load_agent( self, name="runner.pcmk.load_agent", agent_name="ocf:heartbeat:Dummy", agent_filename="resource_agent_ocf_heartbeat_dummy.xml", instead=None, ): """ Create call for loading resource agent metadata. string name -- key of the call string agent_name string agent_filename -- points to file with the agent metadata in the content string instead -- key of call instead of which this new call is to be placed """ self.__calls.place( name, RunnerCall("crm_resource --show-metadata {0}".format(agent_name), stdout=open(rc(agent_filename)).read()), instead=instead, )
def push_independent( self, cib, name="runner.cib.push_independent", instead=None, ): """ Create call for pushing cib. Cib is specified as an argument. string name -- key of the call string cib -- whole cib to push string instead -- key of call instead of which this new call is to be placed """ self.__calls.place( name, RunnerCall( "cibadmin --replace --verbose --xml-pipe --scope configuration", check_stdin=create_check_stdin_xml(cib), ), instead=instead, )
def qdevice_generate_cert(self, cluster_name, cert_req_path="cert_path", stdout=None, stderr="", returncode=0, name="runner.corosync.qdevice_generate_cert"): if stdout is not None and cert_req_path is not None: raise AssertionError( "Cannot specify both 'cert_req_path' and 'stdout'") self.__calls.place( name, RunnerCall( "{binary} -r -n {cluster_name}".format( binary=os.path.join(settings.corosync_binaries, "corosync-qdevice-net-certutil"), cluster_name=cluster_name, ), stdout=(stdout if stdout is not None else f"Certificate request stored in {cert_req_path}\n"), stderr=stderr, returncode=returncode), )