diff options
Diffstat (limited to 'waagent')
| -rw-r--r-- | waagent | 223 |
1 files changed, 166 insertions, 57 deletions
@@ -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)) @@ -1315,6 +1322,18 @@ class debianDistro(AbstractDistro): 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 ############################################################ ubuntu_upstart_file = """\ @@ -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 |
