diff --git a/.gitignore b/.gitignore
index faaf506..0567bf4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,10 @@ tests/status_blob_url.py
build
dist
*.egg-info
+.vs/WALinuxAgent/v14/.suo
+WALinuxAgent.pyproj
+WALinuxAgent.pyproj.user
+WALinuxAgent.sln
.coverage
.ropeproject
diff --git a/Changelog b/Changelog
index 62bf4fc..919bd2d 100644
--- a/Changelog
+++ b/Changelog
@@ -1,5 +1,8 @@
WALinuxAgent Changelog
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+6 Jun 2016, WALinuxAgent 2.0.16
+ . add the support for the rdma driver installing/updating.
+|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5 Jun 2016, WALinuxAgent 2.0.16
. Handle 410 when reporting health
. Add timeout to http request
diff --git a/config/waagent.conf b/config/waagent.conf
index 081579b..2cc697b 100644
--- a/config/waagent.conf
+++ b/config/waagent.conf
@@ -84,3 +84,7 @@ OS.OpensslPath=None
#HttpProxy.Host=None
#HttpProxy.Port=None
+# If set, agent will try to update or check the rdma driver
+OS.UpdateRdmaDriver=y
+OS.CheckRdmaDriver=y
+OS.RdmaRepository=https://drivers.suse.com/microsoft/Microsoft-LIS-RDMA/sle-12/updates
diff --git a/waagent b/waagent
index 673a04c..4d2a95c 100644
--- a/waagent
+++ b/waagent
@@ -80,7 +80,7 @@ if not hasattr(subprocess,'check_output'):
subprocess.check_output=check_output
subprocess.CalledProcessError=CalledProcessError
-
+
GuestAgentName = "WALinuxAgent"
GuestAgentLongName = "Azure Linux Agent"
GuestAgentVersion = "WALinuxAgent-2.0.16"
@@ -192,7 +192,7 @@ class AbstractDistro(object):
self.shadow_file_mode=0600
self.shadow_file_path="/etc/shadow"
self.dhcp_enabled = False
-
+
def isSelinuxSystem(self):
"""
Checks and sets self.selinux = True if SELinux is available on system.
@@ -203,7 +203,7 @@ class AbstractDistro(object):
else:
self.selinux = True
return self.selinux
-
+
def isSelinuxRunning(self):
"""
Calls shell command 'getenforce' and returns True if 'Enforcing'.
@@ -212,7 +212,7 @@ class AbstractDistro(object):
return RunGetOutput("getenforce")[1].startswith("Enforcing")
else:
return False
-
+
def setSelinuxEnforce(self,state):
"""
Calls shell command 'setenforce' with 'state' and returns resulting exit code.
@@ -229,14 +229,14 @@ class AbstractDistro(object):
"""
if self.isSelinuxSystem():
return Run('chcon ' + cn + ' ' + path)
-
+
def setHostname(self,name):
"""
Shell call to hostname.
Returns resulting exit code.
"""
return Run('hostname ' + name)
-
+
def publishHostname(self,name):
"""
Set the contents of the hostname file to 'name'.
@@ -251,7 +251,7 @@ class AbstractDistro(object):
except:
return 1
return r
-
+
def installAgentServiceScriptFiles(self):
"""
Create the waagent support files for service installation.
@@ -267,7 +267,7 @@ class AbstractDistro(object):
Abstract Virtual Function. Over-ridden in concrete Distro classes.
"""
pass
-
+
def uninstallAgentService(self):
"""
Call service subsystem to remove waagent script.
@@ -281,19 +281,19 @@ class AbstractDistro(object):
"""
self.stopAgentService()
self.uninstallAgentService()
-
+
def startAgentService(self):
"""
Service call to start the Agent service
"""
return Run(self.service_cmd + ' ' + self.agent_service_name + ' start')
-
+
def stopAgentService(self):
"""
Service call to stop the Agent service
"""
return Run(self.service_cmd + ' ' + self.agent_service_name + ' stop',False)
-
+
def restartSshService(self):
"""
Service call to re(start) the SSH service
@@ -316,7 +316,7 @@ class AbstractDistro(object):
Error("Failed: " + fprint + ".crt -> " + path)
error = 1
return error
-
+
def checkPackageInstalled(self,p):
"""
Query package database for prescence of an installed package.
@@ -343,7 +343,7 @@ class AbstractDistro(object):
self.setSelinuxContext(filepath,'system_u:object_r:shadow_t:s0')
Log("Root password deleted.")
return 0
-
+
def changePass(self,user,password):
Log("Change user password")
crypt_id = Config.get("Provisioning.PasswordCryptId")
@@ -360,7 +360,7 @@ class AbstractDistro(object):
return self.chpasswd(user, password, crypt_id=crypt_id,
salt_len=salt_len)
-
+
def chpasswd(self, username, password, crypt_id=6, salt_len=10):
passwd_hash = self.gen_password_hash(password, crypt_id, salt_len)
cmd = "usermod -p '{0}' {1}".format(passwd_hash, username)
@@ -382,7 +382,7 @@ class AbstractDistro(object):
Generic function to remove ata_piix.ko.
"""
return WaAgent.TryUnloadAtapiix()
-
+
def deprovisionWarnUser(self):
"""
Generic user warnings used at deprovision.
@@ -404,7 +404,7 @@ class AbstractDistro(object):
except:
pass
return 0
-
+
def uninstallDeleteFiles(self):
"""
Files to delete when agent is uninstalled.
@@ -415,7 +415,7 @@ class AbstractDistro(object):
except:
pass
return 0
-
+
def checkDependencies(self):
"""
Generic dependency check.
@@ -575,7 +575,7 @@ class AbstractDistro(object):
if Run("LC_ALL=C fdisk -l " + dsk + " | grep Disk"):
return False
return True
-
+
def mountDVD(self,dvd,location):
return RunGetOutput(self.mount_dvd_cmd + ' ' + dvd + ' ' + location)
@@ -652,7 +652,7 @@ class AbstractDistro(object):
def getConfigurationPath(self):
return "/etc/waagent.conf"
-
+
def getProcessorCores(self):
return int(RunGetOutput("grep 'processor.*:' /proc/cpuinfo |wc -l")[1])
@@ -691,6 +691,38 @@ class AbstractDistro(object):
Run("/sbin/route add -net " + net + " netmask " + mask + " gw " + gateway,
chk_err=False)
+ def getNdDriverVersion(self):
+ """
+ if error happens, raise a RdmaError
+ """
+ try:
+ with open("/var/lib/hyperv/.kvp_pool_0", "r") as f:
+ lines = f.read()
+ r = re.search("NdDriverVersion\0+(\d\d\d\.\d)", lines)
+ if r is not None:
+ NdDriverVersion = r.groups()[0]
+ return NdDriverVersion #e.g. NdDriverVersion = 142.0
+ else :
+ Log("Error: NdDriverVersion not found.")
+ return None
+ except Exception as e:
+ errMsg = 'Cannot update status: Failed to enable the extension with error: %s, stack trace: %s' % (str(e), traceback.format_exc())
+ Log(errMsg)
+ raise RdmaError(RdmaConfig.nd_driver_detect_error)
+
+ def checkInstallHyperV(self):
+ return None
+
+ def getRdmaPackageVersion(self):
+ return None
+
+ def rdmaUpdate(self,updateRdmaRepository=None):
+ Log("rdmaUpdate in base class")
+ pass
+
+ def checkRDMA(self):
+ Log("checkRDMA in base class")
+ pass
############################################################
# GentooDistro
@@ -712,6 +744,7 @@ depend()
}
"""
+
class gentooDistro(AbstractDistro):
"""
Gentoo distro concrete class
@@ -889,21 +922,34 @@ class SuSEDistro(AbstractDistro):
"""
def __init__(self):
super(SuSEDistro,self).__init__()
- self.service_cmd='/sbin/service'
- self.ssh_service_name='sshd'
- self.kernel_boot_options_file='/boot/grub/menu.lst'
- self.hostname_file_path='/etc/HOSTNAME'
- self.requiredDeps += [ "/sbin/insserv" ]
- self.init_file=suse_init_file
- self.dhcp_client_name='dhcpcd'
- if ((DistInfo(fullname=1)[0] == 'SUSE Linux Enterprise Server' and DistInfo()[1] >= '12') or \
- (DistInfo(fullname=1)[0] == 'openSUSE' and DistInfo()[1] >= '13.2')):
- self.dhcp_client_name='wickedd-dhcp4'
+ dist_info = DistInfo()
+ dist_info_fullname = DistInfo(fullname=1)
+
+ self.dhcp_client_name = 'dhcpcd'
+ if ((dist_info_fullname[0] == 'SUSE Linux Enterprise Server' and dist_info[1] >= '12') or \
+ (dist_info_fullname[0] == 'openSUSE' and dist_info[1] >= '13.2')):
+ self.dhcp_client_name = 'wickedd-dhcp4'
+ self.dhcp_enabled = True
self.grubKernelBootOptionsFile = '/boot/grub/menu.lst'
self.grubKernelBootOptionsLine = 'kernel'
- self.getpidcmd='pidof '
- self.dhcp_enabled=True
-
+ self.getpidcmd = 'pidof '
+ self.hostname_file_path = '/etc/HOSTNAME'
+ self.init_file = suse_init_file
+ self.kernel_boot_options_file = '/boot/grub/menu.lst'
+ self.modprobe_path = '/usr/bin/modprobe'
+
+ self.requiredDeps += [ "/sbin/insserv" ]
+ self.reboot_path = '/sbin/reboot'
+ self.rpm_path = '/bin/rpm'
+ self.service_cmd = '/sbin/service'
+ self.ssh_service_name ='sshd'
+ if(dist_info[1] == "11"):
+ self.ps_path = '/bin/ps'
+ else:
+ self.ps_path = '/usr/bin/ps'
+
+ self.zypper_path = '/usr/bin/zypper'
+
def checkPackageInstalled(self,p):
if Run("rpm -q " + p,chk_err=False):
return 0
@@ -915,7 +961,6 @@ class SuSEDistro(AbstractDistro):
return 1
else:
return 0
-
def installAgentServiceScriptFiles(self):
try:
@@ -923,7 +968,7 @@ class SuSEDistro(AbstractDistro):
os.chmod(self.init_script_file, 0744)
except:
pass
-
+
def registerAgentService(self):
self.installAgentServiceScriptFiles()
return Run('insserv ' + self.agent_service_name)
@@ -940,7 +985,137 @@ class SuSEDistro(AbstractDistro):
def stopDHCP(self):
Run("service " + self.dhcp_client_name + " stop", chk_err=False)
-
+
+ def getRdmaPackageVersion(self):
+ """
+ """
+ error, output = RunGetOutput(self.zypper_path + " info " + RdmaConfig.rmda_package_name)
+ if(error == RdmaConfig.process_success):
+ r = re.search("Version: (\S+)", output)
+ if r is not None:
+ package_version = r.groups()[0] # e.g. package_version is "20150707.140.0_k3.12.28_4-3.1."
+ return package_version
+ else:
+ return None
+ else:
+ return None
+
+ def checkInstallHyperV(self):
+ error, output = RunGetOutput(self.ps_path + " -ef")
+ if(error != RdmaConfig.process_success):
+ return RdmaConfig.common_failed
+ else:
+ hv_kvp_daemon_service_process_name = "hv_kvp_daemon"
+ hv_kvp_daemon_service_name = "hv_kvp_daemon"
+ r = re.search(hv_kvp_daemon_service_process_name, output)
+ if r is None :
+ # if the
+ Log("hv kvp daemon is not running.")
+ error,output = RunGetOutput(self.rpm_path + " -q hyper-v", chk_err=False,log_cmd=False)
+ if(error == RdmaConfig.process_success):
+ Log("the hyper-v package is installed, but hv_kvp_daemon not started")
+ return RdmaConfig.hv_kvp_daemon_not_started
+ else:
+ error,output = RunGetOutput(self.zypper_path + " -n install --force hyper-v")
+ Log("install hyper-v return code: " + str(error) + " output:" + str(output))
+ if(error != RdmaConfig.process_success):
+ return RdmaConfig.common_failed
+ else:
+ self.rebootMachine()
+ return RdmaConfig.process_success
+ else :
+ Log("KVP daemon is running")
+ return RdmaConfig.process_success
+
+ def rdmaUpdate(self,updateRdmaRepository=None):
+ # give some time for the hv_hvp_daemon to start up.
+ time.sleep(10)
+ check_install_result = self.checkInstallHyperV()
+ if(check_install_result == RdmaConfig.process_success):
+ # wait for sometime the RDMA Driver not passed in by KVP in time.
+ time.sleep(10)
+
+ nd_driver_version = self.getNdDriverVersion()
+ if(nd_driver_version is None):
+ raise RdmaError(RdmaConfig.driver_version_not_found)
+ else:
+ check_result = self.checkRDMA(nd_driver_version=nd_driver_version)
+ Log("RDMA version check result is " + str(check_result))
+ if(check_result == RdmaConfig.UpToDate):
+ return
+ elif(check_result == RdmaConfig.OutOfDate):
+ update_rdma_driver_result = self.rdmaUpdatePackage(host_version=nd_driver_version,updateRdmaRepository=updateRdmaRepository)
+ elif(check_result == RdmaConfig.DriverVersionNotFound):
+ raise RdmaError(RdmaConfig.driver_version_not_found)
+ elif(check_result == RdmaConfig.Unknown):
+ raise RdmaError(RdmaConfig.unknown_error)
+ else:
+ raise RdmaError(RdmaConfig.check_install_hv_utils_failed)
+
+ def rdmaUpdatePackage(self, host_version, updateRdmaRepository = None):
+ # check the repository first
+ if(updateRdmaRepository is not None):
+ error,output = RunGetOutput(self.zypper_path + " lr -u")
+ rdma_pack_repository_name = "msft-rdma-pack"
+ rdma_pack_result = re.search(rdma_pack_repository_name, output)
+ if rdma_pack_result is None :
+ Log("rdma_pack_result is None")
+ error, output = RunGetOutput(self.zypper_path + " ar " + str(updateRdmaRepository) + " " + rdma_pack_repository_name)
+ #wait for the cache build.
+ time.sleep(20)
+ Log("error result is " + str(error) + " output is : " + str(output))
+ else:
+ Log("output is: " + str(output))
+ Log("msft-rdma-pack found")
+
+ returnCode, message = RunGetOutput(self.zypper_path + " --no-gpg-checks refresh")
+ Log("refresh repo return code is " + str(returnCode) + " output is: " + str(message))
+ #install the wrapper package, that will put the driver RPM packages under /opt/microsoft/rdma
+ returnCode, message = RunGetOutput(self.zypper_path + " -n remove " + RdmaConfig.wrapper_package_name)
+ Log("remove wrapper package return code is " + str(returnCode) + " output is: " + str(message))
+ returnCode, message = RunGetOutput(self.zypper_path + " --non-interactive install --force " + RdmaConfig.wrapper_package_name)
+ Log("install wrapper package return code is " + str(returnCode) + " output is: " + str(message))
+ r = os.listdir("/opt/microsoft/rdma")
+ if r is not None :
+ for filename in r :
+ if re.match(RdmaConfig.rmda_package_name + "-\d{8}\.(%s).+" % host_version, filename) :
+ error, output = RunGetOutput(self.zypper_path + " --non-interactive remove " + RdmaConfig.rmda_package_name)
+ Log("remove rdma package result is " + str(error) + " output is: " + str(output))
+ Log("Installing RPM /opt/microsoft/rdma/" + filename)
+ error, output = RunGetOutput(self.zypper_path + " --non-interactive install --force /opt/microsoft/rdma/%s" % filename)
+ Log("Install rdma package result is " + str(error) + " output is: " + str(output))
+ if(error == RdmaConfig.process_success):
+ self.rebootMachine()
+ else:
+ raise RdmaError(RdmaConfig.package_install_failed)
+ else:
+ Log("RDMA drivers not found in /opt/microsoft/rdma")
+ raise RdmaError(RdmaConfig.package_not_found)
+
+ def checkRDMA(self, nd_driver_version = None):
+ if(nd_driver_version is None):
+ nd_driver_version = self.getNdDriverVersion()
+ if(nd_driver_version is None or nd_driver_version == ""):
+ return RdmaConfig.DriverVersionNotFound
+ package_version = self.getRdmaPackageVersion()
+ if(package_version is None or package_version == ""):
+ return RdmaConfig.OutOfDate
+ else:
+ # package_version would be like this :20150707_k3.12.28_4-3.1 20150707.140.0_k3.12.28_4-1.1
+ # nd_driver_version 140.0
+ Log("nd_driver_version is " + str(nd_driver_version) + " package_version is " + str(package_version))
+ if(nd_driver_version is not None):
+ r = re.match("^[0-9]+[.](%s).+" % nd_driver_version, package_version)# NdDriverVersion should be at the end of package version
+ if not r : #host ND version is the same as the package version, do an update
+ return RdmaConfig.OutOfDate
+ else:
+ return RdmaConfig.UpToDate
+ return RdmaConfig.Unknown
+
+ def rebootMachine(self):
+ Log("rebooting the machine")
+ RunGetOutput(self.reboot_path)
+
############################################################
# redhatDistro
############################################################
@@ -1001,7 +1176,6 @@ case "$1" in
esac
exit $RETVAL
"""
-
class redhatDistro(AbstractDistro):
"""
Redhat Distro concrete class
@@ -1040,14 +1214,14 @@ class redhatDistro(AbstractDistro):
def registerAgentService(self):
self.installAgentServiceScriptFiles()
return Run('chkconfig --add waagent')
-
+
def uninstallAgentService(self):
return Run('chkconfig --del ' + self.agent_service_name)
def unregisterAgentService(self):
self.stopAgentService()
return self.uninstallAgentService()
-
+
def checkPackageInstalled(self,p):
if Run("yum list installed " + p,chk_err=False):
return 0
@@ -1091,6 +1265,12 @@ class centosDistro(redhatDistro):
def __init__(self):
super(centosDistro,self).__init__()
+ def rdmaUpdate(self,updateRdmaRepository=None):
+ pass
+
+ def checkRDMA(self):
+ pass
+
############################################################
# oracleDistro
############################################################
@@ -1103,8 +1283,6 @@ class oracleDistro(redhatDistro):
def __init__(self):
super(oracleDistro, self).__init__()
-
-
############################################################
# asianuxDistro
############################################################
@@ -1117,7 +1295,6 @@ class asianuxDistro(redhatDistro):
def __init__(self):
super(asianuxDistro,self).__init__()
-
############################################################
# CoreOSDistro
############################################################
@@ -1325,7 +1502,6 @@ esac
exit 0
"""
-
class debianDistro(AbstractDistro):
"""
debian Distro concrete class
@@ -1352,7 +1528,7 @@ class debianDistro(AbstractDistro):
return 1
else:
return 0
-
+
def checkDependencies(self):
"""
Debian dependency check. python-pyasn1 is NOT needed.
@@ -1373,7 +1549,7 @@ class debianDistro(AbstractDistro):
return 1
else:
return 0
-
+
def installAgentServiceScriptFiles(self):
"""
If we are packaged - the service name is walinuxagent, do nothing.
@@ -1387,20 +1563,20 @@ class debianDistro(AbstractDistro):
ErrorWithPrefix('installAgentServiceScriptFiles','Exception: '+str(e)+' occured creating ' + self.init_script_file)
return 1
return 0
-
+
def registerAgentService(self):
if self.installAgentServiceScriptFiles() == 0:
return Run('update-rc.d waagent defaults')
else :
return 1
-
+
def uninstallAgentService(self):
return Run('update-rc.d -f ' + self.agent_service_name + ' remove')
def unregisterAgentService(self):
self.stopAgentService()
return self.uninstallAgentService()
-
+
def sshDeployPublicKey(self,fprint,path):
"""
We support PKCS8.
@@ -1409,7 +1585,7 @@ class debianDistro(AbstractDistro):
return 1
else :
return 0
-
+
############################################################
# KaliDistro - WIP
# Functioning on Kali 1.1.0a so far
@@ -1452,7 +1628,6 @@ end script
exec /usr/sbin/waagent -daemon
"""
-
class UbuntuDistro(debianDistro):
"""
Ubuntu Distro concrete class
@@ -1468,7 +1643,7 @@ class UbuntuDistro(debianDistro):
def registerAgentService(self):
return self.installAgentServiceScriptFiles()
-
+
def uninstallAgentService(self):
"""
If we are packaged - the service name is walinuxagent, do nothing.
@@ -1532,7 +1707,6 @@ class UbuntuDistro(debianDistro):
Error("Can't find host key: {0}".format(path))
return False
-
############################################################
# LinuxMintDistro
############################################################
@@ -1803,7 +1977,7 @@ class FreeBSDDistro(AbstractDistro):
self.mount_dvd_cmd = 'dd bs=2048 count=33 skip=295 if=' # custom data max len is 64k
self.sudoers_dir_base = '/usr/local/etc'
self.waagent_conf_file = FreeBSDWaagentConf
-
+
def installAgentServiceScriptFiles(self):
SetFileContents(self.init_script_file, self.init_file)
os.chmod(self.init_script_file, 0777)
@@ -1814,7 +1988,6 @@ class FreeBSDDistro(AbstractDistro):
self.installAgentServiceScriptFiles()
return Run("services_mkdb " + self.init_script_file)
-
def sshDeployPublicKey(self,fprint,path):
"""
We support PKCS8.
@@ -2001,7 +2174,7 @@ class FreeBSDDistro(AbstractDistro):
ChangeOwner(dir + "/authorized_keys", user)
Log("Created user account: " + user)
return None
-
+
def DeleteAccount(self,user):
"""
Delete the 'user'.
@@ -2091,12 +2264,12 @@ class FreeBSDDistro(AbstractDistro):
Log("Configured SSH client probing to keep connections alive.")
#ApplyVNUMAWorkaround()
return 0
-
+
def mediaHasFilesystem(self,dsk):
if Run('LC_ALL=C fdisk -p ' + dsk + ' | grep "invalid fdisk partition table found" ',False):
return False
return True
-
+
def mountDVD(self,dvd,location):
#At this point we cannot read a joliet option udf DVD in freebsd10 - so we 'dd' it into our location
retcode,out = RunGetOutput(self.mount_dvd_cmd + dvd + ' of=' + location + '/ovf-env.xml')
@@ -2132,10 +2305,10 @@ class FreeBSDDistro(AbstractDistro):
def getProcessorCores(self):
return int(RunGetOutput("sysctl hw.ncpu | awk '{print $2}'")[1])
-
+
def getTotalMemory(self):
return int(RunGetOutput("sysctl hw.realmem | awk '{print $2}'")[1])/1024
-
+
def setDefaultGateway(self, gateway):
Run("/sbin/route add default " + gateway, chk_err=False)
@@ -2270,7 +2443,7 @@ def RunGetOutput(cmd, chk_err=True, log_cmd=True):
"""
if log_cmd:
LogIfVerbose(cmd)
- try:
+ try:
output=subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True)
except subprocess.CalledProcessError,e :
if chk_err and log_cmd:
@@ -2520,13 +2693,13 @@ class Logger(object):
self.file_path=filepath
self.con_path=conpath
self.verbose=verbose
-
+
def ThrottleLog(self,counter):
"""
Log everything up to 10, every 10 up to 100, then every 100.
"""
return (counter < 10) or ((counter < 100) and ((counter % 10) == 0)) or ((counter % 100) == 0)
-
+
def LogToFile(self,message):
"""
Write 'message' to logfile.
@@ -2539,7 +2712,7 @@ class Logger(object):
except IOError, e:
print e
pass
-
+
def LogToCon(self,message):
"""
Write 'message' to /dev/console.
@@ -2553,14 +2726,14 @@ class Logger(object):
C.write(message.encode('ascii','ignore') + "\n")
except IOError, e:
pass
-
+
def Log(self,message):
"""
Standard Log function.
Logs to self.file_path, and con_path
"""
self.LogWithPrefix("", message)
-
+
def LogWithPrefix(self,prefix, message):
"""
Prefix each line of 'message' with current time+'prefix'.
@@ -2572,19 +2745,19 @@ class Logger(object):
line = t + line
self.LogToFile(line)
self.LogToCon(line)
-
+
def NoLog(self,message):
"""
Don't Log.
"""
pass
-
+
def LogIfVerbose(self,message):
"""
Only log 'message' if global Verbose is True.
"""
self.LogWithPrefixIfVerbose('',message)
-
+
def LogWithPrefixIfVerbose(self,prefix, message):
"""
Only log 'message' if global Verbose is True.
@@ -2598,26 +2771,26 @@ class Logger(object):
line = t + line
self.LogToFile(line)
self.LogToCon(line)
-
+
def Warn(self,message):
"""
Prepend the text "WARNING:" to the prefix for each line in 'message'.
"""
self.LogWithPrefix("WARNING:", message)
-
+
def Error(self,message):
"""
Call ErrorWithPrefix(message).
"""
ErrorWithPrefix("", message)
-
+
def ErrorWithPrefix(self,prefix, message):
"""
Prepend the text "ERROR:" to the prefix for each line in 'message'.
Errors written to logfile, and /dev/console
"""
self.LogWithPrefix("ERROR:", message)
-
+
def LoggerInit(log_file_path,log_con_path,verbose=False):
"""
Create log object and export its methods to global scope.
@@ -2764,7 +2937,7 @@ def DoInstallRHUIRPM():
return
Log("install RHUI RPM completed")
-
+
class Util(object):
"""
Http communication class.
@@ -3108,7 +3281,7 @@ class TCPHandler(SocketServer.BaseRequestHandler):
log("Received LB probe # " + strCounter)
self.request.recv(1024)
self.request.send("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nContent-Type: text/html\r\nDate: " + self.GetHttpDateTimeNow() + "\r\n\r\nOK")
-
+
class LoadBalancerProbeServer(object):
"""
Threaded object to receive and send LB probe messages.
@@ -3140,9 +3313,6 @@ class ConfigurationProvider(object):
"""
def __init__(self, walaConfigFile):
self.values = dict()
- if 'MyDistro' not in globals():
- global MyDistro
- MyDistro = GetMyDistro()
if walaConfigFile is None:
walaConfigFile = MyDistro.getConfigurationPath()
if os.path.isfile(walaConfigFile) == False:
@@ -3164,6 +3334,20 @@ class ConfigurationProvider(object):
def get(self, key):
return self.values.get(key)
+ def yes(self,key):
+ configValue = self.get(key)
+ if(configValue is not None and configValue.lower().startswith("y")):
+ return True
+ else:
+ return False
+
+ def no(self,key):
+ configValue = self.get(key)
+ if(configValue is not None and configValue.lower().startswith("n")):
+ return True
+ else:
+ return False
+
class EnvMonitor(object):
"""
Montor changes to dhcp and hostname.
@@ -3440,8 +3624,35 @@ class SharedConfig(object):
rdma_configured = False
+class RdmaConfig(object):
+ """
+ configurations
+ """
+ wrapper_package_name = 'msft-rdma-drivers'
+ rmda_package_name = 'msft-lis-rdma-kmp-default'
+ """
+ error code definitions
+ """
+ process_success = 0
+ common_failed = 1
+ check_install_hv_utils_failed = 2
+ nd_driver_detect_error = 3
+ driver_version_not_found = 4
+ unknown_error = 5
+ package_not_found = 6
+ package_install_failed = 7
+ hv_kvp_daemon_not_started = 8
+ """
+ check_rdma_result
+ """
+ UpToDate = 0
+ OutOfDate = 1
+ DriverVersionNotFound = 3
+ Unknown = -1
+
class RdmaError(Exception):
- pass
+ def __init__(self, error_code = RdmaConfig.process_success):
+ self.error_code = error_code
class RdmaHandler(object):
"""
@@ -4139,7 +4350,6 @@ class ExtensionsConfig(object):
continue
return str(seq_no)
-
def GenerateAggStatus(self, name, version, reportHeartbeat = False):
"""
Generate the status which Azure can understand by the status and heartbeat reported by extension
@@ -4198,7 +4408,6 @@ class ExtensionsConfig(object):
agg_status_string = json.dumps(agg_status_obj)
LogIfVerbose("Handler Aggregated Status:" + agg_status_string)
return agg_status_string
-
def SetHandlerState(self, handler, state=''):
zip_dir=LibDir+"/" + handler
@@ -4222,7 +4431,6 @@ class ExtensionsConfig(object):
else:
return 'NotInstalled'
-
class HostingEnvironmentConfig(object):
"""
Parse Hosting enviromnet config and store in
@@ -4509,7 +4717,7 @@ class GoalState(Util):
LogIfVerbose("Process goalstate")
self.HostingEnvironmentConfig.Process()
self.SharedConfig.Process()
-
+
class OvfEnv(object):
"""
Read, and process provisioning info from provisioning file OvfEnv.xml
@@ -4780,13 +4988,10 @@ class OvfEnv(object):
MyDistro.restartSshService()
return error
-
-class WALAEvent(object):
+class WALAEvent(object):
def __init__(self):
-
self.providerId=""
self.eventId=1
-
self.OpcodeName=""
self.KeywordName=""
self.TaskName=""
@@ -4815,7 +5020,7 @@ class WALAEvent(object):
for attName in self.__dict__:
if attName in ["eventId","filedCount","providerId"]:
continue
-
+
attValue = self.__dict__[attName]
if type(attValue) is int:
strEventsData+=strRecordFormat.format(attName,attValue,strMtUInt64)
@@ -4834,7 +5039,7 @@ class WALAEvent(object):
if type(attValue) is float:
strEventsData+=strRecordFormat.format(attName,attValue,strMtFloat)
continue
-
+
Log("Warning: property "+attName+":"+str(type(attValue))+":type"+str(type(attValue))+"Can't convert to events data:"+":type not supported")
return u"{0}{1}{2}".format(strProviderid,strEventid,strEventsData)
@@ -4846,13 +5051,12 @@ class WALAEvent(object):
os.chmod(eventfolder,0700)
if len(os.listdir(eventfolder)) > 1000:
raise Exception("WriteToFolder:Too many file under "+eventfolder+" exit")
-
+
filename = os.path.join(eventfolder,str(int(time.time()*1000000)))
with open(filename+".tmp",'wb+') as hfile:
hfile.write(self.ToXml().encode("utf-8"))
os.rename(filename+".tmp",filename+".tld")
-
class WALAEventOperation:
HeartBeat="HeartBeat"
Provision = "Provision"
@@ -4862,7 +5066,7 @@ class WALAEventOperation:
Enable = "Enable"
Download = "Download"
Upgrade = "Upgrade"
- Update = "Update"
+ Update = "Update"
def AddExtensionEvent(name,op,isSuccess,duration=0,version="1.0",message="",type="",isInternal=False):
event = ExtensionEvent()
@@ -4878,8 +5082,7 @@ def AddExtensionEvent(name,op,isSuccess,duration=0,version="1.0",message="",type
event.Save()
except:
Error("Error "+traceback.format_exc())
-
-
+
class ExtensionEvent(WALAEvent):
def __init__(self):
@@ -4894,8 +5097,7 @@ class ExtensionEvent(WALAEvent):
self.ExtensionType=""
self.Message=""
self.Duration=0
-
-
+
class WALAEventMonitor(WALAEvent):
def __init__(self,postMethod):
WALAEvent.__init__(self)
@@ -4908,7 +5110,7 @@ class WALAEventMonitor(WALAEvent):
eventThread = threading.Thread(target = self.EventsLoop)
eventThread.setDaemon(True)
eventThread.start()
-
+
def EventsLoop(self):
LastReportHeartBeatTime = datetime.datetime.min
try:
@@ -4921,7 +5123,7 @@ class WALAEventMonitor(WALAEvent):
time.sleep(60)
except:
Error("Exception in events loop:"+traceback.format_exc())
-
+
def SendEvent(self,providerid,events):
dataFormat = u'{1}'\
''
@@ -4983,7 +5185,6 @@ class WALAEventMonitor(WALAEvent):
self.SendEvent(key,events[key])
if eventSendNumber%3 == 0:
time.sleep(15)
-
def AddSystemInfo(self,eventData):
if not self.issysteminfoinitilized:
@@ -5011,8 +5212,7 @@ class WALAEventMonitor(WALAEvent):
if self.sysInfo.get(name):
node.setAttribute("Value",xml.sax.saxutils.escape(str(self.sysInfo[name])))
- return eventObject.toxml()
-
+ return eventObject.toxml()
class Agent(Util):
"""
@@ -5529,7 +5729,7 @@ class Agent(Util):
return 1
Log("Loaded " + krn_pth + " driver for ATAPI CD-ROM")
-
+
# we have succeeded loading the ata_piix mod if it can be done.
def SearchForVMMStartup(self):
@@ -5579,7 +5779,7 @@ class Agent(Util):
Log("VMM Init script not found. Provisioning for Azure")
return
-
+
def Provision(self):
"""
Responible for:
@@ -5716,7 +5916,6 @@ class Agent(Util):
self.Endpoint = self.DoDhcpWork()
while self.Endpoint == None:
- Log("Azure environment not detected.")
Log("Retry environment detection in 60 seconds")
time.sleep(60)
self.Endpoint = self.DoDhcpWork()
@@ -5732,25 +5931,44 @@ class Agent(Util):
MyDistro.initScsiDiskTimeout()
global provisioned
global provisionError
-
+
global Openssl
Openssl = Config.get("OS.OpensslPath")
if Openssl == None:
Openssl = "openssl"
self.TransportCert = self.GenerateTransportCert()
-
+
eventMonitor = None
incarnation = None # goalStateIncarnationFromHealthReport
currentPort = None # loadBalancerProbePort
goalState = None # self.GoalState, instance of GoalState
provisioned = os.path.exists(LibDir + "/provisioned")
program = Config.get("Role.StateConsumer")
- provisionError = None
+ provisionError = None
lbProbeResponder = True
- setting = Config.get("LBProbeResponder")
- if setting != None and setting.lower().startswith("n"):
+
+ lbProbeResponderNo = Config.no("LBProbeResponder")
+ if lbProbeResponderNo:
lbProbeResponder = False
+
+ try:
+ updateRdmaDriverConfigured = Config.yes("OS.UpdateRdmaDriver")
+ updateRdmaRepository = Config.get("OS.RdmaRepository")
+ if(updateRdmaDriverConfigured):
+ MyDistro.rdmaUpdate(updateRdmaRepository)
+ else:
+ Log("OS.UpdateRdmaDriver configured to "+str(updateRdmaDriverConfigured)+" so skip the rdma update.")
+ checkRdmaDriverConfigured = Config.yes("OS.CheckRdmaDriver")
+ if(checkRdmaDriverConfigured):
+ checkRdmaResult = MyDistro.checkRDMA()
+ Log("Rdma check result is " + str(checkRdmaResult))
+ else:
+ Log("OS.CheckRdmaDriver configured to "+str(checkRdmaDriverConfigured)+" so skip the rdma check.")
+ except Exception as e:
+ errMsg = 'check or update Rdma driver failed with error: %s, stack trace: %s' % (str(e), traceback.format_exc())
+ Error(errMsg)
+
while True:
if (goalState == None) or (incarnation == None) or (goalState.Incarnation != incarnation):
try:
@@ -5848,18 +6066,16 @@ class Agent(Util):
#Agent report handler status every 25 seconds. Reduce the log entries by adding a count
Log("Successfully reported handler status")
reportHandlerStatusCount += 1
-
global LinuxDistro
if LinuxDistro == "redhat":
DoInstallRHUIRPM()
-
+
if not eventMonitor:
eventMonitor = WALAEventMonitor(self.HttpPostWithHeaders)
eventMonitor.StartEventsLoop()
time.sleep(25 - sleepToReduceAccessDenied)
-
WaagentLogrotate = """\
/var/log/waagent.log {
monthly
@@ -5979,7 +6195,7 @@ def ApplyVNUMAWorkaround():
Log("Your kernel version " + platform.release() + " has a NUMA-related bug: NUMA has been disabled.")
else :
"Error adding 'numa=off'. NUMA has not been disabled."
-
+
def RevertVNUMAWorkaround():
"""
Remove 'numa=off' from kernel boot options.
@@ -6167,8 +6383,6 @@ def Usage():
print("usage: " + sys.argv[0] + " [-verbose] [-force] [-help|-install|-uninstall|-deprovision[+user]|-version|-serialconsole|-daemon]")
return 0
-
-
def main():
"""
Instantiate MyDistro, exit if distro class is not defined.
@@ -6186,9 +6400,9 @@ def main():
LoggerInit('/var/log/waagent.log','/dev/console')
global LinuxDistro
LinuxDistro=DistInfo()[0]
-
+
global MyDistro
- MyDistro=GetMyDistro()
+ MyDistro = GetMyDistro()
if MyDistro == None :
sys.exit(1)
args = []
@@ -6246,7 +6460,7 @@ def main():
sys.exit(Usage())
global modloaded
modloaded = False
-
+
while True:
try:
SwitchCwd()
@@ -6261,6 +6475,5 @@ def main():
Error("Exception: " + str(e))
Log("Restart agent in 15 seconds")
time.sleep(15)
-
if __name__ == '__main__' :
main()