From 0afc048f2a6ff3638ecfa33e7ded5dc8dddf041a Mon Sep 17 00:00:00 2001 From: Ben Howard Date: Fri, 17 Jul 2015 14:24:20 -0600 Subject: Import patches-unapplied version 2.0.14-0ubuntu1 to ubuntu/wily-proposed Imported using git-ubuntu import. Changelog parent: 7cb11e70e6c639cefc143e8df243b3e88f5fe232 New changelog entries: * New upstream release. - Rebased patches for 2.0.13 onto 2.0.14. - Fix rdma config - Fix page blob uploading for python 2.6 . Fix http request error handling --- Changelog | 5 + Dockerfile | 10 ++ README | 22 ++++- config/docker-waagent.conf | 75 +++++++++++++++ config/waagent.conf | 12 +++ debian/changelog | 10 ++ debian/rules | 4 +- tests/test_shared_config.py | 69 ++++++++++++-- tests/upload_status_blob.py | 8 +- waagent | 223 +++++++++++++++++++++++++++++++++----------- 10 files changed, 370 insertions(+), 68 deletions(-) create mode 100644 Dockerfile create mode 100644 config/docker-waagent.conf diff --git a/Changelog b/Changelog index 44788c8..6706892 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,10 @@ WALinuxAgent Changelog ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +1 Jul 2015, WALinuxAgent 2.0.14 + . Fix rdma config + . Fix page blob uploading for python 2.6 + . Fix http request error handling + 1 Jun 2015, WALinuxAgent 2.0.13 . Handle http 410 returned by host . Add support for http proxy diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bc917e7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM debian:jessie +RUN apt-get update && apt-get upgrade --no-install-recommends -y +RUN apt-get install -y --no-install-recommends \ + openssl ca-certificates ssh parted sudo net-tools ifupdown python python-pyasn1 python-rpm +COPY waagent /usr/sbin/ +COPY config/docker-waagent.conf /etc/waagent.conf +RUN chmod +x /usr/sbin/waagent && \ + rm -rf /etc/skel && \ + ln -sf /dev/stdout /var/log/waagent.log +ENTRYPOINT ["/usr/sbin/waagent"] diff --git a/README b/README index 59fab95..b1c97e5 100644 --- a/README +++ b/README @@ -128,6 +128,10 @@ Flags: -force: Skip interactive confirmation for some commands +Options: + + -conf=/path/to/file.conf: Specify configuration file to use instead of default one. + Commands: -help: Lists the supported commands and flags. @@ -203,6 +207,8 @@ ResourceDisk.MountPoint=/mnt/resource ResourceDisk.EnableSwap=n ResourceDisk.SwapSizeMB=0 LBProbeResponder=y +Logs.File=/var/log/waagent.log +Logs.Console=y Logs.Verbose=n OS.RootDeviceScsiTimeout=300 OS.OpensslPath=None @@ -337,11 +343,23 @@ Type: Boolean Default: y If set, waagent will respond to load balancer probes from the platform (if present). +Logs.File: +Type: String Default: /dev/stdout + +If set, logs are appended to this file (instead of stdout). Bundled +config (config/waagent.conf) sets this to '/var/log/waagent.log'. + +Logs.Console: +Type: Boolean Default: n + +If set, waagent also logs to serial console. Bundled config (config/waagent.conf) +sets this to 'y'. + Logs.Verbose: Type: Boolean Default: n -If set, log verbosity is boosted. Waagent logs to /var/log/waagent.log and -leverages the system logrotate functionality to rotate logs. +If set, log verbosity is boosted. When waagent logs to file it can +leverage the system logrotate functionality to rotate logs. OS.RootDeviceScsiTimeout: Type: Integer Default: 300 diff --git a/config/docker-waagent.conf b/config/docker-waagent.conf new file mode 100644 index 0000000..def7231 --- /dev/null +++ b/config/docker-waagent.conf @@ -0,0 +1,75 @@ +# +# Windows Azure Linux Agent Configuration +# + +# Specified program is invoked with the argument "Ready" when we report ready status +# to the endpoint server. +Role.StateConsumer=None + +# Specified program is invoked with XML file argument specifying role +# configuration. +Role.ConfigurationConsumer=None + +# Specified program is invoked with XML file argument specifying role topology. +Role.TopologyConsumer=None + +# Enable instance creation +Provisioning.Enabled=y + +# Password authentication for root account will be unavailable. +Provisioning.DeleteRootPassword=y + +# Generate fresh host key pair. +Provisioning.RegenerateSshHostKeyPair=n + +# Supported values are "rsa", "dsa" and "ecdsa". +Provisioning.SshHostKeyPairType=rsa + +# Monitor host name changes and publish changes via DHCP requests. +Provisioning.MonitorHostName=y + +# Decode CustomData from Base64. +Provisioning.DecodeCustomData=n + +# Execute CustomData after provisioning. +Provisioning.ExecuteCustomData=n + +# Format if unformatted. If 'n', resource disk will not be mounted. +ResourceDisk.Format=y + +# File system on the resource disk +# Typically ext3 or ext4. FreeBSD images should use 'ufs2' here. +ResourceDisk.Filesystem=ext4 + +# Mount point for the resource disk +ResourceDisk.MountPoint=/mnt/resource + +# Create and use swapfile on resource disk. +ResourceDisk.EnableSwap=n + +# Size of the swapfile. +ResourceDisk.SwapSizeMB=0 + +# Respond to load balancer probes if requested by Windows Azure. +LBProbeResponder=y + +# File to write log to. +# '/var/log/waagent.log' if not set +Logs.File=/dev/stdout + +# Enable logging to serial console (y|n) +# When stdout is not enough... +# 'y' if not set +Logs.Console=n + +# Enable verbose logging (y|n) +Logs.Verbose=n + +# Preferred network interface to communicate with Azure platform +Network.Interface=eth0 + +# Root device timeout in seconds. +OS.RootDeviceScsiTimeout=300 + +# If "None", the system default version is used. +OS.OpensslPath=None diff --git a/config/waagent.conf b/config/waagent.conf index 756eb4d..97da2b9 100644 --- a/config/waagent.conf +++ b/config/waagent.conf @@ -53,9 +53,21 @@ ResourceDisk.SwapSizeMB=0 # Respond to load balancer probes if requested by Windows Azure. LBProbeResponder=y +# File to write log to. +# '/var/log/waagent.log' if not set +Logs.File=/var/log/waagent.log + +# Enable logging to serial console (y|n) +# When stdout is not enough... +# 'y' if not set +Logs.Console=y + # Enable verbose logging (y|n) Logs.Verbose=n +# Preferred network interface to communicate with Azure platform +#Network.Interface=eth0 + # Root device timeout in seconds. OS.RootDeviceScsiTimeout=300 diff --git a/debian/changelog b/debian/changelog index fe6d8fb..9c9260d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +walinuxagent (2.0.14-0ubuntu1) wily; urgency=medium + + * New upstream release. + - Rebased patches for 2.0.13 onto 2.0.14. + - Fix rdma config + - Fix page blob uploading for python 2.6 + . Fix http request error handling + + -- Ben Howard Fri, 17 Jul 2015 14:24:20 -0600 + walinuxagent (2.0.13-0ubuntu2) wily; urgency=medium * Added missing udev rule for product-uuid. diff --git a/debian/rules b/debian/rules index 5358b7e..412afa9 100755 --- a/debian/rules +++ b/debian/rules @@ -6,11 +6,13 @@ DEB_VERSION=$(shell dpkg-parsechangelog | sed -rne 's,^Version: ([^-]+).*,\1,p') ORIG_SRC=https://github.com/WindowsAzure/WALinuxAgent get-packaged-orig-source: - git clone --separate-git-dir=.git \ + git clone --separate-git-dir=walinuxagent.checkout \ $(ORIG_SRC) orig_source git checkout -b tags/$(DEB_VERSION) git archive --format=tar.gz WALinuxAgent-$(DEB_VERSION) \ -o walinuxagent_$(DEB_VERSION).orig.tar.gz + rm -rf walinuxagent.checkout + rm -rf orig_source %: dh $@ --with python2,systemd diff --git a/tests/test_shared_config.py b/tests/test_shared_config.py index ede2766..8252b3b 100644 --- a/tests/test_shared_config.py +++ b/tests/test_shared_config.py @@ -13,6 +13,8 @@ # limitations under the License. # +import os +import re import unittest from env import waagent @@ -24,6 +26,16 @@ class MockDistro(object): pass class TestSharedConfig(unittest.TestCase): + + def test_reg(self): + mac = "00:15:5D:34:00:08" + output = Ifconfig_Out + output = output.replace('\n', '') + reg = r"(eth\d).*(HWaddr|ether) {0}".format(mac) + match = re.search(reg, output, re.IGNORECASE) + output = match.group(0) + eths = re.findall(r"eth\d", output) + self.assertNotEquals(0, len(eths)) def test_parse_shared_config(self): conf = waagent.SharedConfig().Parse(SharedConfigText) @@ -34,15 +46,32 @@ class TestSharedConfig(unittest.TestCase): return conf def test_config_rdma(self): - #waagent.LoggerInit("/dev/stdout", "/dev/null", verbose=True) waagent.MyDistro= MockDistro() - testDev = "/tmp/hvnd_rdma" - waagent.SetFileContents(testDev, "") + waagent.LibDir="/tmp" + + test_dev = "/tmp/hvnd_rdma" + test_dat_conf_files = ["/tmp/dat.conf"] + if os.path.isfile("/tmp/rdmaconfiged"): + os.remove("/tmp/rdmaconfiged") + waagent.SetFileContents(test_dev, "") + old = ("ofa-v2-ib0 u2.0 nonthreadsafe default libdaplofa.so.2 " + "dapl.2.0 \"oldip 0\"") + waagent.SetFileContents(test_dat_conf_files[0], old) conf = self.test_parse_shared_config() - conf.ConfigRdma(dev=testDev) - rdmaConf = waagent.GetFileContents(testDev) - self.assertNotEquals(None, rdmaConf) - self.assertNotEquals("", rdmaConf) + handler = waagent.RdmaHandler(conf.RdmaMacAddress, conf.RdmaIPv4Address, + test_dev, test_dat_conf_files) + handler.set_dat_conf() + handler.set_rdma_dev() + + rdma_conf = waagent.GetFileContents(test_dev) + self.assertNotEquals(None, rdma_conf) + self.assertNotEquals(0, rdma_conf.count(conf.RdmaIPv4Address)) + self.assertNotEquals(0, rdma_conf.count(conf.RdmaMacAddress)) + + dat_conf = waagent.GetFileContents(test_dat_conf_files[0]) + self.assertNotEquals(None, dat_conf) + self.assertNotEquals(0, dat_conf.count(conf.RdmaIPv4Address)) + self.assertEquals(0, dat_conf.count("oldip")) SharedConfigText="""\ @@ -88,6 +117,32 @@ SharedConfigText="""\ """ +Ifconfig_Out="""\ +eth0: flags=4163 mtu 1500 +inet 100.74.52.8 netmask 255.255.255.0 broadcast 100.74.52.255 +inet6 fe80::20d:3aff:fe10:672f prefixlen 64 scopeid 0x20 +ether 00:0d:3a:10:67:2f txqueuelen 1000 (Ethernet) +RX packets 9911 bytes 4451278 (4.2 MiB) +RX errors 0 dropped 0 overruns 0 frame 0 +TX packets 10505 bytes 1643251 (1.5 MiB) +TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + +eth1: flags=4163 mtu 1500 +inet6 fe80::215:5dff:fe34:8 prefixlen 64 scopeid 0x20 +ether 00:15:5d:34:00:08 txqueuelen 1000 (Ethernet) +RX packets 16 bytes 672 (672.0 B) +RX errors 0 dropped 0 overruns 0 frame 0 +TX packets 16 bytes 2544 (2.4 KiB) +TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + +lo: flags=73 mtu 65536 +inet 127.0.0.1 netmask 255.0.0.0 +inet6 ::1 prefixlen 128 scopeid 0x10 +loop txqueuelen 0 (Local Loopback) +RX packets 0 bytes 0 (0.0 B) +RX errors 0 dropped 0 overruns 0 frame 0 +TX packets 0 bytes 0 (0.0 B) +""" if __name__ == '__main__': unittest.main() diff --git a/tests/upload_status_blob.py b/tests/upload_status_blob.py index af8c580..59cb732 100644 --- a/tests/upload_status_blob.py +++ b/tests/upload_status_blob.py @@ -30,8 +30,14 @@ and defined the following 2 variables like: """ from status_blob_url import blockBlobUrl, pageBlobUrl +class MockConfig(object): + def get(self, keyName): + return None + +waagent.Config = MockConfig() + if __name__ == '__main__': waagent.LoggerInit('/dev/stdout', '/dev/null', verbose=True) status = "a" * 512 waagent.UploadStatusBlob(blockBlobUrl, status.encode("utf-8")) - waagent.UploadStatusBlob(pageBlobUrl, status.encode("utf-8")) + #waagent.UploadStatusBlob(pageBlobUrl, status.encode("utf-8")) diff --git a/waagent b/waagent index dd67353..2b616bf 100644 --- a/waagent +++ b/waagent @@ -80,7 +80,7 @@ if not hasattr(subprocess,'check_output'): GuestAgentName = "WALinuxAgent" GuestAgentLongName = "Windows Azure Linux Agent" -GuestAgentVersion = "WALinuxAgent-2.0.13" +GuestAgentVersion = "WALinuxAgent-2.0.14" ProtocolVersion = "2012-11-30" #WARNING this value is used to confirm the correct fabric protocol. Config = None @@ -624,17 +624,24 @@ class AbstractDistro(object): 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) + output = output.replace('\n', '') + match = re.search(r"(eth\d).*(HWaddr|ether) {0}".format(mac), + output, re.IGNORECASE) if match is None: raise Exception("Failed to get ifname with mac: {0}".format(mac)) - return match.group(1) + output = match.group(0) + eths = re.findall(r"eth\d", output) + if eths is None or len(eths) == 0: + raise Exception("Failed to get ifname with mac: {0}".format(mac)) + return eths[-1] - def configIpV4(self, ifName, addr): + def configIpV4(self, ifName, addr, netmask=24): 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)) + ret, output = RunGetOutput("ifconfig {0} {1}/{2}".format(ifName, addr, + netmask)) if ret != 0: raise Exception("Failed to config ipv4 for {0}: {1}".format(ifName, output)) @@ -1314,6 +1321,18 @@ class debianDistro(AbstractDistro): else : return 0 +############################################################ +# KaliDistro - WIP +# Functioning on Kali 1.1.0a so far +############################################################ +class KaliDistro(debianDistro): + """ + Kali Distro concrete class + Put Kali specific behavior here... + """ + def __init__(self): + super(KaliDistro,self).__init__() + ############################################################ # UbuntuDistro ############################################################ @@ -2526,18 +2545,22 @@ def GetFirstActiveNetworkInterfaceNonLoopback(): """ iface='' expected=16 # how many devices should I expect... - struct_size=40 # for 64bit the size is 40 bytes + is_64bits = sys.maxsize > 2**32 + struct_size=40 if is_64bits else 32 # for 64bit the size is 40 bytes, for 32bits it is 32 bytes. s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) buff=array.array('B', b'\0' * (expected*struct_size)) retsize=(struct.unpack('iL', fcntl.ioctl(s.fileno(), 0x8912, struct.pack('iL',expected*struct_size,buff.buffer_info()[0]))))[0] if retsize == (expected*struct_size) : Warn('SIOCGIFCONF returned more than ' + str(expected) + ' up network interfaces.') s=buff.tostring() + preferred_nic = Config.get("Network.Interface") for i in range(0,struct_size*expected,struct_size): iface=s[i:i+16].split(b'\0', 1)[0] if iface == b'lo': continue - else : + elif preferred_nic is None: + break + elif iface == preferred_nic: break return iface.decode('latin-1'), socket.inet_ntoa(s[i+20:i+24]) @@ -2722,8 +2745,9 @@ class Util(object): secure = False proxyHost, proxyPort = self.GetHttpProxy(secure) - resp = self._HttpRequest(method, host, path, port, data, - secure, headers, proxyHost, proxyPort) + resp = self._HttpRequest(method, host, path, port=port, data=data, + secure=secure, headers=headers, + proxyHost=proxyHost, proxyPort=proxyPort) for retry in range(0, maxRetry): if resp is not None and \ (resp.status == httplib.OK or \ @@ -2747,31 +2771,38 @@ class Util(object): Error("HTTP Err: Body={0}".format(resp.read())) time.sleep(self.__class__.RetryWaitingInterval) - resp = self._HttpRequest(method, host, path, data, secure, - headers, proxyHost, proxyPort) + resp = self._HttpRequest(method, host, path, port=port, data=data, + secure=secure, headers=headers, + proxyHost=proxyHost, proxyPort=proxyPort) return None def HttpGet(self, url, headers=None, maxRetry=3, chkProxy=False): - return self.HttpRequest("GET", url, None, headers, maxRetry, chkProxy) + return self.HttpRequest("GET", url, headers=headers, + maxRetry=maxRetry, chkProxy=chkProxy) def HttpHead(self, url, headers=None, maxRetry=3, chkProxy=False): - return self.HttpRequest("HEAD", url, None, headers, maxRetry, chkProxy) + return self.HttpRequest("HEAD", url, headers=headers, + maxRetry=maxRetry, chkProxy=chkProxy) def HttpPost(self, url, data, headers=None, maxRetry=3, chkProxy=False): - return self.HttpRequest("POST", url, data, headers, maxRetry, chkProxy) + return self.HttpRequest("POST", url, data=data, headers=headers, + maxRetry=maxRetry, chkProxy=chkProxy) def HttpPut(self, url, data, headers=None, maxRetry=3, chkProxy=False): - return self.HttpRequest("PUT", url, data, headers, maxRetry, chkProxy) + return self.HttpRequest("PUT", url, data=data, headers=headers, + maxRetry=maxRetry, chkProxy=chkProxy) def HttpDelete(self, url, headers=None, maxRetry=3, chkProxy=False): - return self.HttpRequest("DELETE", url, None, headers, maxRetry, chkProxy) + return self.HttpRequest("DELETE", url, headers=headers, + maxRetry=maxRetry, chkProxy=chkProxy) def HttpGetWithoutHeaders(self, url, maxRetry=3, chkProxy=False): """ Return data from an HTTP get on 'url'. """ - resp = self.HttpGet(url, None, maxRetry, chkProxy) + resp = self.HttpGet(url, headers=None, maxRetry=maxRetry, + chkProxy=chkProxy) return resp.read() if resp is not None else None def HttpGetWithHeaders(self, url, maxRetry=3, chkProxy=False): @@ -2780,10 +2811,10 @@ class Util(object): x-ms-agent-name and x-ms-version headers. """ - resp = self.HttpGet(url, { + resp = self.HttpGet(url, headers={ "x-ms-agent-name": GuestAgentName, "x-ms-version": ProtocolVersion - }, maxRetry, chkProxy) + }, maxRetry=maxRetry, chkProxy=chkProxy) return resp.read() if resp is not None else None def HttpSecureGetWithHeaders(self, url, transportCert, maxRetry=3, @@ -2791,21 +2822,22 @@ class Util(object): """ Return output of get using ssl cert. """ - resp = self.HttpGet(url, { + resp = self.HttpGet(url, headers={ "x-ms-agent-name": GuestAgentName, "x-ms-version": ProtocolVersion, "x-ms-cipher-name": "DES_EDE3_CBC", "x-ms-guest-agent-public-x509-cert": transportCert - }, maxRetry, chkProxy) + }, maxRetry=maxRetry, chkProxy=chkProxy) return resp.read() if resp is not None else None def HttpPostWithHeaders(self, url, data, maxRetry=3, chkProxy=False): - header = { + headers = { "x-ms-agent-name": GuestAgentName, "Content-Type": "text/xml; charset=utf-8", "x-ms-version": ProtocolVersion } - return self.HttpPost(url, data, header, maxRetry, chkProxy) + return self.HttpPost(url, data=data, headers=headers, + maxRetry=maxRetry, chkProxy=chkProxy) __StorageVersion="2014-02-14" @@ -2873,7 +2905,7 @@ def PutPageBlob(url, data): bufSize = pageEnd - start buf = bytearray(bufSize) buf[0 : contentSize] = data[start : end] - ret = restutil.HttpPut(url, buf, { + ret = restutil.HttpPut(url, buffer(buf), { "x-ms-date" : timestamp, "x-ms-range" : "bytes={0}-{1}".format(start, pageEnd - 1), "x-ms-page-write" : "update", @@ -2956,12 +2988,13 @@ class ConfigurationProvider(object): """ Parse amd store key:values in waagent.conf """ - def __init__(self): + def __init__(self, walaConfigFile): self.values = dict() if 'MyDistro' not in globals(): global MyDistro MyDistro = GetMyDistro() - walaConfigFile = MyDistro.getConfigurationPath() + if walaConfigFile is None: + walaConfigFile = MyDistro.getConfigurationPath() if os.path.isfile(walaConfigFile) == False: raise Exception("Missing configuration in {0}".format(walaConfigFile)) try: @@ -3239,35 +3272,6 @@ class SharedConfig(object): LogIfVerbose("Save SharedConfig.xml") SetFileContents("SharedConfig.xml", self.xmlText) - 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") if program != None: @@ -3277,9 +3281,105 @@ class SharedConfig(object): ErrorWithPrefix('Agent.Run','Exception: '+ str(e) +' occured launching ' + program ) def Process(self): - self.ConfigRdma() + global rdma_configured + if not rdma_configured and self.RdmaMacAddress is not None and self.RdmaIPv4Address is not None: + handler = RdmaHandler(self.RdmaMacAddress, self.RdmaIPv4Address) + handler.start() + rdma_configured = True self.InvokeTopologyConsumer() +rdma_configured = False + +class RdmaError(Exception): + pass + +class RdmaHandler(object): + """ + Handle rdma configuration. + """ + + def __init__(self, mac, ip_addr, dev="/dev/hvnd_rdma", + dat_conf_files=['/etc/dat.conf', '/etc/rdma/dat.conf', + '/usr/local/etc/dat.conf']): + self.mac = mac + self.ip_addr = ip_addr + self.dev = dev + self.dat_conf_files = dat_conf_files + self.data = ('rdmaMacAddress="{0}" rdmaIPv4Address="{1}"' + '').format(self.mac, self.ip_addr) + + def start(self): + """ + Start a new thread to process rdma + """ + threading.Thread(target=self.process).start() + + def process(self): + try: + self.set_dat_conf() + self.set_rdma_dev() + self.set_rdma_ip() + except RdmaError as e: + Error("Failed to config rdma device: {0}".format(e)) + + def set_dat_conf(self): + """ + Agent needs to search all possible locations for dat.conf + """ + Log("Set dat.conf") + for dat_conf_file in self.dat_conf_files: + if not os.path.isfile(dat_conf_file): + continue + try: + self.write_dat_conf(dat_conf_file) + except IOError as e: + raise RdmaError("Failed to write to dat.conf: {0}".format(e)) + + def write_dat_conf(self, dat_conf_file): + Log("Write config to {0}".format(dat_conf_file)) + 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.ip_addr) + lines = GetFileContents(dat_conf_file) + lines = re.sub(old, new, lines) + SetFileContents(dat_conf_file, lines) + + def set_rdma_dev(self): + """ + Write config string to /dev/hvnd_rdma + """ + Log("Set /dev/hvnd_rdma") + self.wait_rdma_dev() + self.write_rdma_dev_conf() + + def write_rdma_dev_conf(self): + Log("Write rdma config to {0}: {1}".format(self.dev, self.data)) + try: + with open(self.dev, "w") as c: + c.write(self.data) + except IOError, e: + raise RdmaError("Error writing {0}, {1}".format(self.dev, e)) + + def wait_rdma_dev(self): + Log("Wait for /dev/hvnd_rdma") + retry = 0 + while retry < 120: + if os.path.exists(self.dev): + return + time.sleep(1) + retry += 1 + raise RdmaError("The device doesn't show up in 120 seconds") + + def set_rdma_ip(self): + Log("Set ip addr for rdma") + try: + if_name = MyDistro.getInterfaceNameByMac(self.mac) + #Azure is using 12 bits network mask for infiniband. + MyDistro.configIpV4(if_name, self.ip_addr, 12) + except Exception as e: + raise RdmaError("Failed to config rdma device: {0}".format(e)) + class ExtensionsConfig(object): """ Parse ExtensionsConfig, downloading and unpacking them to /var/lib/waagent. @@ -5884,6 +5984,7 @@ def main(): if MyDistro == None : sys.exit(1) args = [] + conf_file = None global force force = False for a in sys.argv[1:]: @@ -5896,6 +5997,8 @@ def main(): myLogger.verbose = True elif re.match("^([-/]*)force", a): force = True + elif re.match("^(?:[-/]*)conf=.+", a): + conf_file = re.match("^(?:[-/]*)conf=(.+)", a).groups()[0] elif re.match("^([-/]*)(setup|install)", a): sys.exit(MyDistro.Install()) elif re.match("^([-/]*)(uninstall)", a): @@ -5903,8 +6006,14 @@ def main(): else: args.append(a) global Config - Config = ConfigurationProvider() + Config = ConfigurationProvider(conf_file) + logfile = Config.get("Logs.File") + if logfile is not None: + myLogger.file_path = logfile + logconsole = Config.get("Logs.Console") + if logconsole is not None and logconsole.lower().startswith("n"): + myLogger.con_path = None verbose = Config.get("Logs.Verbose") if verbose != None and verbose.lower().startswith("y"): myLogger.verbose=True -- cgit v1.2.3