mirror of
https://github.com/clearlinux/WALinuxAgent.git
synced 2026-08-27 02:46:42 +00:00
[#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:
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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 -- "
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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__':
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user