[#783] -- The agent fails to use the standard Linux environment variables for HTTP proxy

[#830] -- Ensure VM identifier is properly ordered

Signed-off-by: Brendan Dixon <brendandixon@me.com>
This commit is contained in:
Brendan Dixon
2017-08-11 13:20:53 -07:00
parent 0038baf366
commit 285aeff238
14 changed files with 308 additions and 80 deletions
+26 -22
View File
@@ -50,6 +50,12 @@ The information flow from the platform to the agent occurs via two channels:
* A TCP endpoint exposing a REST API used to obtain deployment and topology
configuration.
The agent will use an HTTP proxy if provided via the `http_proxy` (for `http` requests) or
`https_proxy` (for `https` requests) environment variables. The `HttpProxy.Host` and
`HttpProxy.Port` configuration variables (see below), if used, will override the environment
settings. Due to limitations of Python, the agent *does not* support HTTP proxies requiring
authentication.
### REQUIREMENTS
@@ -58,21 +64,6 @@ Linux Agent. Please note that this list may differ from the official list
of supported systems on the Microsoft Azure Platform as described here:
http://support.microsoft.com/kb/2805216
Supported Linux Distributions:
* Archlinux
* CoreOS
* CentOS 6.2+
* Red Hat Enterprise Linux 6.7+
* Debian 7.0+
* Ubuntu 12.04+
* openSUSE 12.3+
* SLES 11 SP2+
* Oracle Linux 6.4+
Other Supported Systems:
* FreeBSD 10+ (Azure Linux Agent v2.0.10+)
* OpenBSD 6+ (Azure Linux Agent v2.2.11+)
Waagent depends on some system packages in order to function properly:
* Python 2.6+
@@ -192,6 +183,7 @@ ResourceDisk.EnableSwap=n
ResourceDisk.SwapSizeMB=0
LBProbeResponder=y
Logs.Verbose=n
OS.AllowHTTP=n
OS.RootDeviceScsiTimeout=300
OS.EnableFIPS=n
OS.OpensslPath=None
@@ -351,6 +343,16 @@ _Default: n_
If set, log verbosity is boosted. Waagent logs to /var/log/waagent.log and
leverages the system logrotate functionality to rotate logs.
* __OS.AllowHTTP__
_Type: Boolean_
_Default: n_
If set to `y` and SSL support is not compiled into Python, the agent will fall-back to
use HTTP. Otherwise, if SSL support is not compiled into Python, the agent will fail
all HTTPS requests.
Note: Allowing HTTP may unintentionally expose secure data.
* __OS.EnableRDMA__
_Type: Boolean_
_Default: n_
@@ -358,9 +360,9 @@ _Default: n_
If set, the agent will attempt to install and then load an RDMA kernel driver
that matches the version of the firmware on the underlying hardware.
* __OS.EnableFIPS__
_Type: Boolean_
_Default: n_
* __OS.EnableFIPS__
_Type: Boolean_
_Default: n_
If set, the agent will emit into the environment "OPENSSL_FIPS=1" when executing
OpenSSL commands. This signals OpenSSL to use any installed FIPS-compliant libraries.
@@ -381,9 +383,9 @@ _Default: None_
This can be used to specify an alternate path for the openssl binary to use for
cryptographic operations.
* __OS.SshDir__
_Type: String_
_Default: "/etc/ssh"_
* __OS.SshDir__
_Type: String_
_Default: `/etc/ssh`_
This option can be used to override the normal location of the SSH configuration
directory.
@@ -392,7 +394,9 @@ directory.
_Type: String_
_Default: None_
If set, the agent will use this proxy server to access the internet.
If set, the agent will use this proxy server to access the internet. These values
*will* override the `http_proxy` or `https_proxy` environment variables. Lastly,
`HttpProxy.Host` is required (if to be used) and `HttpProxy.Port` is optional.
### APPENDIX
+44 -6
View File
@@ -53,7 +53,7 @@ if needed.
DMIDECODE_CMD = 'dmidecode --string system-uuid'
PRODUCT_ID_FILE = '/sys/class/dmi/id/product_uuid'
UUID_PATTERN = re.compile(
'^\s*[A-F0-9]{8}(?:\-[A-F0-9]{4}){3}\-[A-F0-9]{12}\s*$',
r'^\s*[A-F0-9]{8}(?:\-[A-F0-9]{4}){3}\-[A-F0-9]{12}\s*$',
re.IGNORECASE)
class DefaultOSUtil(object):
@@ -63,6 +63,43 @@ class DefaultOSUtil(object):
self.selinux = None
self.disable_route_warning = False
def _correct_instance_id(self, id):
'''
Azure stores the instance ID with an incorrect byte ordering for the
first parts. For example, the ID returned by the metadata service:
D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8
will be found as:
544CDFD0-CB4E-4B4A-9954-5BDF3ED5C3B8
This code corrects the byte order such that it is consistent with
that returned by the metadata service.
'''
if not UUID_PATTERN.match(id):
return id
parts = id.split('-')
return '-'.join([
textutil.swap_hexstring(parts[0], width=2),
textutil.swap_hexstring(parts[1], width=2),
textutil.swap_hexstring(parts[2], width=2),
parts[3],
parts[4]
])
def is_current_instance_id(self, id_that):
'''
Compare two instance IDs for equality, but allow that some IDs
may have been persisted using the incorrect byte ordering.
'''
id_this = self.get_instance_id()
return id_that == id_this or \
id_that == self._correct_instance_id(id_this)
def get_agent_conf_file_path(self):
return self.agent_conf_file_path
@@ -74,13 +111,14 @@ class DefaultOSUtil(object):
If nothing works (for old VMs), return the empty string
'''
if os.path.isfile(PRODUCT_ID_FILE):
return fileutil.read_file(PRODUCT_ID_FILE).strip()
s = fileutil.read_file(PRODUCT_ID_FILE).strip()
rc, s = shellutil.run_get_output(DMIDECODE_CMD)
if rc != 0 or UUID_PATTERN.match(s) is None:
return ""
else:
rc, s = shellutil.run_get_output(DMIDECODE_CMD)
if rc != 0 or UUID_PATTERN.match(s) is None:
return ""
return s.strip()
return self._correct_instance_id(s.strip())
def get_userentry(self, username):
try:
+1 -1
View File
@@ -317,7 +317,7 @@ class Protocol(DataContract):
def download_ext_handler_pkg(self, uri, headers=None):
try:
resp = restutil.http_get(uri, chk_proxy=True, headers=headers)
resp = restutil.http_get(uri, use_proxy=True, headers=headers)
if restutil.request_succeeded(resp):
return resp.read()
except Exception as e:
+7 -7
View File
@@ -541,7 +541,7 @@ class WireClient(object):
try:
# Never use the HTTP proxy for wireserver
kwargs['chk_proxy'] = False
kwargs['use_proxy'] = False
resp = http_req(*args, **kwargs)
except Exception as e:
raise ProtocolError("[Wireserver Exception] {0}".format(
@@ -591,8 +591,8 @@ class WireClient(object):
@staticmethod
def call_storage_service(http_req, *args, **kwargs):
# Default to use the configured HTTP proxy
if not 'chk_proxy' in kwargs or kwargs['chk_proxy'] is None:
kwargs['chk_proxy'] = True
if not 'use_proxy' in kwargs or kwargs['use_proxy'] is None:
kwargs['use_proxy'] = True
return http_req(*args, **kwargs)
@@ -613,7 +613,7 @@ class WireClient(object):
try:
host = self.get_host_plugin()
uri, headers = host.get_artifact_request(version.uri)
response = self.fetch(uri, headers, chk_proxy=False)
response = self.fetch(uri, headers, use_proxy=False)
# If the HostPlugin rejects the request,
# let the error continue, but set to use the HostPlugin
@@ -632,14 +632,14 @@ class WireClient(object):
raise ProtocolError("Failed to fetch manifest from all sources")
def fetch(self, uri, headers=None, chk_proxy=None):
def fetch(self, uri, headers=None, use_proxy=None):
logger.verbose("Fetch [{0}] with headers [{1}]", uri, headers)
try:
resp = self.call_storage_service(
restutil.http_get,
uri,
headers=headers,
chk_proxy=chk_proxy)
use_proxy=use_proxy)
if restutil.request_failed(resp):
msg = "[Storage Failed] URI {0} ".format(uri)
@@ -1054,7 +1054,7 @@ class WireClient(object):
host = self.get_host_plugin()
uri, headers = host.get_artifact_request(blob)
config = self.fetch(uri, headers, chk_proxy=False)
config = self.fetch(uri, headers, use_proxy=False)
profile = self.decode_config(config)
if not textutil.is_str_none_or_whitespace(profile):
+44 -21
View File
@@ -17,6 +17,7 @@
# Requires Python 2.4+ and Openssl 1.0+
#
import os
import time
import traceback
@@ -83,6 +84,9 @@ RETRY_IOERRORS = [
112 # EHOSTDOWN -- Host is down
]
HTTP_PROXY_ENV = "http_proxy"
HTTPS_PROXY_ENV = "https_proxy"
def _is_retry_status(status, retry_codes=RETRY_CODES):
return status in retry_codes
@@ -109,9 +113,25 @@ def _parse_url(url):
return o.hostname, o.port, secure, rel_uri
def _get_http_proxy():
def _get_http_proxy(secure=False):
# Prefer the configuration settings over environment variables
host = conf.get_httpproxy_host()
port = conf.get_httpproxy_port()
port = None
if not host is None:
port = conf.get_httpproxy_port()
else:
http_proxy_env = HTTPS_PROXY_ENV if secure else HTTP_PROXY_ENV
http_proxy_url = None
for v in [http_proxy_env, http_proxy_env.upper()]:
if v in os.environ:
http_proxy_url = os.environ[v]
break
if not http_proxy_url is None:
host, port, _, _ = _parse_url(http_proxy_url)
return host, port
@@ -160,7 +180,7 @@ def _http_request(method, host, rel_uri, port=None, data=None, secure=False,
def http_request(method,
url, data, headers=None,
chk_proxy=False,
use_proxy=False,
max_retry=DEFAULT_RETRIES,
retry_codes=RETRY_CODES,
retry_delay=SHORT_DELAY_IN_SECONDS):
@@ -169,10 +189,13 @@ def http_request(method,
host, port, secure, rel_uri = _parse_url(url)
# Check proxy
# Use the HTTP(S) proxy
proxy_host, proxy_port = (None, None)
if chk_proxy:
proxy_host, proxy_port = _get_http_proxy()
if use_proxy:
proxy_host, proxy_port = _get_http_proxy(secure=secure)
if proxy_host or proxy_port:
logger.verbose("HTTP proxy: [{0}:{1}]", proxy_host, proxy_port)
# If httplib module is not built with ssl support,
# fallback to HTTP if allowed
@@ -187,8 +210,11 @@ def http_request(method,
# If httplib module doesn't support HTTPS tunnelling,
# fallback to HTTP if allowed
if secure and proxy_host is not None and proxy_port is not None \
and not hasattr(httpclient.HTTPSConnection, "set_tunnel"):
if secure and \
proxy_host is not None and \
proxy_port is not None \
and not hasattr(httpclient.HTTPSConnection, "set_tunnel"):
if not conf.get_allow_http():
raise HttpError("HTTPS tunnelling is unavailable and required")
@@ -197,9 +223,6 @@ def http_request(method,
logger.warn("Python does not support HTTPS tunnelling")
SECURE_WARNING_EMITTED = True
if proxy_host or proxy_port:
logger.verbose("HTTP proxy: [{0}:{1}]", proxy_host, proxy_port)
msg = ''
attempt = 0
delay = retry_delay
@@ -258,61 +281,61 @@ def http_request(method,
raise HttpError(msg)
def http_get(url, headers=None, chk_proxy=False,
def http_get(url, headers=None, use_proxy=False,
max_retry=DEFAULT_RETRIES,
retry_codes=RETRY_CODES,
retry_delay=SHORT_DELAY_IN_SECONDS):
return http_request("GET",
url, None, headers=headers,
chk_proxy=chk_proxy,
use_proxy=use_proxy,
max_retry=max_retry,
retry_codes=retry_codes,
retry_delay=retry_delay)
def http_head(url, headers=None, chk_proxy=False,
def http_head(url, headers=None, use_proxy=False,
max_retry=DEFAULT_RETRIES,
retry_codes=RETRY_CODES,
retry_delay=SHORT_DELAY_IN_SECONDS):
return http_request("HEAD",
url, None, headers=headers,
chk_proxy=chk_proxy,
use_proxy=use_proxy,
max_retry=max_retry,
retry_codes=retry_codes,
retry_delay=retry_delay)
def http_post(url, data, headers=None, chk_proxy=False,
def http_post(url, data, headers=None, use_proxy=False,
max_retry=DEFAULT_RETRIES,
retry_codes=RETRY_CODES,
retry_delay=SHORT_DELAY_IN_SECONDS):
return http_request("POST",
url, data, headers=headers,
chk_proxy=chk_proxy,
use_proxy=use_proxy,
max_retry=max_retry,
retry_codes=retry_codes,
retry_delay=retry_delay)
def http_put(url, data, headers=None, chk_proxy=False,
def http_put(url, data, headers=None, use_proxy=False,
max_retry=DEFAULT_RETRIES,
retry_codes=RETRY_CODES,
retry_delay=SHORT_DELAY_IN_SECONDS):
return http_request("PUT",
url, data, headers=headers,
chk_proxy=chk_proxy,
use_proxy=use_proxy,
max_retry=max_retry,
retry_codes=retry_codes,
retry_delay=retry_delay)
def http_delete(url, headers=None, chk_proxy=False,
def http_delete(url, headers=None, use_proxy=False,
max_retry=DEFAULT_RETRIES,
retry_codes=RETRY_CODES,
retry_delay=SHORT_DELAY_IN_SECONDS):
return http_request("DELETE",
url, None, headers=headers,
chk_proxy=chk_proxy,
use_proxy=use_proxy,
max_retry=max_retry,
retry_codes=retry_codes,
retry_delay=retry_delay)
+11
View File
@@ -19,6 +19,7 @@
import base64
import crypt
import random
import re
import string
import struct
import sys
@@ -322,6 +323,16 @@ def safe_shlex_split(s):
return shlex.split(s.encode('utf-8'))
return shlex.split(s)
def swap_hexstring(s, width=2):
r = len(s) % width
if r != 0:
s = ('0' * (width - (len(s) % width))) + s
return ''.join(reversed(
re.findall(
r'[a-f0-9]{{{0}}}'.format(width),
s,
re.IGNORECASE)))
def parse_json(json_str):
"""
+3 -3
View File
@@ -810,7 +810,7 @@ class GuestAgent(object):
uri, headers = self.host.get_artifact_request(uri.uri, self.host.manifest_uri)
try:
if self._fetch(uri, headers=headers, chk_proxy=False):
if self._fetch(uri, headers=headers, use_proxy=False):
if not HostPluginProtocol.is_default_channel():
logger.verbose("Setting host plugin as default channel")
HostPluginProtocol.set_default_channel(True)
@@ -839,10 +839,10 @@ class GuestAgent(object):
return
def _fetch(self, uri, headers=None, chk_proxy=True):
def _fetch(self, uri, headers=None, use_proxy=True):
package = None
try:
resp = restutil.http_get(uri, chk_proxy=chk_proxy, headers=headers)
resp = restutil.http_get(uri, use_proxy=use_proxy, headers=headers)
if restutil.request_succeeded(resp):
package = resp.read()
fileutil.write_file(self.get_agent_pkg_path(),
+1 -1
View File
@@ -170,7 +170,7 @@ class ProvisionHandler(object):
return False
s = fileutil.read_file(self.provisioned_file_path()).strip()
if s != self.osutil.get_instance_id():
if not self.osutil.is_current_instance_id(s):
if len(s) > 0:
logger.warn("VM is provisioned, "
"but the VM unique identifier has changed -- "
+58 -5
View File
@@ -377,23 +377,50 @@ Match host 192.168.1.2\n\
conf.get_sshd_conf_file_path(),
expected_output)
def test_correct_instance_id(self):
util = osutil.DefaultOSUtil()
self.assertEqual(
"12345678-1234-1234-1234-123456789012",
util._correct_instance_id("78563412-3412-3412-1234-123456789012"))
self.assertEqual(
"D0DF4C54-4ECB-4A4B-9954-5BDF3ED5C3B8",
util._correct_instance_id("544CDFD0-CB4E-4B4A-9954-5BDF3ED5C3B8"))
@patch('os.path.isfile', return_value=True)
@patch('azurelinuxagent.common.utils.fileutil.read_file',
return_value="B9F3C233-9913-9F42-8EB3-BA656DF32502")
return_value="33C2F3B9-1399-429F-8EB3-BA656DF32502")
def test_get_instance_id_from_file(self, mock_read, mock_isfile):
util = osutil.DefaultOSUtil()
self.assertEqual(
"B9F3C233-9913-9F42-8EB3-BA656DF32502",
util.get_instance_id(),
"B9F3C233-9913-9F42-8EB3-BA656DF32502")
@patch('os.path.isfile', return_value=True)
@patch('azurelinuxagent.common.utils.fileutil.read_file',
return_value="")
def test_get_instance_id_empty_from_file(self, mock_read, mock_isfile):
util = osutil.DefaultOSUtil()
self.assertEqual(
"",
util.get_instance_id())
@patch('os.path.isfile', return_value=True)
@patch('azurelinuxagent.common.utils.fileutil.read_file',
return_value="Value")
def test_get_instance_id_malformed_from_file(self, mock_read, mock_isfile):
util = osutil.DefaultOSUtil()
self.assertEqual(
"Value",
util.get_instance_id())
@patch('os.path.isfile', return_value=False)
@patch('azurelinuxagent.common.utils.shellutil.run_get_output',
return_value=[0, 'B9F3C233-9913-9F42-8EB3-BA656DF32502'])
return_value=[0, '33C2F3B9-1399-429F-8EB3-BA656DF32502'])
def test_get_instance_id_from_dmidecode(self, mock_shell, mock_isfile):
util = osutil.DefaultOSUtil()
self.assertEqual(
"B9F3C233-9913-9F42-8EB3-BA656DF32502",
util.get_instance_id())
util.get_instance_id(),
"B9F3C233-9913-9F42-8EB3-BA656DF32502")
@patch('os.path.isfile', return_value=False)
@patch('azurelinuxagent.common.utils.shellutil.run_get_output',
@@ -409,6 +436,32 @@ Match host 192.168.1.2\n\
util = osutil.DefaultOSUtil()
self.assertEqual("", util.get_instance_id())
@patch('os.path.isfile', return_value=True)
@patch('azurelinuxagent.common.utils.fileutil.read_file')
def test_is_current_instance_id_from_file(self, mock_read, mock_isfile):
util = osutil.DefaultOSUtil()
mock_read.return_value = "B9F3C233-9913-9F42-8EB3-BA656DF32502"
self.assertTrue(util.is_current_instance_id(
"B9F3C233-9913-9F42-8EB3-BA656DF32502"))
mock_read.return_value = "33C2F3B9-1399-429F-8EB3-BA656DF32502"
self.assertTrue(util.is_current_instance_id(
"B9F3C233-9913-9F42-8EB3-BA656DF32502"))
@patch('os.path.isfile', return_value=False)
@patch('azurelinuxagent.common.utils.shellutil.run_get_output')
def test_is_current_instance_id_from_dmidecode(self, mock_shell, mock_isfile):
util = osutil.DefaultOSUtil()
mock_shell.return_value = [0, 'B9F3C233-9913-9F42-8EB3-BA656DF32502']
self.assertTrue(util.is_current_instance_id(
"B9F3C233-9913-9F42-8EB3-BA656DF32502"))
mock_shell.return_value = [0, '33C2F3B9-1399-429F-8EB3-BA656DF32502']
self.assertTrue(util.is_current_instance_id(
"B9F3C233-9913-9F42-8EB3-BA656DF32502"))
@patch('azurelinuxagent.common.conf.get_sudoers_dir')
def test_conf_sudoer(self, mock_dir):
tmp_dir = tempfile.mkdtemp()
+3 -3
View File
@@ -688,7 +688,7 @@ class TestGuestAgent(UpdateTestCase):
self.assertEqual(mock_http_get.call_args_list[3][0][0], art_uri)
a, k = mock_http_get.call_args_list[3]
self.assertEqual(False, k['chk_proxy'])
self.assertEqual(False, k['use_proxy'])
# ensure fallback works as expected
with patch.object(HostPluginProtocol,
@@ -698,14 +698,14 @@ class TestGuestAgent(UpdateTestCase):
self.assertEqual(mock_http_get.call_count, 6)
a, k = mock_http_get.call_args_list[3]
self.assertEqual(False, k['chk_proxy'])
self.assertEqual(False, k['use_proxy'])
self.assertEqual(mock_http_get.call_args_list[4][0][0], ext_uri)
a, k = mock_http_get.call_args_list[4]
self.assertEqual(mock_http_get.call_args_list[5][0][0], art_uri)
a, k = mock_http_get.call_args_list[5]
self.assertEqual(False, k['chk_proxy'])
self.assertEqual(False, k['use_proxy'])
@patch("azurelinuxagent.ga.update.restutil.http_get")
def test_ensure_downloaded(self, mock_http_get):
+6 -3
View File
@@ -64,27 +64,29 @@ class TestProvision(AgentTestCase):
@patch('azurelinuxagent.pa.deprovision.get_deprovision_handler')
def test_is_provisioned_is_provisioned(self,
mock_deprovision, mock_read, mock_isfile):
ph = ProvisionHandler()
ph.osutil = Mock()
ph.osutil.get_instance_id = \
Mock(return_value="B9F3C233-9913-9F42-8EB3-BA656DF32502")
ph.osutil.is_current_instance_id = Mock(return_value=True)
ph.write_provisioned = Mock()
deprovision_handler = Mock()
mock_deprovision.return_value = deprovision_handler
self.assertTrue(ph.is_provisioned())
ph.osutil.is_current_instance_id.assert_called_once()
deprovision_handler.run_changed_unique_id.assert_not_called()
@patch('os.path.isfile', return_value=True)
@patch('azurelinuxagent.common.utils.fileutil.read_file',
side_effect=["Value"])
return_value="B9F3C233-9913-9F42-8EB3-BA656DF32502")
@patch('azurelinuxagent.pa.deprovision.get_deprovision_handler')
def test_is_provisioned_not_deprovisioned(self,
mock_deprovision, mock_read, mock_isfile):
ph = ProvisionHandler()
ph.osutil = Mock()
ph.osutil.is_current_instance_id = Mock(return_value=False)
ph.report_ready = Mock()
ph.write_provisioned = Mock()
@@ -92,6 +94,7 @@ class TestProvision(AgentTestCase):
mock_deprovision.return_value = deprovision_handler
self.assertTrue(ph.is_provisioned())
ph.osutil.is_current_instance_id.assert_called_once()
deprovision_handler.run_changed_unique_id.assert_called_once()
if __name__ == '__main__':
+8 -8
View File
@@ -100,32 +100,32 @@ class TestWireProtocolGetters(AgentTestCase):
# no kwargs -- Default to True
WireClient.call_storage_service(http_req)
# kwargs, no chk_proxy -- Default to True
# kwargs, no use_proxy -- Default to True
WireClient.call_storage_service(http_req,
url,
headers)
# kwargs, chk_proxy None -- Default to True
# kwargs, use_proxy None -- Default to True
WireClient.call_storage_service(http_req,
url,
headers,
chk_proxy=None)
use_proxy=None)
# kwargs, chk_proxy False -- Keep False
# kwargs, use_proxy False -- Keep False
WireClient.call_storage_service(http_req,
url,
headers,
chk_proxy=False)
use_proxy=False)
# kwargs, chk_proxy True -- Keep True
# kwargs, use_proxy True -- Keep True
WireClient.call_storage_service(http_req,
url,
headers,
chk_proxy=True)
use_proxy=True)
# assert
self.assertTrue(http_patch.call_count == 5)
for i in range(0,5):
c = http_patch.call_args_list[i][-1]['chk_proxy']
c = http_patch.call_args_list[i][-1]['use_proxy']
self.assertTrue(c == (True if i != 3 else False))
def test_status_blob_parsing(self, *args):
+65
View File
@@ -15,6 +15,7 @@
# Requires Python 2.4+ and Openssl 1.0+
#
import os
import unittest
from azurelinuxagent.common.exception import BadRequestError, \
@@ -54,6 +55,70 @@ class TestHttpOperations(AgentTestCase):
self.assertEquals(None, host)
self.assertEquals(rel_uri, "None")
@patch('azurelinuxagent.common.conf.get_httpproxy_port')
@patch('azurelinuxagent.common.conf.get_httpproxy_host')
def test_get_http_proxy_none_is_default(self, mock_host, mock_port):
mock_host.return_value = None
mock_port.return_value = None
h, p = restutil._get_http_proxy()
self.assertEqual(None, h)
self.assertEqual(None, p)
@patch('azurelinuxagent.common.conf.get_httpproxy_port')
@patch('azurelinuxagent.common.conf.get_httpproxy_host')
def test_get_http_proxy_configuration_overrides_env(self, mock_host, mock_port):
mock_host.return_value = "host"
mock_port.return_value = None
h, p = restutil._get_http_proxy()
self.assertEqual("host", h)
self.assertEqual(None, p)
mock_host.assert_called_once()
mock_port.assert_called_once()
@patch('azurelinuxagent.common.conf.get_httpproxy_port')
@patch('azurelinuxagent.common.conf.get_httpproxy_host')
def test_get_http_proxy_configuration_requires_host(self, mock_host, mock_port):
mock_host.return_value = None
mock_port.return_value = None
h, p = restutil._get_http_proxy()
self.assertEqual(None, h)
self.assertEqual(None, p)
mock_host.assert_called_once()
mock_port.assert_not_called()
@patch('azurelinuxagent.common.conf.get_httpproxy_host')
def test_get_http_proxy_http_uses_httpproxy(self, mock_host):
mock_host.return_value = None
with patch.dict(os.environ, {
'http_proxy' : 'http://foo.com:80',
'https_proxy' : 'https://bar.com:443'
}):
h, p = restutil._get_http_proxy()
self.assertEqual("foo.com", h)
self.assertEqual(80, p)
@patch('azurelinuxagent.common.conf.get_httpproxy_host')
def test_get_http_proxy_https_uses_httpsproxy(self, mock_host):
mock_host.return_value = None
with patch.dict(os.environ, {
'http_proxy' : 'http://foo.com:80',
'https_proxy' : 'https://bar.com:443'
}):
h, p = restutil._get_http_proxy(secure=True)
self.assertEqual("bar.com", h)
self.assertEqual(443, p)
@patch('azurelinuxagent.common.conf.get_httpproxy_host')
def test_get_http_proxy_ignores_user_in_httpproxy(self, mock_host):
mock_host.return_value = None
with patch.dict(os.environ, {
'http_proxy' : 'http://user:pw@foo.com:80'
}):
h, p = restutil._get_http_proxy()
self.assertEqual("foo.com", h)
self.assertEqual(80, p)
@patch("azurelinuxagent.common.future.httpclient.HTTPSConnection")
@patch("azurelinuxagent.common.future.httpclient.HTTPConnection")
def test_http_request(self, HTTPConnection, HTTPSConnection):
+31
View File
@@ -107,6 +107,37 @@ class TestTextUtil(AgentTestCase):
"-----END PRIVATE Key-----\n")
base64_bytes = textutil.get_bytes_from_pem(content)
self.assertEquals("private key", base64_bytes)
def test_swap_hexstring(self):
data = [
['12', 1, '21'],
['12', 2, '12'],
['12', 3, '012'],
['12', 4, '0012'],
['123', 1, '321'],
['123', 2, '2301'],
['123', 3, '123'],
['123', 4, '0123'],
['1234', 1, '4321'],
['1234', 2, '3412'],
['1234', 3, '234001'],
['1234', 4, '1234'],
['abcdef12', 1, '21fedcba'],
['abcdef12', 2, '12efcdab'],
['abcdef12', 3, 'f12cde0ab'],
['abcdef12', 4, 'ef12abcd'],
['aBcdEf12', 1, '21fEdcBa'],
['aBcdEf12', 2, '12EfcdaB'],
['aBcdEf12', 3, 'f12cdE0aB'],
['aBcdEf12', 4, 'Ef12aBcd']
]
for t in data:
self.assertEqual(t[2], textutil.swap_hexstring(t[0], width=t[1]))
if __name__ == '__main__':
unittest.main()