diff options
Diffstat (limited to 'waagent')
| -rw-r--r-- | waagent | 344 |
1 files changed, 238 insertions, 106 deletions
@@ -80,7 +80,7 @@ if not hasattr(subprocess,'check_output'): GuestAgentName = "WALinuxAgent" GuestAgentLongName = "Windows Azure Linux Agent" -GuestAgentVersion = "WALinuxAgent-2.0.12" +GuestAgentVersion = "WALinuxAgent-2.0.13" ProtocolVersion = "2012-11-30" #WARNING this value is used to confirm the correct fabric protocol. Config = None @@ -499,8 +499,9 @@ class AbstractDistro(object): if existingFS == "7" and fs != "ntfs": Run("sfdisk -c " + device + " 1 83") Run("mkfs." + fs + " " + partition) - if Run("mount " + partition + " " + mountpoint): + if Run("mount " + partition + " " + mountpoint, chk_err=False): #If mount failed, try to format the partition and mount again + Warn("Failed to mount resource disk. Retry mounting.") Run("mkfs." + fs + " " + partition + " -F") if Run("mount " + partition + " " + mountpoint): Error("ActivateResourceDisk: Failed to mount resource disk (" + partition + ").") @@ -588,7 +589,7 @@ class AbstractDistro(object): def stopDHCP(self): """ - Stop the system DHCP client so that tha agent can bind on its port. If + Stop the system DHCP client so that the agent can bind on its port. If the distro has set dhcp_enabled to True, it will need to provide an implementation of this method. """ @@ -605,6 +606,9 @@ class AbstractDistro(object): """ Translate the custom data from a Base64 encoding. Default to no-op. """ + decodeCustomData = Config.get("Provisioning.DecodeCustomData") + if decodeCustomData != None and decodeCustomData.lower().startswith("y"): + return base64.b64decode(data) return data def getConfigurationPath(self): @@ -615,7 +619,26 @@ class AbstractDistro(object): def getTotalMemory(self): return int(RunGetOutput("grep MemTotal /proc/meminfo |awk '{print $2}'")[1])/1024 - + + def getInterfaceNameByMac(self, mac): + ret, output = RunGetOutput("ifconfig -a") + if ret != 0: + raise Exception("Failed to get network interface info") + match = re.search(r"(eth\d)[^\n]+HWaddr {0}".format(mac), output) + if match is None: + raise Exception("Failed to get ifname with mac: {0}".format(mac)) + return match.group(1) + + def configIpV4(self, ifName, addr): + ret, output = RunGetOutput("ifconfig {0} up".format(ifName)) + if ret != 0: + raise Exception("Failed to bring up {0}: {1}".format(ifName, + output)) + ret, output = RunGetOutput("ifconfig {0} {1}/24".format(ifName, addr)) + if ret != 0: + raise Exception("Failed to config ipv4 for {0}: {1}".format(ifName, + output)) + ############################################################ # GentooDistro ############################################################ @@ -1019,7 +1042,7 @@ class CoreOSDistro(AbstractDistro): self.dhcp_client_name='systemd-networkd' self.getpidcmd='pidof ' self.shadow_file_mode=0640 - self.waagent_path='/usr/share/oem/waagent/bin' + self.waagent_path='/usr/share/oem/bin' self.python_path='/usr/share/oem/python/bin' self.dhcp_enabled=True if 'PATH' in os.environ: @@ -1337,18 +1360,6 @@ class UbuntuDistro(debianDistro): def registerAgentService(self): return self.installAgentServiceScriptFiles() - - def startAgentService(self): - """ - Use upstart syntax. - """ - return Run('start ' + self.agent_service_name) - - def stopAgentService(self): - """ - Use upstart syntax. - """ - return Run('stop ' + self.agent_service_name) def uninstallAgentService(self): """ @@ -2585,12 +2596,15 @@ def DeviceForIdePort(n): break return device +class HttpResourceGoneError(Exception): + pass + class Util(object): """ Http communication class. Base of GoalState, and Agent classes. """ - __RetryWaitingInterval=10 + RetryWaitingInterval=10 def __init__(self): self.Endpoint = None @@ -2598,47 +2612,82 @@ class Util(object): def _ParseUrl(self, url): secure = False host = self.Endpoint - action = url - - #Strip "http[s]://hostname/" from url + path = url + port = None + + #"http[s]://hostname[:port][/]" if url.startswith("http://"): url = url[7:] - pos = url.index("/") - if pos > 0: - host = url[0: pos] - action = url[pos:] + if "/" in url: + host = url[0: url.index("/")] + path = url[url.index("/"):] + else: + host = url + path = "/" elif url.startswith("https://"): secure = True url = url[8:] - pos = url.index("/") - if pos > 0: - host = url[0:pos] - action = url[pos:] - return host, action, secure - - def _HttpRequest(self, method, host, action, data=None, - secure=False, headers=None): - resp = None; - try: - httpConnection = None + if "/" in url: + host = url[0: url.index("/")] + path = url[url.index("/"):] + else: + host = url + path = "/" + + if host is None: + raise ValueError("Host is invalid:{0}".format(url)) + + if(":" in host): + pos = host.rfind(":") + port = int(host[pos + 1:]) + host = host[0:pos] + + return host, port, secure, path - #If httplib module is not built with ssl support. Failback to http - if secure and hasattr(httplib, "HTTPSConnection"): - httpConnection = httplib.HTTPSConnection(host) + def GetHttpProxy(self, secure): + """ + Get http_proxy and https_proxy from environment variables. + Username and password is not supported now. + """ + host = Config.get("HttpProxy.Host") + port = Config.get("HttpProxy.Port") + return (host, port) + + def _HttpRequest(self, method, host, path, port=None, data=None, secure=False, + headers=None, proxyHost=None, proxyPort=None): + resp = None + conn = None + try: + if secure: + port = 443 if port is None else port + if proxyHost is not None and proxyPort is not None: + conn = httplib.HTTPSConnection(proxyHost, proxyPort) + conn.set_tunnel(host, port) + #If proxy is used, full url is needed. + path = "https://{0}:{1}{2}".format(host, port, path) + else: + conn = httplib.HTTPSConnection(host, port) else: - httpConnection = httplib.HTTPConnection(host) + port = 80 if port is None else port + if proxyHost is not None and proxyPort is not None: + conn = httplib.HTTPConnection(proxyHost, proxyPort) + #If proxy is used, full url is needed. + path = "http://{0}:{1}{2}".format(host, port, path) + else: + conn = httplib.HTTPConnection(host, port) if headers == None: - httpConnection.request(method, action, data) + conn.request(method, path, data) else: - httpConnection.request(method, action, data, headers) - resp = httpConnection.getresponse() + conn.request(method, path, data, headers) + resp = conn.getresponse() except httplib.HTTPException, e: Error('HTTPException {0}, args:{1}'.format(e, repr(e.args))) except IOError, e: Error('Socket IOError {0}, args:{1}'.format(e, repr(e.args))) return resp - def HttpRequest(self, method, url, data, headers=None, maxRetry=3): + def HttpRequest(self, method, url, data=None, + headers=None, maxRetry=3, chkProxy=False): """ Sending http request to server On error, sleep 10 and maxRetry times. @@ -2647,8 +2696,34 @@ class Util(object): LogIfVerbose("HTTP Req: {0} {1}".format(method, url)) LogIfVerbose("HTTP Req: Data={0}".format(data)) LogIfVerbose("HTTP Req: Header={0}".format(headers)) - host, action, secure = self._ParseUrl(url) - resp = self._HttpRequest(method, host, action, data, secure, headers) + try: + host, port, secure, path = self._ParseUrl(url) + except ValueError, e: + Error("Failed to parse url:{0}".format(url)) + return None + + #Check proxy + proxyHost, proxyPort = (None, None) + if chkProxy: + proxyHost, proxyPort = self.GetHttpProxy(secure) + + #If httplib module is not built with ssl support. Fallback to http + if secure and not hasattr(httplib, "HTTPSConnection"): + Warn("httplib is not built with ssl support") + secure = False + proxyHost, proxyPort = self.GetHttpProxy(secure) + + #If httplib module doesn't support https tunnelling. Fallback to http + if secure and \ + proxyHost is not None and \ + proxyPort is not None and \ + not hasattr(httplib.HTTPSConnection, "set_tunnel"): + Warn("httplib doesn't support https tunnelling(new in python 2.7)") + secure = False + proxyHost, proxyPort = self.GetHttpProxy(secure) + + resp = self._HttpRequest(method, host, path, port, data, + secure, headers, proxyHost, proxyPort) for retry in range(0, maxRetry): if resp is not None and \ (resp.status == httplib.OK or \ @@ -2656,6 +2731,9 @@ class Util(object): resp.status == httplib.ACCEPTED): return resp; + if resp is not None and resp.status == httplib.GONE: + raise HttpResourceGoneError("Http resource gone.") + Error("Retry={0}".format(retry)) Error("HTTP Req: {0} {1}".format(method, url)) Error("HTTP Req: Data={0}".format(data)) @@ -2667,35 +2745,36 @@ class Util(object): Error("HTTP Err: Reason={0}".format(resp.reason)) Error("HTTP Err: Header={0}".format(resp.getheaders())) Error("HTTP Err: Body={0}".format(resp.read())) - time.sleep(self.__class__.__RetryWaitingInterval) - resp = self._HttpRequest(method, host, action, data, secure, - headers) + + time.sleep(self.__class__.RetryWaitingInterval) + resp = self._HttpRequest(method, host, path, data, secure, + headers, proxyHost, proxyPort) return None - def HttpGet(self, url, headers=None, maxRetry=3): - return self.HttpRequest("GET", url, None, headers, maxRetry) + def HttpGet(self, url, headers=None, maxRetry=3, chkProxy=False): + return self.HttpRequest("GET", url, None, headers, maxRetry, chkProxy) - def HttpHead(self, url, headers=None, maxRetry=3): - return self.HttpRequest("HEAD", url, None, headers, maxRetry) + def HttpHead(self, url, headers=None, maxRetry=3, chkProxy=False): + return self.HttpRequest("HEAD", url, None, headers, maxRetry, chkProxy) - def HttpPost(self, url, data, headers=None, maxRetry=3): - return self.HttpRequest("POST", url, data, headers, maxRetry) + def HttpPost(self, url, data, headers=None, maxRetry=3, chkProxy=False): + return self.HttpRequest("POST", url, data, headers, maxRetry, chkProxy) - def HttpPut(self, url, data, headers=None, maxRetry=3): - return self.HttpRequest("PUT", url, data, headers, maxRetry) + def HttpPut(self, url, data, headers=None, maxRetry=3, chkProxy=False): + return self.HttpRequest("PUT", url, data, headers, maxRetry, chkProxy) - def HttpDelete(url, data, headers=None, maxRetry=3): - return self.HttpRequest("DELETE", url, data, headers, maxRetry) + def HttpDelete(self, url, headers=None, maxRetry=3, chkProxy=False): + return self.HttpRequest("DELETE", url, None, headers, maxRetry, chkProxy) - def HttpGetWithoutHeaders(self, url, maxRetry=3): + def HttpGetWithoutHeaders(self, url, maxRetry=3, chkProxy=False): """ Return data from an HTTP get on 'url'. """ - resp = self.HttpGet(url, None, maxRetry) + resp = self.HttpGet(url, None, maxRetry, chkProxy) return resp.read() if resp is not None else None - def HttpGetWithHeaders(self, url, maxRetry=3): + def HttpGetWithHeaders(self, url, maxRetry=3, chkProxy=False): """ Return data from an HTTP get on 'url' with x-ms-agent-name and x-ms-version @@ -2704,10 +2783,11 @@ class Util(object): resp = self.HttpGet(url, { "x-ms-agent-name": GuestAgentName, "x-ms-version": ProtocolVersion - }, maxRetry) + }, maxRetry, chkProxy) return resp.read() if resp is not None else None - def HttpSecureGetWithHeaders(self, url, transportCert, maxRetry=3): + def HttpSecureGetWithHeaders(self, url, transportCert, maxRetry=3, + chkProxy=False): """ Return output of get using ssl cert. """ @@ -2716,16 +2796,16 @@ class Util(object): "x-ms-version": ProtocolVersion, "x-ms-cipher-name": "DES_EDE3_CBC", "x-ms-guest-agent-public-x509-cert": transportCert - }, maxRetry) + }, maxRetry, chkProxy) return resp.read() if resp is not None else None - def HttpPostWithHeaders(self, url, data, maxRetry=3): + def HttpPostWithHeaders(self, url, data, maxRetry=3, chkProxy=False): header = { "x-ms-agent-name": GuestAgentName, "Content-Type": "text/xml; charset=utf-8", "x-ms-version": ProtocolVersion } - return self.HttpPost(url, data, header, maxRetry) + return self.HttpPost(url, data, header, maxRetry, chkProxy) __StorageVersion="2014-02-14" @@ -2737,7 +2817,7 @@ def GetBlobType(url): blobPropResp = restutil.HttpHead(url, { "x-ms-date" : timestamp, 'x-ms-version' : __StorageVersion - }); + }, chkProxy=True); blobType = None if blobPropResp is None: Error("Can't get status blob type.") @@ -2755,7 +2835,7 @@ def PutBlockBlob(url, data): "x-ms-blob-type" : "BlockBlob", "Content-Length": str(len(data)), "x-ms-version" : __StorageVersion - }) + }, chkProxy=True) if ret is None: Error("Failed to upload block blob for status.") @@ -2771,7 +2851,7 @@ def PutPageBlob(url, data): "Content-Length": "0", "x-ms-blob-content-length" : str(pageBlobSize), "x-ms-version" : __StorageVersion - }) + }, chkProxy=True) if ret is None: Error("Failed to clean up page blob for status") return @@ -2799,7 +2879,7 @@ def PutPageBlob(url, data): "x-ms-page-write" : "update", "x-ms-version" : __StorageVersion, "Content-Length": str(pageEnd - start) - }) + }, chkProxy=True) if ret is None: Error("Failed to upload page blob for status") return @@ -2919,7 +2999,7 @@ class EnvMonitor(object): Monitor dhcp client pid and hostname. If dhcp clinet process re-start has occurred, reset routes, dhcp with fabric. """ - publish = ConfigurationProvider().get("Provisioning.MonitorHostName") + publish = Config.get("Provisioning.MonitorHostName") dhcpcmd = MyDistro.getpidcmd+ ' ' + MyDistro.getDhcpClientName() dhcppid = RunGetOutput(dhcpcmd)[1] while not self.shutdown: @@ -3130,6 +3210,7 @@ class SharedConfig(object): """ Parse and write configuration to file SharedConfig.xml. """ + LogIfVerbose(xmlText) self.reinitialize() self.xmlText = xmlText dom = xml.dom.minidom.parseString(xmlText) @@ -3146,25 +3227,46 @@ class SharedConfig(object): if nodes is not None and len(nodes) != 0: node = nodes[0] if node.hasAttribute("rdmaMacAddress"): - self.RdmaMacAddress = node.getAttribute("rdmaMacAddress") + addr = node.getAttribute("rdmaMacAddress") + self.RdmaMacAddress = addr[0:2] + for i in range(1, 6): + self.RdmaMacAddress += ":" + addr[2 * i : 2 *i + 2] if node.hasAttribute("rdmaIPv4Address"): self.RdmaIPv4Address = node.getAttribute("rdmaIPv4Address") return self def Save(self): + LogIfVerbose("Save SharedConfig.xml") SetFileContents("SharedConfig.xml", self.xmlText) - def ConfigRdma(self, dev="/dev/hvnd_rdma"): - if self.RdmaIPv4Address is not None and self.RdmaMacAddress is not None: - if os.path.isfile(dev): - data = ('rdmaMacAddress="{0}" rdmaIPv4Address="{1}"' - '').format(self.RdmaMacAddress, self.RdmaIPv4Address) - Log("Write rdma config to {0}: {1}".format(dev, data)) - try: - with open(dev, "w") as c: - c.write(data) - except IOError, e: - Error("Error writing {0}, {1}".format(dev, e)) + def ConfigRdma(self, dev="/dev/hvnd_rdma", datConf="/etc/dat.conf"): + if self.RdmaIPv4Address is None or self.RdmaMacAddress is None: + return + + if os.path.isfile(datConf): + old = ("ofa-v2-ib0 u2.0 nonthreadsafe default libdaplofa.so.2 " + "dapl.2.0 \"\S+ 0\"") + new = ("ofa-v2-ib0 u2.0 nonthreadsafe default libdaplofa.so.2 " + "dapl.2.0 \"{0} 0\"").format(self.RdmaIPv4Address) + lines = GetFileContents(datConf) + lines = re.sub(old, new, lines) + SetFileContents(lines) + + if os.path.isfile(dev): + data = ('rdmaMacAddress="{0}" rdmaIPv4Address="{1}"' + '').format(self.RdmaMacAddress, self.RdmaIPv4Address) + Log("Write rdma config to {0}: {1}".format(dev, data)) + try: + with open(dev, "w") as c: + c.write(data) + except IOError, e: + Error("Error writing {0}, {1}".format(dev, e)) + + try: + ifName = MyDistro.getInterfaceNameByMac(self.RdmaMacAddress) + MyDistro.configIpV4(ifName, self.RdmaIPv4Address) + except Exception as e: + Error("Failed to config rdma device: {0}".format(e)) def InvokeTopologyConsumer(self): program = Config.get("Role.TopologyConsumer") @@ -3331,7 +3433,7 @@ class ExtensionsConfig(object): Log("Plugin server is: " + self.Util.Endpoint) SimpleLog(p.plugin_log,"Plugin server is: " + self.Util.Endpoint) - manifest=self.Util.HttpGetWithoutHeaders(location) + manifest=self.Util.HttpGetWithoutHeaders(location, chkProxy=True) if manifest == None: Error("Unable to download plugin manifest" + name + " from primary location. Attempting with failover location.") SimpleLog(p.plugin_log,"Unable to download plugin manifest" + name + " from primary location. Attempting with failover location.") @@ -3340,12 +3442,12 @@ class ExtensionsConfig(object): Log("Plugin failover server is: " + self.Util.Endpoint) SimpleLog(p.plugin_log,"Plugin failover server is: " + self.Util.Endpoint) - manifest=self.Util.HttpGetWithoutHeaders(failoverlocation) + manifest=self.Util.HttpGetWithoutHeaders(failoverlocation, chkProxy=True) #if failoverlocation also fail what to do then? if manifest == None: AddExtensionEvent(name,WALAEventOperation.Download,False,0,version,"Download mainfest fail "+failoverlocation) - Log("Plugin manifest" + name + "downloaded successfully length = " + str(len(manifest))) - SimpleLog(p.plugin_log,"Plugin manifest" + name + "downloaded successfully length = " + str(len(manifest))) + Log("Plugin manifest " + name + " downloading failed from failover location.") + SimpleLog(p.plugin_log,"Plugin manifest " + name + " downloading failed from failover location.") filepath=LibDir+"/" + name + '.' + incarnation + '.manifest' if os.path.splitext(location)[-1] == '.xml' : #if this is an xml file we may have a BOM @@ -3374,7 +3476,7 @@ class ExtensionsConfig(object): SimpleLog(p.plugin_log,"Bundle URI = " + bundle_uri) # Download the zipfile archive and save as '.zip' - bundle=self.Util.HttpGetWithoutHeaders(bundle_uri) + bundle=self.Util.HttpGetWithoutHeaders(bundle_uri, chkProxy=True) if bundle == None: AddExtensionEvent(name,WALAEventOperation.Download,True,0,version,"Download zip fail "+bundle_uri) Error("Unable to download plugin bundle" + bundle_uri ) @@ -4085,6 +4187,7 @@ class GoalState(Util): LogIfVerbose("SharedConfigUrl:" + self.SharedConfigUrl) self.SharedConfigXml = self.HttpGetWithHeaders(self.SharedConfigUrl) self.SharedConfig = SharedConfig().Parse(self.SharedConfigXml) + self.SharedConfig.Save() elif e.localName == "ExtensionsConfig": self.ExtensionsConfigUrl = GetNodeTextData(e) LogIfVerbose("ExtensionsConfigUrl:" + self.ExtensionsConfigUrl) @@ -4113,9 +4216,9 @@ class GoalState(Util): """ Calls HostingEnvironmentConfig.Process() """ + LogIfVerbose("Process goalstate") self.HostingEnvironmentConfig.Process() self.SharedConfig.Process() - self.SharedConfig.Save() class OvfEnv(object): """ @@ -4170,7 +4273,7 @@ class OvfEnv(object): self.SshPublicKeys = [] self.SshKeyPairs = [] - def Parse(self, xmlText): + def Parse(self, xmlText, isDeprovision = False): """ Parse xml tree, retreiving user and ssh key information. Return self. @@ -4202,6 +4305,8 @@ class OvfEnv(object): return None self.ComputerName = GetNodeTextData(section.getElementsByTagNameNS(self.WaNs, "HostName")[0]) self.UserName = GetNodeTextData(section.getElementsByTagNameNS(self.WaNs, "UserName")[0]) + if isDeprovision == True: + return self try: self.UserPassword = GetNodeTextData(section.getElementsByTagNameNS(self.WaNs, "UserPassword")[0]) except: @@ -4450,7 +4555,7 @@ class WALAEvent(object): os.mkdir(eventfolder) os.chmod(eventfolder,0700) if len(os.listdir(eventfolder)) > 1000: - raise Exception("WriteToFolder:Too many file under "+datafolder+" exit") + 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: @@ -4594,7 +4699,7 @@ class WALAEventMonitor(WALAEvent): if not self.issysteminfoinitilized: self.issysteminfoinitilized=True try: - self.sysInfo["OSVersion"]=platform.system()+":"+"-".join(DistInfo())+":"+platform.release() + self.sysInfo["OSVersion"]=platform.system()+":"+"-".join(DistInfo(1))+":"+platform.release() self.sysInfo["GAVersion"]=GuestAgentVersion self.sysInfo["RAM"]=MyDistro.getTotalMemory() self.sysInfo["Processors"]=MyDistro.getProcessorCores() @@ -5346,9 +5451,17 @@ class Agent(Util): lbProbeResponder = False while True: if (goalState == None) or (incarnation == None) or (goalState.Incarnation != incarnation): - goalState = self.UpdateGoalState() + try: + goalState = self.UpdateGoalState() + except HttpResourceGoneError as e: + Warn("Incarnation is out of date:{0}".format(e)) + incarnation = None + continue + if goalState == None : + Warn("Failed to fetch goalstate") continue + if provisioned == False: self.ReportNotReady("Provisioning", "Starting") @@ -5368,7 +5481,15 @@ class Agent(Util): #Get Ctime of wala config, can help identify the base image of this VM AddExtensionEvent(name="WALA",op=WALAEventOperation.Provision,isSuccess=True, message="WALA Config Ctime:"+lastCtime) - + + executeCustomData = Config.get("Provisioning.ExecuteCustomData") + if executeCustomData != None and executeCustomData.lower().startswith("y"): + if os.path.exists(LibDir + '/CustomData'): + Run('chmod +x ' + LibDir + '/CustomData') + Run(LibDir + '/CustomData') + else: + Error(LibDir + '/CustomData does not exist.') + # # only one port supported # restart server if new port is different than old port @@ -5376,13 +5497,17 @@ class Agent(Util): # goalPort = goalState.LoadBalancerProbePort if currentPort != goalPort: - self.LoadBalancerProbeServer_Shutdown() - currentPort = goalPort - if currentPort != None and lbProbeResponder == True: - self.LoadBalancerProbeServer = LoadBalancerProbeServer(currentPort) - if self.LoadBalancerProbeServer == None : - lbProbeResponder = False - Log("Unable to create LBProbeResponder.") + try: + self.LoadBalancerProbeServer_Shutdown() + currentPort = goalPort + if currentPort != None and lbProbeResponder == True: + self.LoadBalancerProbeServer = LoadBalancerProbeServer(currentPort) + if self.LoadBalancerProbeServer == None : + lbProbeResponder = False + Log("Unable to create LBProbeResponder.") + except Exception, e: + Error("Failed to launch LBProbeResponder: {0}".format(e)) + currentPort = None # Report SSH key fingerprint type = Config.get("Provisioning.SshHostKeyPairType") @@ -5419,7 +5544,7 @@ class Agent(Util): eventMonitor = WALAEventMonitor(self.HttpPostWithHeaders) eventMonitor.StartEventsLoop() - time.sleep(25 - sleepToReduceAccessDenied) + time.sleep(25 - sleepToReduceAccessDenied) WaagentLogrotate = """\ @@ -5513,14 +5638,14 @@ def ReplaceStringInFile(fname,src,repl): """ Replace 'src' with 'repl' in file. """ - updated='' try: sr=re.compile(src) if FindStringInFile(fname,src): + updated='' for l in (open(fname,'r')).readlines(): n=re.sub(sr,repl,l) updated+=n - ReplaceFileContentsAtomic(fname,updated) + ReplaceFileContentsAtomic(fname,updated) except : raise return @@ -5619,6 +5744,7 @@ def DistInfo(fullname=0): release = re.sub('\-.*\Z', '', str(platform.release())) distinfo = ['FreeBSD', release] return distinfo + if 'linux_distribution' in dir(platform): distinfo = list(platform.linux_distribution(full_distribution_name=fullname)) distinfo[0] = distinfo[0].strip() # remove trailing whitespace in distro name @@ -5679,7 +5805,7 @@ def Deprovision(force, deluser): ovfxml = GetFileContents(LibDir+"/ovf-env.xml") ovfobj = None if ovfxml != None: - ovfobj = OvfEnv().Parse(ovfxml) + ovfobj = OvfEnv().Parse(ovfxml, True) print("WARNING! The waagent service will be stopped.") print("WARNING! All SSH host key pairs will be deleted.") @@ -5747,6 +5873,12 @@ def main(): LoggerInit('/var/log/waagent.log','/dev/console') global LinuxDistro LinuxDistro=DistInfo()[0] + + #The platform.py lib has issue with detecting oracle linux distribution. + #Merge the following patch provided by oracle as a temparory fix. + if os.path.exists("/etc/oracle-release"): + LinuxDistro="Oracle Linux" + global MyDistro MyDistro=GetMyDistro() if MyDistro == None : |
