diff options
author | Ben Howard <ben.howard@ubuntu.com> | 2013-03-21 12:57:08 -0600 |
---|---|---|
committer | usd-importer <ubuntu-server@lists.ubuntu.com> | 2013-03-26 22:33:20 +0000 |
commit | 571bdcfe4b3d37c0fc94689d511712c2a0a13b69 (patch) | |
tree | 3c8b1b9ef1a85c122f210c91e7e2527533a56386 /waagent | |
parent | 608a9999c43d3500a13f03621c3982db505ec781 (diff) | |
download | vyos-walinuxagent-571bdcfe4b3d37c0fc94689d511712c2a0a13b69.tar.gz vyos-walinuxagent-571bdcfe4b3d37c0fc94689d511712c2a0a13b69.zip |
Import patches-unapplied version 1.3.2-0ubuntu1 to ubuntu/raring-proposed
Imported using git-ubuntu import.
Changelog parent: 608a9999c43d3500a13f03621c3982db505ec781
New changelog entries:
* Updated to 1.3.2 as part of Windows Azure requirement (LP: #1158465).
* Upstream now supports packaging; incorporated upstream packaging into
Ubuntu Packaging.
Diffstat (limited to 'waagent')
-rw-r--r-- | waagent | 236 |
1 files changed, 164 insertions, 72 deletions
@@ -43,15 +43,15 @@ import threading import time import traceback import xml.dom.minidom -import commands - + GuestAgentName = "WALinuxAgent" GuestAgentLongName = "Windows Azure Linux Agent" -GuestAgentVersion = "WALinuxAgent-1.3" +GuestAgentVersion = "WALinuxAgent-1.3.2" ProtocolVersion = "2011-12-31" Config = None LinuxDistro = "UNKNOWN" +PackagedForDistro = "UNKNOWN" Verbose = False WaAgent = None DiskActivated = False @@ -65,6 +65,34 @@ VarLibDhcpDirectories = ["/var/lib/dhclient", "/var/lib/dhcpcd", "/var/lib/dhcp" EtcDhcpClientConfFiles = ["/etc/dhcp/dhclient.conf", "/etc/dhcp3/dhclient.conf"] LibDir = "/var/lib/waagent" +# backport subprocess.check_output if not defined ( for python version < 2.7) +if not hasattr(subprocess,'check_output'): + def check_output(*popenargs, **kwargs): + r"""Backport from subprocess module from python 2.7""" + if 'stdout' in kwargs: + raise ValueError('stdout argument not allowed, it will be overridden.') + process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + raise subprocess.CalledProcessError(retcode, cmd, output=output) + return output + + # Exception classes used by this module. + class CalledProcessError(Exception): + def __init__(self, returncode, cmd, output=None): + self.returncode = returncode + self.cmd = cmd + self.output = output + def __str__(self): + return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) + + subprocess.check_output=check_output + subprocess.CalledProcessError=CalledProcessError + # This lets us index into a string or an array of integers transparently. def Ord(a): if type(a) == type("a"): @@ -79,11 +107,24 @@ def IsLinux(): def DetectLinuxDistro(): global LinuxDistro + global PackagedForDistro if os.path.isfile("/etc/redhat-release"): LinuxDistro = "RedHat" return True if os.path.isfile("/etc/lsb-release") and "Ubuntu" in GetFileContents("/etc/lsb-release"): LinuxDistro = "Ubuntu" + + # Should this run as if it is packaged Ubuntu? + try: + cmd="dpkg -S %s" % os.path.basename(__file__) + retcode, krn = RunGetOutput(cmd,chk_err=False) + if not retcode: + PackagedForDistro = "Ubuntu" + + except IOError as e: + pass + + return True if os.path.isfile("/etc/debian_version"): LinuxDistro = "Debian" @@ -99,12 +140,21 @@ def IsRedHat(): def IsUbuntu(): return "Ubuntu" in LinuxDistro +def IsPackagedUbuntu(): + return "Ubuntu" in PackagedForDistro + def IsDebian(): return IsUbuntu() or "Debian" in LinuxDistro def IsSuse(): return "Suse" in LinuxDistro +def IsPackaged(): + if PackagedForDistro == "UNKNOWN": + return False + + return True + def UsesRpm(): return IsRedHat() or IsSuse() @@ -161,23 +211,38 @@ def GetLineStartingWith(prefix, filepath): return line return None -def Run(a): - LogIfVerbose(a) - return os.system(a) +def Run(cmd,chk_err=True): + retcode,out=RunGetOutput(cmd,chk_err) + return retcode -def RunSafe(cmd): - Log(cmd) - # for python2.1 double try, in order to use a finally... +def RunGetOutput(cmd,chk_err=True): + LogIfVerbose(cmd) try: - try: - (exit_status,output) = commands.getstatusoutput(cmd) - except OSError,e : # just catch the exception and proceed - Log( ("OSError " + str(e) + " caught") ) - return exit_status,output - else: - return exit_status,output - finally: - pass + output=subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + except subprocess.CalledProcessError,e : + if chk_err : + Error('CalledProcessError. Error Code: ' + str(e.returncode) ) + Error('CalledProcessError. Command string: "' + e.cmd + '"') + Error('CalledProcessError. Command result: "' + e.output[:-1] + '"') + return e.returncode,e.output + return 0,output + +def RunSendStdin(cmd,input,chk_err=True): + LogIfVerbose(cmd+input) + try: + me=subprocess.Popen([cmd], shell=True, stdin=subprocess.PIPE,stderr=subprocess.STDOUT,stdout=subprocess.PIPE) + output=me.communicate(input) + except OSError,e : + if chk_err : + Error('CalledProcessError. Error Code:' + str(me.returncode)) + Error('CalledProcessError. Command string:"' + cmd + '"' ) + Error('CalledProcessError. Command result:"' + output[:-1] + '"') + return 1,output[0] + if me.returncode is not 0 and chk_err is True: + Error('CalledProcessError. Error Code:' + str(me.returncode)) + Error('CalledProcessError. Command string:"' + cmd + '"' ) + Error('CalledProcessError. Command result:"' + (output[0])[:-1] + '"') + return me.returncode,output[0] def GetNodeTextData(a): for b in a.childNodes: @@ -239,7 +304,7 @@ def CreateAccount(user, password, expiration, thumbprint): else: Log("CreateAccount: " + user + " already exists. Will update password.") if password != None: - os.popen("chpasswd", "w").write(user + ":" + password + "\n") + RunSendStdin("chpasswd",(user + ":" + password + "\n")) try: if password == None: SetFileContents("/etc/sudoers.d/waagent", user + " ALL = (ALL) NOPASSWD: ALL\n") @@ -349,7 +414,8 @@ def Logger(): class T(object): def __init__(self): self.File = None - + self.Con = None + self = T() def LogToFile(message): @@ -362,6 +428,13 @@ def Logger(): self.File.write(message + "\n") self.File.flush() + def LogToCon(message): + ConPath = '/dev/console' + if self.Con == None: + self.Con = open(ConPath, "a") + self.Con.write(message + "\n") + self.Con.flush() + def Log(message): LogWithPrefix("", message) @@ -371,9 +444,9 @@ def Logger(): t += prefix for line in message.split('\n'): line = t + line - print(line) LogToFile(line) - + LogToCon(line) + return Log, LogWithPrefix Log, LogWithPrefix = Logger() @@ -383,7 +456,7 @@ def NoLog(message): def LogIfVerbose(message): if Verbose == True: - Log(message) + LogFileWithPrefix('',message) def LogWithPrefixIfVerbose(prefix, message): if Verbose == True: @@ -393,10 +466,10 @@ def Warn(message): LogWithPrefix("WARNING:", message) def Error(message): - LogWithPrefix("ERROR:", message) + ErrorWithPrefix("", message) def ErrorWithPrefix(prefix, message): - LogWithPrefix("ERROR:" + prefix, message) + LogWithPrefix("ERROR:", message) def Linux_ioctl_GetIpv4Address(ifname): import fcntl @@ -433,7 +506,7 @@ def GetMacAddress(): if IsWindows(): # Windows: Physical Address. . . . . . . . . : 00-15-17-79-00-7F\n a = "ipconfig /all | findstr /c:\"Physical Address\" | findstr /v \"00-00-00-00-00-00-00\"" - a = os.popen(a).read() + a = os.popen(a).read() # not re-implementing wirh RunGetOutput - not called unless we're in windows a = re.sub("\s+$", "", a) a = re.sub(".+ ", "", a) a = re.sub(":", "", a) @@ -475,7 +548,7 @@ class Util(object): url = url[url.index("/"):] for retry in range(0, maxRetry + 1): strRetry = str(retry) - log = [NoLog, Log][retry > 0] + log = [NoLog, Error][retry > 0] log("retry HttpGet(" + url + "),retry=" + strRetry) response = None strStatus = "None" @@ -487,16 +560,16 @@ class Util(object): request = httpConnection.request("GET", url, None, headers) response = httpConnection.getresponse() strStatus = str(response.status) - except: - pass + except httplib.HTTPException, e: + Error('HTTPException ' + e.message + ' args: ' + repr(e.args)) log("response HttpGet(" + url + "),retry=" + strRetry + ",status=" + strStatus) if response == None or response.status != httplib.OK: Error("HttpGet(" + url + "),retry=" + strRetry + ",status=" + strStatus) if retry == maxRetry: - Log("return HttpGet(" + url + "),retry=" + strRetry + ",status=" + strStatus) + Error("return HttpGet(" + url + "),retry=" + strRetry + ",status=" + strStatus) return None else: - Log("sleep 10 seconds HttpGet(" + url + "),retry=" + strRetry + ",status=" + strStatus) + Error("sleep 10 seconds HttpGet(" + url + "),retry=" + strRetry + ",status=" + strStatus) time.sleep(10) else: log("return HttpGet(" + url + "),retry=" + strRetry + ",status=" + strStatus) @@ -519,7 +592,7 @@ class Util(object): maxRetry = 2 for retry in range(0, maxRetry + 1): strRetry = str(retry) - log = [NoLog, Log][retry > 0] + log = [NoLog, Error][retry > 0] log("retry HttpPost(" + url + "),retry=" + strRetry) response = None strStatus = "None" @@ -530,16 +603,16 @@ class Util(object): "x-ms-version": ProtocolVersion}) response = httpConnection.getresponse() strStatus = str(response.status) - except: - pass + except httplib.HTTPException, e: + Error('HTTPException ' + e.message + ' args: ' + repr(e.args)) log("response HttpPost(" + url + "),retry=" + strRetry + ",status=" + strStatus) if response == None or (response.status != httplib.OK and response.status != httplib.ACCEPTED): Error("HttpPost(" + url + "),retry=" + strRetry + ",status=" + strStatus) if retry == maxRetry: - Log("return HttpPost(" + url + "),retry=" + strRetry + ",status=" + strStatus) + Error("return HttpPost(" + url + "),retry=" + strRetry + ",status=" + strStatus) return None else: - Log("sleep 10 seconds HttpPost(" + url + "),retry=" + strRetry + ",status=" + strStatus) + Error("sleep 10 seconds HttpPost(" + url + "),retry=" + strRetry + ",status=" + strStatus) time.sleep(10) else: log("return HttpPost(" + url + "),retry=" + strRetry + ",status=" + strStatus) @@ -626,7 +699,7 @@ class EnvMonitor(object): dhcpcmd = "pidof dhcpcd" if IsDebian(): dhcpcmd = "pidof dhclient3" - dhcppid = os.popen(dhcpcmd).read() + dhcppid = RunGetOutput(dhcpcmd,chk_err=False)[1] while not self.shutdown: for a in RulesFiles: if os.path.isfile(a): @@ -640,7 +713,7 @@ class EnvMonitor(object): Log("EnvMonitor: Detected host name change: " + self.HostName + " -> " + socket.gethostname()) self.HostName = socket.gethostname() WaAgent.UpdateAndPublishHostName(self.HostName) - dhcppid = os.popen(dhcpcmd).read() + dhcppid = RunGetOutput(dhcpcmd,chk_err=False)[1] self.published = True except: pass @@ -648,7 +721,7 @@ class EnvMonitor(object): self.published = True pid = "" if not os.path.isdir("/proc/" + dhcppid.strip()): - pid = os.popen(dhcpcmd).read() + pid = RunGetOutput(dhcpcmd,chk_err=False)[1] if pid != "" and pid != dhcppid: Log("EnvMonitor: Detected dhcp client restart. Restoring routing table.") WaAgent.RestoreRoutes() @@ -733,8 +806,8 @@ class Certificates(object): index = 1 filename = str(index) + ".crt" while os.path.isfile(filename): - thumbprint = os.popen(Openssl + " x509 -in " + filename + " -fingerprint -noout").read().rstrip().split('=')[1].replace(':', '').upper() - pubkey=os.popen(Openssl + " x509 -in " + filename + " -pubkey -noout").read() + thumbprint = (RunGetOutput(Openssl + " x509 -in " + filename + " -fingerprint -noout")[1]).rstrip().split('=')[1].replace(':', '').upper() + pubkey=RunGetOutput(Openssl + " x509 -in " + filename + " -pubkey -noout")[1] keys[pubkey] = thumbprint os.rename(filename, thumbprint + ".crt") os.chmod(thumbprint + ".crt", 0600) @@ -745,7 +818,7 @@ class Certificates(object): index = 1 filename = str(index) + ".prv" while os.path.isfile(filename): - pubkey = os.popen(Openssl + " rsa -in " + filename + " -pubout").read() + pubkey = RunGetOutput(Openssl + " rsa -in " + filename + " -pubout 2> /dev/null")[1] os.rename(filename, keys[pubkey] + ".prv") os.chmod(keys[pubkey] + ".prv", 0600) if IsRedHat(): @@ -897,7 +970,7 @@ class HostingEnvironmentConfig(object): + "Content-Type: application/x-pkcs7-mime; name=\"password.p7m\"\n" + "Content-Transfer-Encoding: base64\n\n" + textwrap.fill(e, 64)) - return os.popen(Openssl + " cms -decrypt -in password.p7m -inkey Certificates.pem -recip Certificates.pem").read() + return RunGetOutput(Openssl + " cms -decrypt -in password.p7m -inkey Certificates.pem -recip Certificates.pem")[1] def ActivateResourceDisk(self): global DiskActivated @@ -914,7 +987,7 @@ class HostingEnvironmentConfig(object): Error("ActivateResourceDisk: Unable to detect disk topology.") return device = "/dev/" + device - for entry in os.popen("mount").read().split(): + for entry in RunGetOutput("mount")[1].split(): if entry.startswith(device + "1"): Log("ActivateResourceDisk: " + device + "1 is already mounted.") DiskActivated = True @@ -926,7 +999,7 @@ class HostingEnvironmentConfig(object): fs = Config.get("ResourceDisk.Filesystem") if fs == None: fs = "ext3" - if os.popen("sfdisk -q -c " + device + " 1").read().rstrip() == "7" and fs != "ntfs": + if RunGetOutput("sfdisk -q -c " + device + " 1")[1].rstrip() == "7" and fs != "ntfs": Run("sfdisk -c " + device + " 1 83") Run("mkfs." + fs + " " + device + "1") if Run("mount " + device + "1 " + mountpoint): @@ -1282,10 +1355,10 @@ class OvfEnv(object): GetFileContents(filepath).split('\n'))) + "PasswordAuthentication no\nChallengeResponseAuthentication no\n") Log("Disabled SSH password-based authentication methods.") if self.AdminPassword != None: - os.popen("chpasswd", "w").write("root:" + self.AdminPassword + "\n") + RunSendStdin("chpasswd",("root:" + self.AdminPassword + "\n")) if self.UserName != None: error = CreateAccount(self.UserName, self.UserPassword, None, None) - sel = os.popen("getenforce").read().startswith("Enforcing") + sel = RunGetOutput("getenforce",chk_err=False)[1].startswith("Enforcing") if sel == True and IsRedHat(): Run("setenforce 0") home = GetHome() @@ -1503,7 +1576,7 @@ class Agent(Util): net = self.IntegerToIpAddressV4String(net) mask = self.IntegerToIpAddressV4String(mask) gateway = self.IntegerToIpAddressV4String(gateway) - Run("/sbin/route add -net " + net + " netmask " + mask + " gw " + gateway) + Run("/sbin/route add -net " + net + " netmask " + mask + " gw " + gateway,chk_err=False) # We supress error logging on error. def HandleDhcpResponse(self, sendData, receiveBuffer): LogIfVerbose("HandleDhcpResponse") @@ -1600,8 +1673,8 @@ class Agent(Util): ShortSleep = False # Sleep 1 second before retrying DHCP queries. ifname=None if not IsWindows(): - Run("iptables -D INPUT -p udp --dport 68 -j ACCEPT") - Run("iptables -I INPUT -p udp --dport 68 -j ACCEPT") + Run("iptables -D INPUT -p udp --dport 68 -j ACCEPT",chk_err=False) # We supress error logging on error. + Run("iptables -I INPUT -p udp --dport 68 -j ACCEPT",chk_err=False) # We supress error logging on error. sleepDurations = [0, 5, 10, 30, 60, 60, 60, 60] maxRetry = len(sleepDurations) @@ -1618,7 +1691,7 @@ class Agent(Util): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) missingDefaultRoute = True try: - for line in os.popen("route -n").read().split('\n'): + for line in RunGetOutput("route -n")[1].split('\n'): if line.startswith("0.0.0.0 "): missingDefaultRoute = False except: @@ -1633,7 +1706,7 @@ class Agent(Util): except IOError, e: pass Log("DoDhcpWork: Missing default route - adding broadcast route for DHCP.") - Run("route add 255.255.255.255 dev " + ifname) + Run("route add 255.255.255.255 dev " + ifname,chk_err=False) # We supress error logging on error. sock.bind(("0.0.0.0", 68)) sock.sendto(sendData, ("<broadcast>", 67)) sock.settimeout(10) @@ -1659,7 +1732,7 @@ class Agent(Util): sock.close() if missingDefaultRoute: #We added this route - delete it - Run("route del 255.255.255.255 dev " + ifname) + Run("route del 255.255.255.255 dev " + ifname,chk_err=False) # We supress error logging on error. Log("DoDhcpWork: Removing broadcast route for DHCP.") return None @@ -1668,7 +1741,7 @@ class Agent(Util): Log("Setting host name: " + name) UpdateAndPublishHostNameCommon(name) for ethernetInterface in PossibleEthernetInterfaces: - Run("ifdown " + ethernetInterface + " && ifup " + ethernetInterface) + Run("ifdown " + ethernetInterface + " && ifup " + ethernetInterface,chk_err=False) # We supress error logging on error. self.RestoreRoutes() def RestoreRoutes(self): @@ -1769,17 +1842,17 @@ class Agent(Util): if os.path.exists("/dev/sr0"): dvd = "/dev/sr0" modloaded=False - if Run("fdisk -l " + dvd + " | grep Disk"): + if Run("fdisk -l " + dvd + " | grep Disk",chk_err=False): # Is it possible to load a module for ata_piix? - retcode,krn=RunSafe('uname -r') + retcode,krn=RunGetOutput('uname -r') if retcode: Error("Unable to provision: Failed to call uname -a") return "Unable to provision: Failed to mount DVD." - krn_pth='/lib/modules/'+krn+'/kernel/drivers/ata/ata_piix.ko' + krn_pth='/lib/modules/'+krn.strip('\n')+'/kernel/drivers/ata/ata_piix.ko' if not os.path.isfile(krn_pth): Error("Unable to provision: Failed to locate ata_piix.ko") return "Unable to provision: Failed to mount DVD." - retcode,output=RunSafe('insmod ' + krn_pth) + retcode,output=RunGetOutput('insmod ' + krn_pth) if retcode: Error("Unable to provision: Failed to insmod " + krn+pth) return "Failed to retrieve provisioning data (0x01)." @@ -1795,12 +1868,12 @@ class Agent(Util): CreateDir("/mnt/cdrom/secure", "root", 0700) #begin mount loop - ten tries - 5 sec wait between for retry in range(1,11): - retcode,output=RunSafe("mount -v " + dvd + " /mnt/cdrom/secure") - Log(output) + retcode,output=RunGetOutput("mount -v " + dvd + " /mnt/cdrom/secure") + Log(output[:-1]) if retcode: Log("mount failed on attempt #" + str(retry) ) else: - Log("mount suceed on attempt #" + str(retry) ) + Log("mount succeeded on attempt #" + str(retry) ) break Log("mount loop sleeping 5...") time.sleep(5) @@ -1823,7 +1896,7 @@ class Agent(Util): Error ("Provisioninig image FAILED " + error) return ("Provisioninig image FAILED " + error) # This is done here because regenerated SSH host key pairs may be potentially overwritten when processing the ovfxml - fingerprint = os.popen("ssh-keygen -lf /etc/ssh/ssh_host_" + type + "_key.pub").read().rstrip().split()[1].replace(':','') + fingerprint = RunGetOutput("ssh-keygen -lf /etc/ssh/ssh_host_" + type + "_key.pub")[1].rstrip().split()[1].replace(':','') self.ReportRoleProperties(fingerprint) delRootPass = Config.get("Provisioning.DeleteRootPassword") if delRootPass != None and delRootPass.lower().startswith("y"): @@ -2236,13 +2309,13 @@ def Install(): if missing == True: Warn("Please resolve missing dependencies listed for full functionality.") if UsesRpm(): - if not Run("rpm --quiet -q NetworkManager"): + if not Run("rpm --quiet -q NetworkManager",chk_err=False): # We want this to fail - supress error logging on error. Error(GuestAgentLongName + " is not compatible with NetworkManager.") return 1 if Run("rpm --quiet -q python-pyasn1"): Error(GuestAgentLongName + " requires python-pyasn1.") return 1 - if UsesDpkg() and not Run("dpkg-query -s network-manager >/dev/null 2>&1"): + if UsesDpkg() and not Run("dpkg-query -s network-manager >/dev/null 2>&1",chk_err=False): # We want this to fail - supress error logging on error. Error(GuestAgentLongName + " is not compatible with network-manager.") return 1 for a in RulesFiles: @@ -2252,14 +2325,14 @@ def Install(): shutil.move(a, ".") Warn("Moved " + a + " -> " + LibDir + "/" + GetLastPathElement(a) ) - if IsUbuntu(): + if IsUbuntu() and not IsPackagedUbuntu(): # Support for Ubuntu's upstart configuration filename="waagent.conf" filepath = "/etc/init/" + filename SetFileContents(filepath, Init_Ubuntu) os.chmod(filepath, 0644) - else: + elif not IsPackagedUbuntu(): # Regular init.d configurations filename = "waagent" filepath = "/etc/init.d/" + filename @@ -2273,6 +2346,7 @@ def Install(): SetFileContents(filepath, init[0]) os.chmod(filepath, 0755) Run(init[1]) + if os.path.isfile("/etc/waagent.conf"): try: os.remove("/etc/waagent.conf.old") @@ -2310,12 +2384,30 @@ def Uninstall(): if a == 0: Error("Unable to detect Linux Distribution.") return 1 - Run("service " + filename + " stop") - cmd = ["chkconfig --del " + filename, - "update-rc.d -f " + filename + " remove", - "insserv -r " + filename][a - 1] - Run(cmd) - for f in os.listdir(LibDir) + ["/etc/init/waagent.conf","/etc/init.d/" + filename, "/etc/waagent.conf", "/etc/logrotate.d/waagent", "/etc/sudoers.d/waagent"]: + + # Managed by dpkg for Packaged Ubuntu + if not IsPackaged(): + Run("service " + filename + " stop") + cmd = ["chkconfig --del " + filename, + "update-rc.d -f " + filename + " remove", + "insserv -r " + filename][a - 1] + Run(cmd) + + remove_f = [ + "/etc/waagent.conf", + "/etc/logrotate.d/waagent", + "/etc/sudoers.d/waagent", + ] + + # For packaged Ubuntu, the script should let the packaging + # manage the removal of these files + if not IsPackagedUbuntu(): + remove_f.append([ + "/etc/init/waagent.conf", + "/etc/init.d/" + filename, + ]) + + for f in os.listdir(LibDir) + remove_f: try: os.remove(f) except: |