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_agent( self, name="runner.pcmk.load_agent", agent_name="ocf:heartbeat:Dummy", agent_filename=None, agent_is_missing=False, 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] elif not agent_is_missing: 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(""))) if agent_is_missing: self.__calls.place( name, RunnerCall( "crm_resource --show-metadata {0}".format(agent_name), stdout="", stderr=( f"Agent {agent_name} not found or does not support " "meta-data: Invalid argument (22)\n" f"Metadata query for {agent_name} failed: Input/output " "error\n"), returncode=74), instead=instead, ) return with open(rc(agent_metadata_filename)) as a_file: self.__calls.place( name, RunnerCall( "crm_resource --show-metadata {0}".format(agent_name), stdout=a_file.read()), instead=instead, )
def load( self, modifiers=None, name="runner.cib.load", filename=None, before=None, returncode=0, stderr=None, instead=None, env=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 env -- CommandRunner environment variables 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) """ # pylint: disable=too-many-arguments 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, env=env ) else: with open( rc(filename if filename else self.cib_filename) ) as cib_file: cib = modify_cib( cib_file.read(), modifiers, **modifier_shortcuts ) call = RunnerCall(command, stdout=cib, env=env) self.__calls.place(name, call, before=before, instead=instead)
def load_state( self, name="runner.pcmk.load_state", filename="crm_mon.minimal.xml", resources=None, nodes=None, stdout="", stderr="", returncode=0, env=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 string nodes -- xml - nodes section, will be put to state string stdout -- crm_mon's stdout string stderr -- crm_mon's stderr int returncode -- crm_mon's returncode dict env -- CommandRunner environment variables """ if (resources or nodes) and (stdout or stderr or returncode): raise AssertionError( "Cannot specify resources or nodes when stdout, stderr or " "returncode is specified" ) command = ["crm_mon", "--one-shot", "--inactive", "--output-as", "xml"] if stdout or stderr or returncode: self.__calls.place( name, RunnerCall( command, stdout=stdout, stderr=stderr, returncode=returncode, env=env, ), ) return with open(rc(filename)) as a_file: state_xml = a_file.read() self.__calls.place( name, RunnerCall( command, stdout=etree_to_str( complete_state(state_xml, resources, nodes) ), env=env, ), )
def load_ticket_state_plaintext( self, name="runner.pcmk.load_ticket_state_plaintext", stdout="", stderr="", returncode=0, env=None, ): """ Create a call for loading plaintext tickets status str name -- key of the call str stdout -- crm_ticket's stdout str stderr -- crm_ticket's stderr int returncode -- crm_ticket's returncode dict env -- CommandRunner environment variables """ self.__calls.place( name, RunnerCall( ["crm_ticket", "--details"], stdout=stdout, stderr=stderr, returncode=returncode, env=env, ), )
def place( self, command, name="", stdout="", stderr="", returncode=0, check_stdin=None, before=None, instead=None, env=None, ): # pylint: disable=too-many-arguments """ 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 dict env -- CommandRunner environment variables """ call = RunnerCall(command, stdout, stderr, returncode, check_stdin, env=env) self.__calls.place(name, call, before, instead) return self
def _resource_move_ban_clear(self, name, action, instead=None, before=None, resource=None, node=None, master=None, lifetime=None, expired=None, stdout="", stderr="", returncode=0): cmd = ["crm_resource", action] if resource: cmd.extend(["--resource", resource]) if node: cmd.extend(["--node", node]) if master: cmd.extend(["--master"]) if lifetime: cmd.extend(["--lifetime", lifetime]) if expired: cmd.extend(["--expired"]) self.__calls.place( name, RunnerCall(" ".join(cmd), stdout=stdout, stderr=stderr, returncode=returncode), before=before, instead=instead, )
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( "stonith_admin --history {0} --cleanup".format(node), stdout=stdout, stderr=stderr, returncode=returncode, ), )
def ticket_revoke(self, ticket_name, site_ip, stdout="", stderr="", returncode=0, name="runner.booth.ticket_revoke", instead=None, before=None): # pylint: disable=too-many-arguments """ Create a call for revoking a ticket string ticket_name -- the name of the ticket to be revoked string site_ip -- an IP address of a site the ticket is being revoked to string stdout -- stdout of the booth revoke command string stderr -- stderr of the booth revoke command int returncode -- returncode of the booth revoke command string name -- the key of the call string before -- the key of a call before which this call is to be placed string instead -- the key of a call instead of which this new call is to be placed """ self.__calls.place( name, RunnerCall( f"{settings.booth_binary} revoke -s {site_ip} {ticket_name}", stdout=stdout, stderr=stderr, returncode=returncode, ), before=before, 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=CheckStdinEqualXml(cib), ), instead=instead, )
def get_status( self, node, device, fence_agent, stdout="", stderr="", return_code=0, name="runner.scsi.is_fenced", ): """ Create a call for getting scsi status string node -- a node from which is unfencing performed str device -- a device to check string stdout -- stdout from fence_scsi agent script string stderr -- stderr from fence_scsi agent script int return_code -- return code of the fence_scsi agent script string name -- the key of this call """ self.__calls.place( name, RunnerCall( [ os.path.join(settings.fence_agent_binaries, fence_agent), "--action=status", f"--devices={device}", f"--plug={node}", ], stdout=stdout, stderr=stderr, returncode=return_code, ), )
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( ["corosync-qdevice-net-certutil", "-M", "-c", cert_path], stdout=( stdout if stdout is not None else f"Certificate stored in {output_path}\n" ), stderr=stderr, returncode=returncode, ), )
def is_enabled( self, service, is_enabled=True, name="runner_systemctl.is_enabled", before=None, instead=None, ): args = dict( stdout="disabled\n", returncode=1, ) if is_enabled: args = dict( stdout="enabled\n", returncode=0, ) self.__calls.place( name, RunnerCall( [ settings.systemctl_binary, "is-enabled", f"{service}.service" ], **args, ), before=before, 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( ["corosync-qdevice-net-certutil", "-r", "-n", cluster_name], stdout=( stdout if stdout is not None else f"Certificate request stored in {cert_req_path}\n" ), stderr=stderr, returncode=returncode, ), )
def initialize_devices( self, devices, options, stdout="", stderr="", return_code=0, name="runner.sbd.initialize_devices", ): cmd = [settings.sbd_binary] for device in devices: cmd += ["-d", device] for opt, val in sorted(options.items()): cmd += [DEVICE_INITIALIZATION_OPTIONS_MAPPING[opt], str(val)] cmd.append("create") self.__calls.place( name, RunnerCall( cmd, stdout=stdout, stderr=stderr, returncode=return_code, ), )
def status_daemon(self, instance_name=None, stdout="", stderr="", returncode=0, name="runner.booth.status_daemon", instead=None, before=None): """ Create a call for getting the booth daemon status string instance_name -- booth instance name string stdout -- stdout of the booth command string stderr -- stderr of the booth command int returncode -- returncode of the booth command string name -- the key of the call string before -- the key of a call before which this call is to be placed string instead -- the key of a call instead of which this new call is to be placed """ cmd = f"{settings.booth_binary} status" if instance_name: cmd += f" -c {instance_name}" self.__calls.place(name, RunnerCall( cmd, stdout=stdout, stderr=stderr, returncode=returncode, ), before=before, instead=instead)
def verify( self, name="runner.pcmk.verify", cib_tempfile=None, stderr=None, verbose=False, env=None, ): """ 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 dict env -- CommandRunner environment variables """ cmd = ["crm_verify"] if verbose: cmd.extend(["-V", "-V"]) if cib_tempfile: cmd.extend(["--xml-file", cib_tempfile]) else: cmd.append("--live-check") self.__calls.place( name, RunnerCall( cmd, stderr=("" if stderr is None else stderr), returncode=(0 if stderr is None else 55), env=env, ), )
def diff( self, cib_old_file, cib_new_file, name="runner.cib.diff", stdout="resulting diff", stderr="", returncode=1, # 0 -> old and new are the same, 1 -> old and new differ ): """ 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", cib_old_file, "--new", cib_new_file, "--no-version", ], stdout=stdout, stderr=stderr, returncode=returncode, ), )
def get_rule_in_effect_status( self, rule_id, returncode=0, name="runner.pcmk.get_rule_in_effect_status", cib_load_name="runner.cib.load", ): """ Create a call for running a tool to get rule expired status string rule_id -- id of the rule to be checked int returncode -- result of the check sting name -- key of the call string cib_load_name -- key of a call from whose stdout the cib is taken """ cib_xml = self.__calls.get(cib_load_name).stdout self.__calls.place( name, RunnerCall( ["crm_rule", "--check", "--rule", rule_id, "--xml-text", "-"], check_stdin=CheckStdinEqualXml(cib_xml), stdout="", stderr="", returncode=returncode, ), )
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 -- returncode of the wait command, defaults to 0 if stderr is empty and to 124 if stderr is not empty """ 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 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( "stonith_admin --history {0} --verbose".format(node), 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 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 """ if stdout is None: with open(rc("fenced_metadata.xml")) as a_file: stdout = a_file.read() self.__calls.place( name, RunnerCall( f"{settings.pacemaker_fenced} metadata", 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, env=None, ): """ Create a call for pushing a diff of CIBs string name -- key of the call string cib_diff -- the diff of CIBs dict env -- CommandRunner environment variables """ self.__calls.place( name, RunnerCall( ["cibadmin", "--patch", "--verbose", "--xml-pipe"], check_stdin=CheckStdinEqualXml(cib_diff), stdout=stdout, stderr=stderr, returncode=returncode, env=env, ), )
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 -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 is_enabled( self, service, is_enabled=True, name="runner_systemctl.is_enabled", before=None, instead=None ): args = dict( stdout="disabled\n", returncode=1, ) if is_enabled: args = dict( stdout="enabled\n", returncode=0, ) self.__calls.place( name, RunnerCall( "{bin_path} is-enabled {service}.service".format( bin_path=settings.systemctl_binary, service=service, ), **args ), 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 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, ), )
def unfence_node( self, node, devices, stdout="", stderr="", return_code=0, name="runner.scsi.unfence_node", ): """ Create a calls for node scsi unfencing string node -- a node from which is unfencing performed list devices -- list of devices to unfence string stdout -- stdout from fence_scsi agent script string stderr -- stderr from fence_scsi agent script int return_code -- return code of the fence_scsi agent script string name -- the key of this call """ self.__calls.place( name, RunnerCall( [ os.path.join(settings.fence_agent_binaries, "fence_scsi"), "--action=on", "--devices", ",".join(devices), f"--plug={node}", ], stdout=stdout, stderr=stderr, returncode=return_code, ), )
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, ), )