summaryrefslogtreecommitdiff
path: root/waagent
diff options
context:
space:
mode:
Diffstat (limited to 'waagent')
-rw-r--r--waagent223
1 files changed, 166 insertions, 57 deletions
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))
@@ -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