diff --git a/agents/kubevirt/fence_kubevirt.py b/agents/kubevirt/fence_kubevirt.py index 8392b75a..8c27a033 100755 --- a/agents/kubevirt/fence_kubevirt.py +++ b/agents/kubevirt/fence_kubevirt.py @@ -1,152 +1,154 @@ #!@PYTHON@ -tt import sys import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, run_delay, EC_STATUS, EC_FETCH_VM_UUID try: from kubernetes.client.exceptions import ApiException except ImportError: logging.error("Couldn\'t import kubernetes.client.exceptions.ApiException - not found or not accessible") +def _get_namespace(options): + from kubernetes import config + + ns = options.get("--namespace") + if ns is None: + ns = config.kube_config.list_kube_config_contexts()[1]['context']['namespace'] + + return ns + def get_nodes_list(conn, options): logging.debug("Starting list/monitor operation") result = {} try: apiversion = options.get("--apiversion") - namespace = options.get("--namespace") + namespace = _get_namespace(options) include_uninitialized = True vm_api = conn.resources.get(api_version=apiversion, kind='VirtualMachine') vm_list = vm_api.get(namespace=namespace) for vm in vm_list.items: result[vm.metadata.name] = ("", None) except Exception as e: logging.error("Exception when calling VirtualMachine list: %s", e) return result def get_power_status(conn, options): logging.debug("Starting get status operation") try: apiversion = options.get("--apiversion") - namespace = options.get("--namespace") + namespace = _get_namespace(options) name = options.get("--plug") vmi_api = conn.resources.get(api_version=apiversion, kind='VirtualMachineInstance') vmi = vmi_api.get(name=name, namespace=namespace) return translate_status(vmi.status.phase) except ApiException as e: if e.status == 404: try: vm_api = conn.resources.get(api_version=apiversion, kind='VirtualMachine') vm = vm_api.get(name=name, namespace=namespace) except ApiException as e: logging.error("VM %s doesn't exist", name) fail(EC_FETCH_VM_UUID) return "off" logging.error("Failed to get power status, with API Exception: %s", e) fail(EC_STATUS) except Exception as e: logging.error("Failed to get power status, with Exception: %s", e) fail(EC_STATUS) def translate_status(instance_status): if instance_status == "Running": return "on" return "unknown" def set_power_status(conn, options): logging.debug("Starting set status operation") try: apiversion= options.get("--apiversion") - namespace = options.get("--namespace") + namespace = _get_namespace(options) name = options.get("--plug") action = 'start' if options["--action"] == "on" else 'stop' virtctl_vm_action(conn, action, namespace, name, apiversion) except Exception as e: logging.error("Failed to set power status, with Exception: %s", e) fail(EC_STATUS) def define_new_opts(): all_opt["namespace"] = { "getopt" : ":", "longopt" : "namespace", "help" : "--namespace=[namespace] Namespace of the KubeVirt machine", "shortdesc" : "Namespace of the KubeVirt machine.", - "required" : "1", + "required" : "0", "order" : 2 } all_opt["kubeconfig"] = { "getopt" : ":", "longopt" : "kubeconfig", "help" : "--kubeconfig=[kubeconfig] Kubeconfig file path", "shortdesc": "Kubeconfig file path", "required": "0", "order": 4 } all_opt["apiversion"] = { "getopt" : ":", "longopt" : "apiversion", "help" : "--apiversion=[apiversion] Version of the KubeVirt API", "shortdesc" : "Version of the KubeVirt API.", "required" : "0", "default" : "kubevirt.io/v1", "order" : 5 } def virtctl_vm_action(conn, action, namespace, name, apiversion): path = '/apis/subresources.{api_version}/namespaces/{namespace}/virtualmachines/{name}/{action}' path = path.format(api_version=apiversion, namespace=namespace, name=name, action=action) return conn.request('put', path, header_params={'accept': '*/*'}) -def validate_options(required_options_list, options): - for required_option in required_options_list: - if required_option not in options: - fail_usage("Failed: %s option must be provided" % required_option) - # Main agent method def main(): conn = None device_opt = ["port", "namespace", "kubeconfig", "ssl_insecure", "no_password", "apiversion"] atexit.register(atexit_handler) define_new_opts() all_opt["power_timeout"]["default"] = "40" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for KubeVirt" docs["longdesc"] = "fence_kubevirt is an I/O Fencing agent for KubeVirt." docs["vendorurl"] = "https://kubevirt.io/" show_docs(options, docs) run_delay(options) - validate_options(['--namespace'], options) - # Disable insecure-certificate-warning message if "--ssl-insecure" in options: import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) try: from kubernetes import config from openshift.dynamic import DynamicClient kubeconfig = options.get('--kubeconfig') k8s_client = config.new_client_from_config(config_file=kubeconfig) conn = DynamicClient(k8s_client) except ImportError: logging.error("Couldn\'t import kubernetes.config or " "openshift.dynamic.DynamicClient - not found or not accessible") # Operate the fencing device result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) sys.exit(result) if __name__ == "__main__": main() diff --git a/tests/data/metadata/fence_kubevirt.xml b/tests/data/metadata/fence_kubevirt.xml index 24e97558..ccb20c22 100644 --- a/tests/data/metadata/fence_kubevirt.xml +++ b/tests/data/metadata/fence_kubevirt.xml @@ -1,134 +1,134 @@ <?xml version="1.0" ?> <resource-agent name="fence_kubevirt" shortdesc="Fence agent for KubeVirt" > <longdesc>fence_kubevirt is an I/O Fencing agent for KubeVirt.</longdesc> <vendor-url>https://kubevirt.io/</vendor-url> <parameters> <parameter name="action" unique="0" required="1"> <getopt mixed="-o, --action=[action]" /> <content type="string" default="reboot" /> <shortdesc lang="en">Fencing action</shortdesc> </parameter> <parameter name="plug" unique="0" required="1" obsoletes="port"> <getopt mixed="-n, --plug=[id]" /> <content type="string" /> <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc> </parameter> <parameter name="port" unique="0" required="1" deprecated="1"> <getopt mixed="-n, --plug=[id]" /> <content type="string" /> <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc> </parameter> <parameter name="ssl_insecure" unique="0" required="0"> <getopt mixed="--ssl-insecure" /> <content type="boolean" /> <shortdesc lang="en">Use SSL connection without verifying certificate</shortdesc> </parameter> - <parameter name="namespace" unique="0" required="1"> + <parameter name="namespace" unique="0" required="0"> <getopt mixed="--namespace=[namespace]" /> <content type="string" /> <shortdesc lang="en">Namespace of the KubeVirt machine.</shortdesc> </parameter> <parameter name="kubeconfig" unique="0" required="0"> <getopt mixed="--kubeconfig=[kubeconfig]" /> <content type="string" /> <shortdesc lang="en">Kubeconfig file path</shortdesc> </parameter> <parameter name="apiversion" unique="0" required="0"> <getopt mixed="--apiversion=[apiversion]" /> <content type="string" default="kubevirt.io/v1" /> <shortdesc lang="en">Version of the KubeVirt API.</shortdesc> </parameter> <parameter name="quiet" unique="0" required="0"> <getopt mixed="-q, --quiet" /> <content type="boolean" /> <shortdesc lang="en">Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog.</shortdesc> </parameter> <parameter name="verbose" unique="0" required="0"> <getopt mixed="-v, --verbose" /> <content type="boolean" /> <shortdesc lang="en">Verbose mode. Multiple -v flags can be stacked on the command line (e.g., -vvv) to increase verbosity.</shortdesc> </parameter> <parameter name="verbose_level" unique="0" required="0"> <getopt mixed="--verbose-level" /> <content type="integer" /> <shortdesc lang="en">Level of debugging detail in output. Defaults to the number of --verbose flags specified on the command line, or to 1 if verbose=1 in a stonith device configuration (i.e., on stdin).</shortdesc> </parameter> <parameter name="debug" unique="0" required="0" deprecated="1"> <getopt mixed="-D, --debug-file=[debugfile]" /> <content type="string" /> <shortdesc lang="en">Write debug information to given file</shortdesc> </parameter> <parameter name="debug_file" unique="0" required="0" obsoletes="debug"> <getopt mixed="-D, --debug-file=[debugfile]" /> <content type="string" /> <shortdesc lang="en">Write debug information to given file</shortdesc> </parameter> <parameter name="version" unique="0" required="0"> <getopt mixed="-V, --version" /> <content type="boolean" /> <shortdesc lang="en">Display version information and exit</shortdesc> </parameter> <parameter name="help" unique="0" required="0"> <getopt mixed="-h, --help" /> <content type="boolean" /> <shortdesc lang="en">Display help and exit</shortdesc> </parameter> <parameter name="separator" unique="0" required="0"> <getopt mixed="-C, --separator=[char]" /> <content type="string" default="," /> <shortdesc lang="en">Separator for CSV created by 'list' operation</shortdesc> </parameter> <parameter name="delay" unique="0" required="0"> <getopt mixed="--delay=[seconds]" /> <content type="second" default="0" /> <shortdesc lang="en">Wait X seconds before fencing is started</shortdesc> </parameter> <parameter name="disable_timeout" unique="0" required="0"> <getopt mixed="--disable-timeout=[true/false]" /> <content type="string" /> <shortdesc lang="en">Disable timeout (true/false) (default: true when run from Pacemaker 2.0+)</shortdesc> </parameter> <parameter name="login_timeout" unique="0" required="0"> <getopt mixed="--login-timeout=[seconds]" /> <content type="second" default="5" /> <shortdesc lang="en">Wait X seconds for cmd prompt after login</shortdesc> </parameter> <parameter name="power_timeout" unique="0" required="0"> <getopt mixed="--power-timeout=[seconds]" /> <content type="second" default="40" /> <shortdesc lang="en">Test X seconds for status change after ON/OFF</shortdesc> </parameter> <parameter name="power_wait" unique="0" required="0"> <getopt mixed="--power-wait=[seconds]" /> <content type="second" default="0" /> <shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc> </parameter> <parameter name="shell_timeout" unique="0" required="0"> <getopt mixed="--shell-timeout=[seconds]" /> <content type="second" default="3" /> <shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc> </parameter> <parameter name="stonith_status_sleep" unique="0" required="0"> <getopt mixed="--stonith-status-sleep=[seconds]" /> <content type="second" default="1" /> <shortdesc lang="en">Sleep X seconds between status calls during a STONITH action</shortdesc> </parameter> <parameter name="retry_on" unique="0" required="0"> <getopt mixed="--retry-on=[attempts]" /> <content type="integer" default="1" /> <shortdesc lang="en">Count of attempts to retry power on</shortdesc> </parameter> </parameters> <actions> <action name="on" automatic="0"/> <action name="off" /> <action name="reboot" /> <action name="status" /> <action name="list" /> <action name="list-status" /> <action name="monitor" /> <action name="metadata" /> <action name="manpage" /> <action name="validate-all" /> </actions> </resource-agent>