This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch 4.11
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.11 by this push:
     new 13779dd  kvm: add support for custom KVM hook scripts (#2819)
13779dd is described below

commit 13779ddd2ee3d816271de681426243c005c1d8be
Author: ernjvr <ern...@gmail.com>
AuthorDate: Mon Aug 27 10:16:52 2018 +0200

    kvm: add support for custom KVM hook scripts (#2819)
    
    KVM hook script include - logic to execute custom scripts & logging 
requirements
    KVM hook script include - add logic to create custom directory if not 
exists & extra logging
---
 agent/bindir/libvirtqemuhook.in | 84 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 78 insertions(+), 6 deletions(-)

diff --git a/agent/bindir/libvirtqemuhook.in b/agent/bindir/libvirtqemuhook.in
index 55ab3e6..598968b 100755
--- a/agent/bindir/libvirtqemuhook.in
+++ b/agent/bindir/libvirtqemuhook.in
@@ -6,9 +6,7 @@
 # to you under the Apache License, Version 2.0 (the
 # "License"); you may not use this file except in compliance
 # with the License.  You may obtain a copy of the License at
-#
 #   http://www.apache.org/licenses/LICENSE-2.0
-#
 # Unless required by applicable law or agreed to in writing,
 # software distributed under the License is distributed on an
 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,6 +17,9 @@
 import logging
 import re
 import sys
+import os
+import subprocess
+from threading import Timer
 from xml.dom.minidom import parse
 from cloudutils.configFileOps import configFileOps
 from cloudutils.networkConfig import networkConfig
@@ -30,19 +31,24 @@ 
logging.basicConfig(filename='/var/log/libvirt/qemu-hook.log',
                     level=logging.INFO)
 logger = logging.getLogger('qemu-hook')
 
+customDir = "/etc/libvirt/hooks/custom"
+customDirPermissions = 0744
+timeoutSeconds = 10 * 60
+validQemuActions = ['prepare', 'start', 'started', 'stopped', 'release', 
'migrate', 'restore', 'reconnect', 'attach']
+
 def isOldStyleBridge(brName):
     if brName.find("cloudVirBr") == 0:
-       return True
+        return True
     else:
-       return False
+        return False
 
 def isNewStyleBridge(brName):
     if brName.startswith('brvx-'):
         return False
     if re.match(r"br(\w+)-(\d+)", brName) == None:
-       return False
+        return False
     else:
-       return True
+        return True
 
 def getGuestNetworkDevice():
     netlib = networkConfig()
@@ -71,6 +77,66 @@ def handleMigrateBegin():
         pass
 
 
+def executeCustomScripts(sysArgs):
+    createDirectoryIfNotExists(customDir, customDirPermissions)
+    scripts = getCustomScriptsFromDirectory()
+
+    for scriptName in scripts:
+        executeScript(scriptName, sysArgs)
+
+
+def executeScript(scriptName, sysArgs):
+    logger.info('Executing custom script: %s, parameters: %s' % (scriptName, ' 
'.join(map(str, sysArgs))))
+    path = customDir + os.path.sep + scriptName
+
+    if not os.access(path, os.X_OK):
+        logger.warning('Custom script: %s is not executable; skipping 
execution.' % scriptName)
+        return
+
+    try:
+        process = subprocess.Popen([path] + sysArgs, stdout=subprocess.PIPE,
+                                   stderr=subprocess.PIPE, shell=False)
+        try:
+            timer = Timer(timeoutSeconds, terminateProcess, [process, 
scriptName])
+            timer.start()
+            output, error = process.communicate()
+
+            if process.returncode == -15:
+                logger.error('Custom script: %s terminated after timeout of %s 
second[s].'
+                             % (scriptName, timeoutSeconds))
+                return
+            if process.returncode != 0:
+                logger.info('return code: %s' % str(process.returncode))
+                raise Exception(error)
+            logger.info('Custom script: %s finished successfully; output: 
\n%s' %
+                        (scriptName, str(output)))
+        finally:
+            timer.cancel()
+    except (OSError, Exception) as e:
+        logger.exception("Custom script: %s finished with error: \n%s" % 
(scriptName, e))
+
+
+def terminateProcess(process, scriptName):
+    logger.warning('Custom script: %s taking longer than %s second[s]; 
terminating..' % (scriptName, str(timeoutSeconds)))
+    process.terminate()
+
+
+def getCustomScriptsFromDirectory():
+    return sorted(filter(lambda fileName: (fileName is not None) & (fileName 
!= "") & ('_' in fileName) &
+                                          (fileName.startswith((action + '_')) 
| fileName.startswith(('all' + '_'))),
+                         os.listdir(customDir)), key=lambda fileName: 
substringAfter(fileName, '_'))
+
+
+def createDirectoryIfNotExists(dir, permissions):
+    if not os.path.exists(dir):
+        logger.info('Directory %s does not exist; creating it.' % dir)
+        os.makedirs(dir, permissions)
+
+
+def substringAfter(s, delimiter):
+    return s.partition(delimiter)[2]
+
+
 if __name__ == '__main__':
     if len(sys.argv) != 5:
         sys.exit(0)
@@ -79,5 +145,11 @@ if __name__ == '__main__':
     logger.debug("Executing qemu hook with args: %s" % sys.argv)
     action, status = sys.argv[2:4]
 
+    if action not in validQemuActions:
+        logger.error('The given action: %s, is not a valid libvirt qemu 
operation.' % action)
+        sys.exit(0)
+
     if action == "migrate" and status == "begin":
         handleMigrateBegin()
+
+    executeCustomScripts(sys.argv[1:])

Reply via email to