Hello community,

here is the log from the commit of package WALinuxAgent for openSUSE:Factory 
checked in at 2015-06-12 20:31:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/WALinuxAgent (Old)
 and      /work/SRC/openSUSE:Factory/.WALinuxAgent.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "WALinuxAgent"

Changes:
--------
--- /work/SRC/openSUSE:Factory/WALinuxAgent/WALinuxAgent.changes        
2015-04-16 14:12:32.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.WALinuxAgent.new/WALinuxAgent.changes   
2015-06-12 20:31:11.000000000 +0200
@@ -1,0 +2,11 @@
+Fri Jun  5 13:33:59 UTC 2015 - rjsch...@suse.com
+
+- Update to version 2.0.13 (bnc#933695,bnc#933761)
+  + Handle http 410 returned by host
+  + Add support for http proxy
+  + Add support to execute CustomData after provisioning
+  + Add a udev rule for product-uuid to be world readable (bnc#933774)
+  + Fix agent path for CoreOS
+  + Update service start/stop command for Ubuntu
+
+-------------------------------------------------------------------

Old:
----
  WALinuxAgent-2.0.12.tar.gz

New:
----
  WALinuxAgent-2.0.13.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ WALinuxAgent.spec ++++++
--- /var/tmp/diff_new_pack.RH312g/_old  2015-06-12 20:31:13.000000000 +0200
+++ /var/tmp/diff_new_pack.RH312g/_new  2015-06-12 20:31:13.000000000 +0200
@@ -20,7 +20,7 @@
 Summary:        The Windows Azure Linux Agent
 License:        Apache-2.0
 Group:          System/Daemons
-Version:        2.0.12
+Version:        2.0.13
 Release:        0
 Url:            https://github.com/Azure/WALinuxAgent
 Source0:        
https://github.com/Azure/%{name}/archive/%{name}-%{version}.tar.gz
@@ -102,9 +102,11 @@
 %if 0%{?suse_version} < 1230
 mkdir -p %{buildroot}/lib/udev/rules.d
 install -D -m 0644 %{SOURCE1} 
%{buildroot}/lib/udev/rules.d/99-azure-timeout.rules
+mv %{buildroot}/%{_sysconfdir}/udev/rules.d/99-azure-product-uuid.rules 
%{buildroot}/lib/udev/rules.d/
 %else
 mkdir -p %{buildroot}/usr/lib/udev/rules.d
 install -D -m 0644 %{SOURCE1} 
%{buildroot}/usr/lib/udev/rules.d/99-azure-timeout.rules
+mv %{buildroot}/%{_sysconfdir}/udev/rules.d/99-azure-product-uuid.rules 
%{buildroot}/usr/lib/udev/rules.d/
 %endif
 ### log file ghost
 mkdir -p  %{buildroot}/%{_localstatedir}/log
@@ -150,8 +152,10 @@
 %endif
 %if 0%{?suse_version} < 1230
 %config /lib/udev/rules.d/99-azure-timeout.rules
+%config /lib/udev/rules.d/99-azure-product-uuid.rules
 %else
 %config /usr/lib/udev/rules.d/99-azure-timeout.rules
+%config /usr/lib/udev/rules.d/99-azure-product-uuid.rules
 %endif
 
 %changelog

++++++ WALinuxAgent-2.0.12.tar.gz -> WALinuxAgent-2.0.13.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/Changelog 
new/WALinuxAgent-WALinuxAgent-2.0.13/Changelog
--- old/WALinuxAgent-WALinuxAgent-2.0.12/Changelog      2015-03-15 
15:16:08.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/Changelog      2015-06-01 
03:55:11.000000000 +0200
@@ -1,5 +1,13 @@
 WALinuxAgent                                                          Changelog
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+1 Jun 2015, WALinuxAgent 2.0.13
+   . Handle http 410 returned by host
+   . Add support for http proxy
+   . Add support to execute CustomData after provisioning
+   . Add a udev rule for product-uuid
+   . Fix agent path for CoreOS
+   . Update service start/stop command for Ubuntu
+
 15 Jan 2015, WALinuxAgent 2.0.12
    . Add support for page blob status report
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/README 
new/WALinuxAgent-WALinuxAgent-2.0.13/README
--- old/WALinuxAgent-WALinuxAgent-2.0.12/README 2015-03-15 15:16:08.000000000 
+0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/README 2015-06-01 03:55:11.000000000 
+0200
@@ -31,11 +31,11 @@
 
   * SCVMM Deployments
     - Detect and bootstrap the VMM agent for Linux when running in a System
-         Center Virtual Machine Manager 2012R2 environment
+      Center Virtual Machine Manager 2012R2 environment
 
   * VM Extension
     - Inject component authored by Microsoft and Partners into Linux VM (IaaS)
-         to enable software and configuration automation
+      to enable software and configuration automation
     - VM Extension reference implementation on 
https://github.com/Azure/azure-linux-extensions
 
 
@@ -90,8 +90,32 @@
 If installing manually, waagent should be copied to /usr/sbin/waagent and
 installed by running:
 
-       # sudo chmod 755 /usr/sbin/waagent
-       # sudo /usr/sbin/waagent -install -verbose
+    # sudo chmod 755 /usr/sbin/waagent
+    # sudo /usr/sbin/waagent -install -verbose
+
+The agent's log file is kept at /var/log/waagent.log.
+
+
+UPGRADE
+
+Upgrading via your distribution's package repository is preferred.
+
+If upgrading manually, same with installation above, waagent should be copied 
+to /usr/sbin/waagent to override original file and installed by running:
+
+    # sudo chmod 755 /usr/sbin/waagent
+
+Restart waagent service,for most of linux distributions:
+
+    #sudo service waagent restart
+
+For Ubuntu, use:
+
+    #sudo service walinuxagent restart
+
+For CoreOS, use:
+
+    #sudo systemctl restart waagent 
 
 The agent's log file is kept at /var/log/waagent.log.
 
@@ -171,6 +195,8 @@
 Provisioning.RegenerateSshHostKeyPair=y
 Provisioning.SshHostKeyPairType=rsa
 Provisioning.MonitorHostName=y
+Provisioning.DecodeCustomData=n
+Provisioning.ExecuteCustomData=n
 ResourceDisk.Format=y
 ResourceDisk.Filesystem=ext4
 ResourceDisk.MountPoint=/mnt/resource
@@ -180,6 +206,8 @@
 Logs.Verbose=n
 OS.RootDeviceScsiTimeout=300
 OS.OpensslPath=None
+HttpProxy.Host=None
+HttpProxy.Port=None
 
 The various configuration options are described in detail below. Configuration
 options are of three types : Boolean, String or Integer. The Boolean
@@ -260,6 +288,16 @@
 servers, networking will be restarted in the VM. This will result in brief loss
 of Internet connectivity.
 
+Provisioning.DecodeCustomData:
+Type: Boolean Default: n
+
+If set, waagent will decode CustomData from Base64.
+
+Provisioning.ExecuteCustomData:
+Type: Boolean Default: n
+
+If set, waagent will execute CustomData after provisioning.
+
 ResourceDisk.Format:
 Type: Boolean Default: y
 
@@ -317,6 +355,11 @@
 This can be used to specify an alternate path for the openssl binary to use for
 cryptographic operations.
 
+HttpProxy.Host=None
+HttpProxy.Port=None
+Type: String Default: None
+
+If set, agent will use proxy server to access internet
 
 APPENDIX
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/WALinuxAgent-WALinuxAgent-2.0.12/config/99-azure-product-uuid.rules 
new/WALinuxAgent-WALinuxAgent-2.0.13/config/99-azure-product-uuid.rules
--- old/WALinuxAgent-WALinuxAgent-2.0.12/config/99-azure-product-uuid.rules     
1970-01-01 01:00:00.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/config/99-azure-product-uuid.rules     
2015-06-01 03:55:11.000000000 +0200
@@ -0,0 +1,9 @@
+SUBSYSTEM!="dmi", GOTO="product_uuid-exit"
+ATTR{sys_vendor}!="Microsoft Corporation", GOTO="product_uuid-exit"
+ATTR{product_name}!="Virtual Machine", GOTO="product_uuid-exit"
+TEST!="/sys/devices/virtual/dmi/id/product_uuid", GOTO="product_uuid-exit"
+
+RUN+="/bin/chmod 0444 /sys/devices/virtual/dmi/id/product_uuid"
+
+LABEL="product_uuid-exit"
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/config/waagent.conf 
new/WALinuxAgent-WALinuxAgent-2.0.13/config/waagent.conf
--- old/WALinuxAgent-WALinuxAgent-2.0.12/config/waagent.conf    2015-03-15 
15:16:08.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/config/waagent.conf    2015-06-01 
03:55:11.000000000 +0200
@@ -28,6 +28,12 @@
 # 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
 
@@ -55,3 +61,8 @@
 
 # If "None", the system default version is used.
 OS.OpensslPath=None
+
+# If set, agent will use proxy server to access internet
+#HttpProxy.Host=None
+#HttpProxy.Port=None
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/fix-gpt-ubuntu.py 
new/WALinuxAgent-WALinuxAgent-2.0.13/fix-gpt-ubuntu.py
--- old/WALinuxAgent-WALinuxAgent-2.0.12/fix-gpt-ubuntu.py      2015-03-15 
15:16:08.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/fix-gpt-ubuntu.py      2015-06-01 
03:55:11.000000000 +0200
@@ -26,7 +26,7 @@
 a new one using the entire disk space.
 """
 if __name__ == '__main__':
-    print 'Umnout resource disk...'
+    print 'Unmount resource disk...'
     subprocess.call(['umount', '/dev/sdb1'])
     print 'Remove old partitions...'
     subprocess.call(['parted', '/dev/sdb', 'rm', '1'])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/WALinuxAgent-WALinuxAgent-2.0.12/rpm/walinuxagent.spec 
new/WALinuxAgent-WALinuxAgent-2.0.13/rpm/walinuxagent.spec
--- old/WALinuxAgent-WALinuxAgent-2.0.12/rpm/walinuxagent.spec  2015-03-15 
15:16:08.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/rpm/walinuxagent.spec  2015-06-01 
03:55:11.000000000 +0200
@@ -2,19 +2,19 @@
 # Name: walinuxagent.spec
 
#-------------------------------------------------------------------------------
 # Purpose : RPM Spec file for Python script packaging
-# Version : 2.0.8
+# Version : 2.0.13
 # Created : April 20 2012
 
#===============================================================================
 
 Name:           WALinuxAgent
 Summary:        The Windows Azure Linux Agent
-Version:        2.0.8
+Version:        2.0.13
 Release:        1
 License:        Apache License Version 2.0
 Group:          System/Daemons
 Url:            http://go.microsoft.com/fwlink/?LinkId=250998
-Source0:        WALinuxAgent-2.0.8.tar.gz
-Requires:       python python-pyasn1 openssh openssl util-linux sed grep sudo 
iptables
+Source0:        WALinuxAgent-2.0.13.tar.gz
+Requires:       python python-pyasn1 openssh openssl util-linux sed grep sudo 
iptables parted
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 BuildArch:      noarch
 Vendor:         Microsoft Corporation
@@ -61,7 +61,8 @@
 
 
 %files
-%attr(0755,root,root) %{_initddir}/waagent
+%attr(0755,root,root) %{_sysconfdir}/rc.d/init.d/waagent
+%attr(0755,root,root) %{_sysconfdir}/udev/rules.d/99-azure-product-uuid.rules
 %defattr(0644,root,root,0755)
 %doc Changelog LICENSE-2.0.txt NOTICE README
 %attr(0755,root,root) %{_sbindir}/waagent
@@ -75,7 +76,7 @@
 * Thu Sep 18 2014 - walinuxag...@microsoft.com
 - Remove NetworkManager conflict for EL7+
 
-* Thu Mar 25 2014 - walinuxag...@microsoft.com
+* Sun Mar 25 2014 - walinuxag...@microsoft.com
 - Create directory /var/lib/waagent
 - Updated version to 2.0.4 for release
 
@@ -91,13 +92,13 @@
 * Fri Sep 20 2013 - walinuxag...@microsoft.com
 - Updated version to 2.0.0 for release
 
-* Thu Aug 23 2013 - walinuxag...@microsoft.com
+* Fri Aug 23 2013 - walinuxag...@microsoft.com
 - Updated version to 1.4.0 for release
 
 * Thu May 30 2013 - walinuxag...@microsoft.com
 - Updated version to 1.3.3 for release
 
-* Fri Feb 26 2013 - walinuxag...@microsoft.com
+* Tue Feb 26 2013 - walinuxag...@microsoft.com
 - Updated version to 1.3.2 for release
 
 * Fri Feb 15 2013 - walinuxag...@microsoft.com
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/script/buildrpm.sh 
new/WALinuxAgent-WALinuxAgent-2.0.13/script/buildrpm.sh
--- old/WALinuxAgent-WALinuxAgent-2.0.12/script/buildrpm.sh     1970-01-01 
01:00:00.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/script/buildrpm.sh     2015-06-01 
03:55:11.000000000 +0200
@@ -0,0 +1,31 @@
+script=$(dirname $0)
+root=$script/..
+cd $root
+root=`pwd`
+
+version=WALinuxAgent-2.0.13
+
+mkdir -p ~/rpmbuild/TMP
+mkdir -p ~/rpmbuild/SPECS
+mkdir -p ~/rpmbuild/SOURCES
+
+
+echo "rsync -a --exclude '.*' $root/ ~/rpmbuild/TMP/$version"
+rsync -a --exclude '.*' $root/ ~/rpmbuild/TMP/$version
+
+echo "cd ~/rpmbuild/TMP"
+cd ~/rpmbuild/TMP
+
+echo "tar -czf ${version}.tar.gz $version"
+tar -czf ${version}.tar.gz $version
+
+echo "cp $root/rpm/walinuxagent.spec ~/rpmbuild/SPECS"
+cp $root/rpm/walinuxagent.spec ~/rpmbuild/SPECS
+
+echo "cp ~/rpmbuild/TMP/${version}.tar.gz ~/rpmbuild/SOURCES"
+cp ~/rpmbuild/TMP/${version}.tar.gz ~/rpmbuild/SOURCES
+
+echo "rpmbuild -ba ~/rpmbuild/SPECS/walinuxagent.spec"
+rpmbuild -ba ~/rpmbuild/SPECS/walinuxagent.spec
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/setup.py 
new/WALinuxAgent-WALinuxAgent-2.0.13/setup.py
--- old/WALinuxAgent-WALinuxAgent-2.0.12/setup.py       2015-03-15 
15:16:08.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/setup.py       2015-06-01 
03:55:11.000000000 +0200
@@ -41,7 +41,6 @@
         distro = 'redhat'
 
     return distro
-    
 
 class InstallData(install):
     user_options = install.user_options + [
@@ -133,19 +132,33 @@
     
         # Configuration file
         if not os.path.exists(tgtDir + 'etc'):
-                try:
-                    self.mkpath(tgtDir + 'etc', 0755)
-                except:
-                    msg = 'Could not create config dir '
-                    msg += tgtDir
-                    msg += 'etc'
-                    print msg
-                    sys.exit(1)
+            try:
+                self.mkpath(tgtDir + 'etc', 0755)
+            except:
+                msg = 'Could not create config dir '
+                msg += tgtDir
+                msg += 'etc'
+                print msg
+                sys.exit(1)
         try:
             self.copy_file('config/waagent.conf', tgtDir + 'etc/waagent.conf')
         except:
-            print 'Could not install configuration file %etc' %tgtDir
+            print 'Could not install configuration file %setc' %tgtDir
+            sys.exit(1)
+
+        if not os.path.exists(tgtDir + 'etc/udev/rules.d'):
+            try:
+                self.mkpath(tgtDir + 'etc/udev/rules.d', 0755)
+            except Exception as e:
+                print e
+
+        try:
+            self.copy_file('config/99-azure-product-uuid.rules', tgtDir + 
'etc/udev/rules.d/99-azure-product-uuid.rules')
+        except Exception as e:
+            print e
+            print 'Could not install product uuid rules file %setc' %tgtDir
             sys.exit(1)
+
         if not os.path.exists(tgtDir + 'etc/logrotate.d'):
             try:
                 self.mkpath(tgtDir + 'etc/logrotate.d', 0755)
@@ -161,7 +174,7 @@
             msg += tgtDir + 'etc/logrotate.d'
             print  msg
             sys.exit(1)
-    
+         
         # Daemon
         if not os.path.exists(tgtDir + prefix + 'sbin'):
             try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/tests/__init__.py 
new/WALinuxAgent-WALinuxAgent-2.0.13/tests/__init__.py
--- old/WALinuxAgent-WALinuxAgent-2.0.12/tests/__init__.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/tests/__init__.py      2015-06-01 
03:55:11.000000000 +0200
@@ -0,0 +1,19 @@
+# Copyright 2014 Microsoft Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Requires Python 2.4+ and Openssl 1.0+
+#
+# Implements parts of RFC 2131, 1541, 1497 and
+# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx
+# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/tests/env.py 
new/WALinuxAgent-WALinuxAgent-2.0.13/tests/env.py
--- old/WALinuxAgent-WALinuxAgent-2.0.12/tests/env.py   2015-03-15 
15:16:08.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/tests/env.py   2015-06-01 
03:55:11.000000000 +0200
@@ -15,9 +15,11 @@
 
 import imp
 import os
+import sys
 
-projet_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-waagent = imp.load_source('waagent', os.path.join(projet_root, 'waagent'))
+project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+waagent = imp.load_source('waagent', os.path.join(project_root, 'waagent'))
+sys.path.insert(0, project_root)
 
 waagent.LoggerInit('/dev/stdout', '/dev/null')
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/tests/test_http.py 
new/WALinuxAgent-WALinuxAgent-2.0.13/tests/test_http.py
--- old/WALinuxAgent-WALinuxAgent-2.0.12/tests/test_http.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/tests/test_http.py     2015-06-01 
03:55:11.000000000 +0200
@@ -0,0 +1,147 @@
+# Copyright 2014 Microsoft Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import unittest
+from env import waagent
+import sys
+from tests.tools import *
+
+class MockHTTPResponse(object):
+    def __init__(self, status=200):
+        self.status = status
+        self.reason = "foo"
+
+    def getheaders(*args, **kwargs):
+        return {"hehe" : "haha"}
+
+    def read(*args, **kwargs):
+        return "bar"
+
+class MockOldHTTPConnection(object):
+    MockHost=None
+    MockPort=None
+    MockUrl=None
+    MockCallCount=0
+
+    def __init__(self, host, port):
+        self.__class__.MockHost = host
+        self.__class__.MockPort = port
+
+    def request(self, method, url, data, headers = None):
+        self.__class__.MockUrl = url
+        self.__class__.MockCallCount += 1
+    
+    def getresponse(*args, **kwargs):
+        return MockHTTPResponse()
+
+class MockHTTPConnection(MockOldHTTPConnection):
+    def set_tunnel(*args, **kwargs):
+        pass
+
+class MockBadHTTPConnection(MockHTTPConnection):
+    def getresponse(*args, **kwargs):
+        return MockHTTPResponse(500)
+
+class MockHttpLib(object):
+    def __init__(self):
+        self.HTTPConnection = MockHTTPConnection
+        self.OK = 200
+
+MockOSEnv = {
+        "http_proxy":"http://httpproxy:8888";,
+        "https_proxy":"https://httpsproxy:8888";
+}
+
+class TestHttp(unittest.TestCase):
+
+    def test_parseurl(self):
+        httputil = waagent.Util()
+        host, port, secure, path = httputil._ParseUrl("http://foo:8/bar?hehe";)
+        self.assertEquals("foo", host)
+        self.assertEquals(8, port)
+        self.assertEquals(False, secure)
+        self.assertEquals("/bar?hehe", path)
+        
+        host, port, secure, path = httputil._ParseUrl("http://foo.bar/";)
+        self.assertEquals("foo.bar", host)
+        self.assertEquals(80, port)
+        self.assertEquals(False, secure)
+        self.assertEquals("/", path)
+
+        host, port, secure, path= httputil._ParseUrl("https://foo.bar/";)
+        self.assertEquals("foo.bar", host)
+        self.assertEquals(80, port)
+        self.assertEquals(True, secure)
+        self.assertEquals("/", path)
+
+        self.assertRaises(ValueError, httputil._ParseUrl, 
+                          "https://a:b...@foo.bar/";)
+
+        host, port, secure, path = httputil._ParseUrl("https://foo.bar";)
+        self.assertEquals("foo.bar", host)
+        self.assertEquals(80, port)
+        self.assertEquals(True, secure)
+        self.assertEquals("/", path)
+
+        host, port, secure, path = 
httputil._ParseUrl("http://a:b...@foo.bar:8888";)
+        self.assertEquals("a:b...@foo.bar", host)
+        self.assertEquals(8888, port)
+        self.assertEquals(False, secure)
+        self.assertEquals("/", path)
+    
+    @Mockup(waagent.httplib, "HTTPConnection", MockHTTPConnection)
+    @Mockup(waagent.os, "environ", MockOSEnv)
+    def test_http_request(self):
+        httputil = waagent.Util()
+
+        #If chkProxy is on, host and port should point to proxy server
+        httputil.HttpRequest("GET", "http://foo.bar/get";, chkProxy=True)
+        self.assertEquals("httpproxy", MockHTTPConnection.MockHost) 
+        self.assertEquals(8888, MockHTTPConnection.MockPort) 
+        self.assertEquals("http://foo.bar:80/get";, MockHTTPConnection.MockUrl) 
+        
+        #If chkProxy is off, ignore proxy
+        httputil.HttpRequest("GET", "http://foo.bar/get";, chkProxy=False)
+        self.assertEquals("foo.bar", MockHTTPConnection.MockHost) 
+        self.assertEquals(80, MockHTTPConnection.MockPort) 
+        self.assertEquals("/get", MockHTTPConnection.MockUrl) 
+
+    @Mockup(waagent, "httplib" , MockHttpLib())
+    def test_https_fallback(self):
+        httputil = waagent.Util()
+        print "The bellowing warning log is expected:"
+        httputil.HttpRequest("GET", "https://foo.bar/get";)
+        self.assertEquals("/get", MockHTTPConnection.MockUrl)
+
+    @Mockup(waagent.httplib, "HTTPConnection", MockOldHTTPConnection)
+    @Mockup(waagent.httplib, "HTTPSConnection", MockOldHTTPConnection)
+    @Mockup(waagent.os, "environ", MockOSEnv)
+    def test_https_fallback2(self):
+        httputil = waagent.Util()
+        print "The bellowing warning log is expected:"
+        httputil.HttpRequest("GET", "https://foo.bar/get";, chkProxy=True)
+        self.assertEquals("http://foo.bar:80/get";, 
MockOldHTTPConnection.MockUrl)
+
+    @Mockup(waagent.Util, "RetryWaitingInterval", 0)
+    @Mockup(waagent.httplib, "HTTPConnection", MockBadHTTPConnection)
+    def test_retry(self):
+        httputil = waagent.Util()
+        MockBadHTTPConnection.MockCallCount=0
+        print "The bellowing error log is expected:"
+        httputil.HttpRequest("GET", "http://foo.bar";, chkProxy=False, 
maxRetry=1)
+        self.assertEquals(2, MockBadHTTPConnection.MockCallCount)
+    
+if __name__ == '__main__':
+    unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/WALinuxAgent-WALinuxAgent-2.0.12/tests/test_shared_config.py 
new/WALinuxAgent-WALinuxAgent-2.0.13/tests/test_shared_config.py
--- old/WALinuxAgent-WALinuxAgent-2.0.12/tests/test_shared_config.py    
2015-03-15 15:16:08.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/tests/test_shared_config.py    
2015-06-01 03:55:11.000000000 +0200
@@ -16,6 +16,12 @@
 import unittest
 from env import waagent
 
+class MockDistro(object):
+    def getInterfaceNameByMac(self, mac):
+        pass
+
+    def configIpV4(self, ifName, addr):
+        pass
 
 class TestSharedConfig(unittest.TestCase):
     
@@ -24,10 +30,12 @@
         self.assertNotEquals(None, conf)
         self.assertNotEquals(None, conf.RdmaMacAddress)
         self.assertNotEquals(None, conf.RdmaIPv4Address)
+        self.assertEquals("00:15:5D:34:00:44", conf.RdmaMacAddress)
         return conf
 
     def test_config_rdma(self):
-        waagent.LoggerInit("/dev/stdout", "/dev/null", verbose=True)
+        #waagent.LoggerInit("/dev/stdout", "/dev/null", verbose=True)
+        waagent.MyDistro= MockDistro()
         testDev = "/tmp/hvnd_rdma"
         waagent.SetFileContents(testDev, "")
         conf = self.test_parse_shared_config()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/tests/test_util.py 
new/WALinuxAgent-WALinuxAgent-2.0.13/tests/test_util.py
--- old/WALinuxAgent-WALinuxAgent-2.0.12/tests/test_util.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/tests/test_util.py     2015-06-01 
03:55:11.000000000 +0200
@@ -0,0 +1,61 @@
+# Copyright 2014 Microsoft Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import unittest
+from env import waagent
+import sys
+from tests.tools import *
+
+SampleInterfaceInfo="""\
+eth0      Link encap:Ethernet  HWaddr ff:ff:ff:ff:ff:ff  
+          inet addr:10.94.20.249  Bcast:10.94.23.255  Mask:255.255.252.0
+          inet6 addr: fe80::215:5dff:fe5f:bf03/64 Scope:Link
+          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
+          RX packets:3789880 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:80973 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:1000 
+          RX bytes:388563383 (388.5 MB)  TX bytes:21484571 (21.4 MB)
+
+eth1      Link encap:Ethernet  HWaddr 00:00:00:00:00:00  
+          inet addr:192.168.1.1  Bcast:192.168.1.255  Mask:255.255.255.0
+          inet6 addr: fe80::215:5dff:fe5f:bf08/64 Scope:Link
+          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
+          RX packets:386614 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:201356 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:1000 
+          RX bytes:32507619 (32.5 MB)  TX bytes:78342503 (78.3 MB)
+
+lo        Link encap:Local Loopback  
+          inet addr:127.0.0.1  Mask:255.0.0.0
+          inet6 addr: ::1/128 Scope:Host
+          UP LOOPBACK RUNNING  MTU:65536  Metric:1
+          RX packets:2561 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:2561 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:0 
+"""
+
+class TestUtil(unittest.TestCase):
+
+    @Mockup(waagent, "RunGetOutput", MockFunc('', (0, SampleInterfaceInfo)))
+    def test_getInterfaceNameByMac(self):
+        distro = waagent.AbstractDistro()
+        ifName = distro.getInterfaceNameByMac("ff:ff:ff:ff:ff:ff")
+        self.assertEquals("eth0", ifName)
+        ifName = distro.getInterfaceNameByMac("00:00:00:00:00:00")
+        self.assertEquals("eth1", ifName)
+        
+
+if __name__ == '__main__':
+    unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/tests/test_utils.py 
new/WALinuxAgent-WALinuxAgent-2.0.13/tests/test_utils.py
--- old/WALinuxAgent-WALinuxAgent-2.0.12/tests/test_utils.py    2015-03-15 
15:16:08.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/tests/test_utils.py    2015-06-01 
03:55:11.000000000 +0200
@@ -14,6 +14,8 @@
 #
 
 import unittest
+import tempfile
+import os
 from env import waagent
 
 sample_mount_list = """\
@@ -43,5 +45,39 @@
         mp = waagent.GetMountPoint(malformed, device_name)
         self.assertEqual(mp, None)
 
+    def test_replace_in_file_found(self):
+        tmpfilename = tempfile.mkstemp('', 'tmp', None, True)[1]
+        try:
+            tmpfile = open(tmpfilename, 'w')
+            tmpfile.write('Replace Me')
+            tmpfile.close()
+
+            result = waagent.ReplaceStringInFile(tmpfilename, r'c. ', 'ced ')
+
+            tmpfile = open(tmpfilename, 'r')
+            newcontents = tmpfile.read();
+            tmpfile.close()
+
+            self.assertEqual('Replaced Me', str(newcontents))
+        finally:
+            os.remove(tmpfilename)
+
+    def test_replace_in_file_not_found(self):
+        tmpfilename = tempfile.mkstemp('', 'tmp', None, True)[1]
+        try:
+            tmpfile = open(tmpfilename, 'w')
+            tmpfile.write('Replace Me')
+            tmpfile.close()
+
+            result = waagent.ReplaceStringInFile(tmpfilename, r'not here ', 
'ced ')
+
+            tmpfile = open(tmpfilename, 'r')
+            newcontents = tmpfile.read();
+            tmpfile.close()
+
+            self.assertEqual('Replace Me', str(newcontents))
+        finally:
+            os.remove(tmpfilename)
+
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/tests/tools.py 
new/WALinuxAgent-WALinuxAgent-2.0.13/tests/tools.py
--- old/WALinuxAgent-WALinuxAgent-2.0.12/tests/tools.py 1970-01-01 
01:00:00.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/tests/tools.py 2015-06-01 
03:55:11.000000000 +0200
@@ -0,0 +1,61 @@
+# Copyright 2014 Microsoft Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Requires Python 2.4+ and Openssl 1.0+
+#
+# Implements parts of RFC 2131, 1541, 1497 and
+# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx
+# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx
+
+
+import os
+import sys
+
+parent = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+sys.path.append(parent)
+
+def simple_file_grep(file_path, search_str):
+    for line in open(file_path):
+         if search_str in line:
+                return line
+
+def Mockup(target, name, mock):
+    def Decorator(func):
+        def Wrapper(*args, **kwargs):
+            origin = getattr(target, name)
+            setattr(target, name, mock)
+            try:
+                result = func(*args, **kwargs)
+            except:
+                raise
+            finally:
+                setattr(target, name, origin)
+            return result
+        return Wrapper
+    return Decorator
+
+class MockFunc():
+    def __init__(self, name='', retval=None):
+        self.name = name
+        self.retval = retval
+
+    def __call__(*args, **kwargs):
+        self = args[0]
+        self.args = args[1:]
+        self.kwargs = kwargs
+        return self.retval
+
+def Dummy():
+    pass
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/WALinuxAgent-WALinuxAgent-2.0.12/waagent 
new/WALinuxAgent-WALinuxAgent-2.0.13/waagent
--- old/WALinuxAgent-WALinuxAgent-2.0.12/waagent        2015-03-15 
15:16:08.000000000 +0100
+++ new/WALinuxAgent-WALinuxAgent-2.0.13/waagent        2015-06-01 
03:55:11.000000000 +0200
@@ -80,7 +80,7 @@
     
 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 @@
                 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 @@
 
     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 @@
         """
         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 @@
     
     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 @@
         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 @@
 
     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 @@
             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 @@
     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 httplib module is not built with ssl support. Failback to http
-            if secure and hasattr(httplib, "HTTPSConnection"):
-                httpConnection = httplib.HTTPSConnection(host)
+        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
+
+    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 @@
         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 @@
                     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 @@
                 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 @@
         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 @@
             "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 @@
     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 @@
         "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 @@
         "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 @@
             "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 @@
         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 @@
         """
         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 @@
         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 @@
                 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 @@
                     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 @@
                 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 @@
                                                                 
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 @@
         """
         Calls HostingEnvironmentConfig.Process()
         """
+        LogIfVerbose("Process goalstate")
         self.HostingEnvironmentConfig.Process()
         self.SharedConfig.Process()
-        self.SharedConfig.Save()
         
 class OvfEnv(object):
     """
@@ -4170,7 +4273,7 @@
         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 @@
             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 @@
             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 @@
         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 @@
             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 @@
                         #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 @@
                 #
                 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 @@
                 eventMonitor = WALAEventMonitor(self.HttpPostWithHeaders)
                 eventMonitor.StartEventsLoop()
 
-            time.sleep(25 - sleepToReduceAccessDenied) 
+            time.sleep(25 - sleepToReduceAccessDenied)
 
             
 WaagentLogrotate = """\
@@ -5513,14 +5638,14 @@
     """
     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 @@
         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 @@
     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 @@
     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 :


Reply via email to