7a42dc
diff --color -uNr a/agents/kubevirt/fence_kubevirt.py b/agents/kubevirt/fence_kubevirt.py
7a42dc
--- a/agents/kubevirt/fence_kubevirt.py	1970-01-01 01:00:00.000000000 +0100
7a42dc
+++ b/agents/kubevirt/fence_kubevirt.py	2021-10-25 13:25:59.904501348 +0200
7a42dc
@@ -0,0 +1,140 @@
7a42dc
+#!@PYTHON@ -tt
7a42dc
+
7a42dc
+import sys
7a42dc
+import logging
7a42dc
+sys.path.append("@FENCEAGENTSLIBDIR@")
7a42dc
+from fencing import *
7a42dc
+from fencing import fail, fail_usage, run_delay, EC_STATUS
7a42dc
+
7a42dc
+try:
7a42dc
+    sys.path.insert(0, '/usr/lib/fence-agents/bundled/kubevirt')
7a42dc
+    from kubernetes.client.exceptions import ApiException
7a42dc
+except ImportError:
7a42dc
+    logging.error("Couldn\'t import kubernetes.client.exceptions.ApiException - not found or not accessible")
7a42dc
+
7a42dc
+def get_nodes_list(conn, options):
7a42dc
+    logging.debug("Starting list/monitor operation")
7a42dc
+    result = {}
7a42dc
+    try:
7a42dc
+        apiversion = options.get("--apiversion")
7a42dc
+        namespace = options.get("--namespace")
7a42dc
+        include_uninitialized = True
7a42dc
+        vm_api = conn.resources.get(api_version=apiversion, kind='VirtualMachine')
7a42dc
+        vm_list = vm_api.get(namespace=namespace)
7a42dc
+        for vm in vm_list.items:
7a42dc
+            result[vm.metadata.name] = ("", None)
7a42dc
+    except Exception as e:
7a42dc
+        logging.error("Exception when calling VirtualMachine list: %s", e)
7a42dc
+    return result
7a42dc
+
7a42dc
+def get_power_status(conn, options):
7a42dc
+    logging.debug("Starting get status operation")
7a42dc
+    try:
7a42dc
+        apiversion = options.get("--apiversion")
7a42dc
+        namespace = options.get("--namespace")
7a42dc
+        name = options.get("--plug")
7a42dc
+        vmi_api = conn.resources.get(api_version=apiversion,
7a42dc
+                                              kind='VirtualMachineInstance')
7a42dc
+        vmi = vmi_api.get(name=name, namespace=namespace)
7a42dc
+        if vmi is not None:
7a42dc
+            phase = vmi.status.phase
7a42dc
+            if phase == "Running":
7a42dc
+                return "on"
7a42dc
+        return "off"
7a42dc
+    except ApiException as e:
7a42dc
+        if e.status == 404:
7a42dc
+            return "off"
7a42dc
+        logging.error("Failed to get power status, with API Exception: %s", e)
7a42dc
+        fail(EC_STATUS)
7a42dc
+    except Exception as e:
7a42dc
+        logging.error("Failed to get power status, with Exception: %s", e)
7a42dc
+        fail(EC_STATUS)
7a42dc
+
7a42dc
+def set_power_status(conn, options):
7a42dc
+    logging.debug("Starting set status operation")
7a42dc
+    try:
7a42dc
+        apiversion= options.get("--apiversion")
7a42dc
+        namespace = options.get("--namespace")
7a42dc
+        name = options.get("--plug")
7a42dc
+        action = 'start' if options["--action"] == "on" else 'stop'
7a42dc
+        virtctl_vm_action(conn, action, namespace, name, apiversion)
7a42dc
+    except Exception as e:
7a42dc
+        logging.error("Failed to set power status, with Exception: %s", e)
7a42dc
+        fail(EC_STATUS)
7a42dc
+
7a42dc
+def define_new_opts():
7a42dc
+    all_opt["namespace"] = {
7a42dc
+        "getopt" : ":",
7a42dc
+        "longopt" : "namespace",
7a42dc
+        "help" : "--namespace=[namespace]        Namespace of the KubeVirt machine",
7a42dc
+        "shortdesc" : "Namespace of the KubeVirt machine.",
7a42dc
+        "required" : "1",
7a42dc
+        "order" : 2
7a42dc
+    }
7a42dc
+    all_opt["kubeconfig"] = {
7a42dc
+        "getopt" : ":",
7a42dc
+        "longopt" : "kubeconfig",
7a42dc
+        "help" : "--kubeconfig=[kubeconfig]      Kubeconfig file path",
7a42dc
+        "shortdesc": "Kubeconfig file path",
7a42dc
+        "required": "0",
7a42dc
+        "order": 4
7a42dc
+    }
7a42dc
+    all_opt["apiversion"] = {
7a42dc
+        "getopt" : ":",
7a42dc
+        "longopt" : "apiversion",
7a42dc
+        "help" : "--apiversion=[apiversion]      Version of the KubeVirt API",
7a42dc
+        "shortdesc" : "Version of the KubeVirt API.",
7a42dc
+        "required" : "0",
7a42dc
+        "default" : "kubevirt.io/v1",
7a42dc
+        "order" : 5
7a42dc
+    }
7a42dc
+
7a42dc
+def virtctl_vm_action(conn, action, namespace, name, apiversion):
7a42dc
+    path = '/apis/subresources.{api_version}/namespaces/{namespace}/virtualmachines/{name}/{action}'
7a42dc
+    path = path.format(api_version=apiversion, namespace=namespace, name=name, action=action)
7a42dc
+    return conn.request('put', path, header_params={'accept': '*/*'})
7a42dc
+
7a42dc
+def validate_options(required_options_list, options):
7a42dc
+    for required_option in required_options_list:
7a42dc
+        if required_option not in options:
7a42dc
+            fail_usage("Failed: %s option must be provided" % required_option)
7a42dc
+
7a42dc
+# Main agent method
7a42dc
+def main():
7a42dc
+    conn = None
7a42dc
+
7a42dc
+    device_opt = ["port", "namespace", "kubeconfig", "ssl_insecure", "no_password", "apiversion"]
7a42dc
+    define_new_opts()
7a42dc
+    options = check_input(device_opt, process_input(device_opt))
7a42dc
+
7a42dc
+    docs = {}
7a42dc
+    docs["shortdesc"] = "Fence agent for KubeVirt"
7a42dc
+    docs["longdesc"] = "fence_kubevirt is an I/O Fencing agent for KubeVirt."
7a42dc
+    docs["vendorurl"] = "https://kubevirt.io/"
7a42dc
+    show_docs(options, docs)
7a42dc
+
7a42dc
+    run_delay(options)
7a42dc
+
7a42dc
+    validate_options(['--namespace'], options)
7a42dc
+
7a42dc
+    # Disable insecure-certificate-warning message
7a42dc
+    if "--ssl-insecure" in options:
7a42dc
+        import urllib3
7a42dc
+        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
7a42dc
+
7a42dc
+    try:
7a42dc
+        from kubernetes import config
7a42dc
+        from openshift.dynamic import DynamicClient
7a42dc
+        kubeconfig = options.get('--kubeconfig')
7a42dc
+        k8s_client = config.new_client_from_config(config_file=kubeconfig)
7a42dc
+        conn = DynamicClient(k8s_client)
7a42dc
+    except ImportError:
7a42dc
+        logging.error("Couldn\'t import kubernetes.config or "
7a42dc
+                      "openshift.dynamic.DynamicClient - not found or not accessible")
7a42dc
+
7a42dc
+    # Operate the fencing device
7a42dc
+    result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list)
7a42dc
+    sys.exit(result)
7a42dc
+
7a42dc
+if __name__ == "__main__":
7a42dc
+	main()