Repository: Azure/WALinuxAgent
Pull request #1706 (2019-11-08 16:13:57)

Fix issue with GPT disk mounting with guessing filesystem type
<!-- DO NOT DELETE THIS TEMPLATE -->

## Description

When we activate the resource disk, if the resource disk is a GPT disk with a single partition then we will try to mount the disk without formatting it. Because the resource disks are originally ntfs filesystem, if the machine has the ntfs driver then it will mount with that filesystem, completely disregarding the configuration `ResourceDisk.Filesystem`.

The fix is to explicitly specify the filesystem type with `-t` and passing in the configuration value so that we ensure that the user gets the resource disk in the desired filesystem. This should not be an ntfs-first approach.

// @anhvoms 

---

### PR information
- [x] The title of the PR is clear and informative.
- [x] There are a small number of commits, each of which has an informative message. This means that previously merged commits do not appear in the history of the PR. For information on cleaning up the commits in your pull request, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md).
- [x] Except for special cases involving multiple contributors, the PR is started from a fork of the main repository, not a branch.
- [ ] If applicable, the PR references the bug/issue that it fixes in the description.
- [ ] New Unit tests were added for the changes made and Travis.CI is passing.

### Quality of Code and Contribution Guidelines
- [x] I have read the [contribution guidelines](https://github.com/Azure/WALinuxAgent/blob/master/.github/CONTRIBUTING.md).

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/azure/walinuxagent/1706)
<!-- Reviewable:end -->


codecov[bot]: # [Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1706?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`develop@7d1920d`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/Azure/WALinuxAgent/pull/1706/graphs/tree.svg?width=650&token=ae90E2KYCw&height=150&src=pr)](https://codecov.io/gh/Azure/WALinuxAgent/pull/1706?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##             develop    #1706   +/-   ##
==========================================
  Coverage           ?   67.67%           
==========================================
  Files              ?       80           
  Lines              ?    11512           
  Branches           ?     1616           
==========================================
  Hits               ?     7791           
  Misses             ?     3379           
  Partials           ?      342
```


| [Impacted Files](https://codecov.io/gh/Azure/WALinuxAgent/pull/1706?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [azurelinuxagent/daemon/resourcedisk/default.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/1706/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2RhZW1vbi9yZXNvdXJjZWRpc2svZGVmYXVsdC5weQ==) | `34.13% <100%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1706?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1706?src=pr&el=footer). Last update [7d1920d...7cf2b89](https://codecov.io/gh/Azure/WALinuxAgent/pull/1706?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index d655a537..f9493b3f 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,14 +1,12 @@
 ---
 name: Bug report
 about: Create a report to help us improve
-title: "[BUG]"
-labels: triage
+title: "[BUG] Bug Title"
 assignees: narrieta, pgombar, vrdmr, larohra
 
 ---
 
-**Describe the bug**
-A clear and concise description of what the bug is.
+**Describe the bug: A clear and concise description of what the bug is.**
 
 Note: Please add some context which would help us understand the problem better
 1. Section of the log where the error occurs.
@@ -17,7 +15,10 @@ Note: Please add some context which would help us understand the problem better
 
 **Distro and WALinuxAgent details (please complete the following information):**
  - Distro and Version: [e.g. Ubuntu 16.04]
- - WALinuxAgent version [e.g. 2.2.34, you can copy the output of `waagent --version`, more info [here](https://github.com/Azure/WALinuxAgent/wiki/FAQ#what-does-goal-state-agent-mean-in-waagent---version-output) ]
+ - WALinuxAgent version [e.g. 2.2.40, you can copy the output of `waagent --version`, more info [here](https://github.com/Azure/WALinuxAgent/wiki/FAQ#what-does-goal-state-agent-mean-in-waagent---version-output) ]
 
 **Additional context**
 Add any other context about the problem here.
+
+**Log file attached**
+If possible, please provide the full /var/log/waagent.log file to help us understand the problem better and get the context of the issue.
diff --git a/.gitignore b/.gitignore
index 563e6e15..0a31340c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 # Byte-compiled / optimized / DLL files
 __pycache__/
 *.py[cod]
+*$py.class
 
 # Virtualenv
 py3env/
@@ -27,6 +28,7 @@ var/
 
 # PyCharm
 .idea/
+.idea_modules/
 
 # PyInstaller
 #  Usually these files are written by a python script from a template
@@ -72,3 +74,21 @@ bin/waagent2.0c
 
 # mac osx specific files
 .DS_Store
+
+### VirtualEnv template
+# Virtualenv
+# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
+.Python
+pyvenv.cfg
+.venv
+pip-selfcheck.json
+
+# virtualenv
+venv/
+ENV/
+
+# dotenv
+.env
+
+# pyenv
+.python-version
diff --git a/CODEOWNERS b/CODEOWNERS
index 477d874a..a8f2d5de 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -10,5 +10,13 @@
 # questions, please feel free to reach out to thstring@microsoft.com.
 /azurelinuxagent/pa/ @trstringer @anhvoms
 
-# Guest Agent team
+#
+# RDMA
+#
+/azurelinuxagent/common/rdma.py @longlimsft
+/azurelinuxagent/pa/rdma/ @longlimsft
+
+#
+# Linux Agent team
+#
 * @narrieta @vrdmr @pgombar @larohra
diff --git a/azurelinuxagent/agent.py b/azurelinuxagent/agent.py
index 2e3b26c4..c163c753 100644
--- a/azurelinuxagent/agent.py
+++ b/azurelinuxagent/agent.py
@@ -67,10 +67,11 @@ class Agent(object):
         if conf.get_logs_console():
             logger.add_logger_appender(logger.AppenderType.CONSOLE, level,
                     path="/dev/console")
-        # See issue #1035
-        # logger.add_logger_appender(logger.AppenderType.TELEMETRY,
-        #                            logger.LogLevel.WARNING,
-        #                            path=event.add_log_event)
+
+        if not event.send_logs_to_telemetry():
+            logger.add_logger_appender(logger.AppenderType.TELEMETRY,
+                                       logger.LogLevel.WARNING,
+                                       path=event.add_log_event)
 
         ext_log_dir = conf.get_ext_log_dir()
         try:
diff --git a/azurelinuxagent/common/cgroupstelemetry.py b/azurelinuxagent/common/cgroupstelemetry.py
index 168b4d5d..dcc586a3 100644
--- a/azurelinuxagent/common/cgroupstelemetry.py
+++ b/azurelinuxagent/common/cgroupstelemetry.py
@@ -15,11 +15,15 @@
 # Requires Python 2.6+ and Openssl 1.0+
 import errno
 import threading
+from collections import namedtuple
 from datetime import datetime as dt
 
 from azurelinuxagent.common import logger
-from azurelinuxagent.common.future import ustr
 from azurelinuxagent.common.exception import CGroupsException
+from azurelinuxagent.common.future import ustr
+
+
+MetricValue = namedtuple('Metric', ['category', 'counter', 'instance', 'value'])
 
 
 class CGroupsTelemetry(object):
@@ -93,6 +97,16 @@ class CGroupsTelemetry(object):
 
     @staticmethod
     def report_all_tracked():
+        """
+        The report_all_tracked's purpose is to collect the data from the tracked cgroups and process the metric into a
+        data structure by _process_cgroup_metric. The perf metric is added into the data structure and returned to the
+        caller.
+
+        The report_all_tracked would be removed soon - in favor of sending report_metric directly, when polling the data
+        from tracked groups.
+
+        :return collected_metrics: dictionary of cgroups metrics.
+        """
         collected_metrics = {}
 
         for name, cgroup_metrics in CGroupsTelemetry._cgroup_metrics.items():
@@ -112,18 +126,43 @@ class CGroupsTelemetry(object):
 
     @staticmethod
     def poll_all_tracked():
+        metrics = []
+
         with CGroupsTelemetry._rlock:
             for cgroup in CGroupsTelemetry._tracked[:]:
-
+                # noinspection PyBroadException
                 if cgroup.name not in CGroupsTelemetry._cgroup_metrics:
                     CGroupsTelemetry._cgroup_metrics[cgroup.name] = CgroupMetrics()
-
-                CGroupsTelemetry._cgroup_metrics[cgroup.name].collect_data(cgroup)
-
+                try:
+                    if cgroup.controller == "cpu":
+                        current_cpu_usage = cgroup.get_cpu_usage()
+                        CGroupsTelemetry._cgroup_metrics[cgroup.name].add_cpu_usage(current_cpu_usage)
+                        metrics.append(MetricValue("Process", "% Processor Time", cgroup.name, current_cpu_usage))
+                    elif cgroup.controller == "memory":
+                        current_memory_usage = cgroup.get_memory_usage()
+                        CGroupsTelemetry._cgroup_metrics[cgroup.name].add_memory_usage(current_memory_usage)
+                        metrics.append(MetricValue("Memory", "Total Memory Usage", cgroup.name, current_memory_usage))
+
+                        max_memory_usage = cgroup.get_max_memory_usage()
+                        CGroupsTelemetry._cgroup_metrics[cgroup.name].add_max_memory_usage(max_memory_usage)
+                        metrics.append(MetricValue("Memory", "Max Memory Usage", cgroup.name, max_memory_usage))
+                    else:
+                        raise CGroupsException('CGroup controller {0} is not supported for cgroup {1}'.format(
+                                               cgroup.controller, cgroup.name))
+                except Exception as e:
+                    # There can be scenarios when the CGroup has been deleted by the time we are fetching the values
+                    # from it. This would raise IOError with file entry not found (ERRNO: 2). We do not want to log
+                    # every occurrences of such case as it would be very verbose. We do want to log all the other
+                    # exceptions which could occur, which is why we do a periodic log for all the other errors.
+                    if not isinstance(e, (IOError, OSError)) or e.errno != errno.ENOENT:
+                        logger.periodic_warn(logger.EVERY_HOUR, '[PERIODIC] Could not collect metrics for cgroup '
+                                                                '{0}. Error : {1}'.format(cgroup.name, ustr(e)))
                 if not cgroup.is_active():
                     CGroupsTelemetry.stop_tracking(cgroup)
                     CGroupsTelemetry._cgroup_metrics[cgroup.name].marked_for_delete = True
 
+        return metrics
+
     @staticmethod
     def prune_all_tracked():
         with CGroupsTelemetry._rlock:
@@ -145,19 +184,14 @@ class CgroupMetrics(object):
         self._cpu_usage = Metric()
         self.marked_for_delete = False
 
-    def collect_data(self, cgroup):
-        # noinspection PyBroadException
-        try:
-            if cgroup.controller == "cpu":
-                self._cpu_usage.append(cgroup.get_cpu_usage())
-            elif cgroup.controller == "memory":
-                self._memory_usage.append(cgroup.get_memory_usage())
-                self._max_memory_usage.append(cgroup.get_max_memory_usage())
-            else:
-                raise CGroupsException('CGroup controller {0} is not supported'.format(controller))
-        except Exception as e:
-            if not isinstance(e, (IOError, OSError)) or e.errno != errno.ENOENT:
-                logger.periodic_warn(logger.EVERY_HALF_HOUR, 'Could not collect metrics for cgroup {0}. Error : {1}'.format(cgroup.path, ustr(e)))
+    def add_memory_usage(self, usage):
+        self._memory_usage.append(usage)
+
+    def add_max_memory_usage(self, usage):
+        self._max_memory_usage.append(usage)
+
+    def add_cpu_usage(self, usage):
+        self._cpu_usage.append(usage)
 
     def get_memory_usage(self):
         return self._memory_usage
diff --git a/azurelinuxagent/common/conf.py b/azurelinuxagent/common/conf.py
index fb26468e..bfc61f02 100644
--- a/azurelinuxagent/common/conf.py
+++ b/azurelinuxagent/common/conf.py
@@ -173,15 +173,19 @@ def enable_rdma(conf=__conf__):
 def enable_rdma_update(conf=__conf__):
     return conf.get_switch("OS.UpdateRdmaDriver", False)
 
+
 def enable_check_rdma_driver(conf=__conf__):
     return conf.get_switch("OS.CheckRdmaDriver", True)
 
+
 def get_logs_verbose(conf=__conf__):
     return conf.get_switch("Logs.Verbose", False)
 
+
 def get_logs_console(conf=__conf__):
     return conf.get_switch("Logs.Console", True)
 
+
 def get_lib_dir(conf=__conf__):
     return conf.get("Lib.Dir", "/var/lib/waagent")
 
diff --git a/azurelinuxagent/common/dhcp.py b/azurelinuxagent/common/dhcp.py
index fc2cb649..59749656 100644
--- a/azurelinuxagent/common/dhcp.py
+++ b/azurelinuxagent/common/dhcp.py
@@ -19,8 +19,6 @@ import socket
 import array
 import time
 import azurelinuxagent.common.logger as logger
-import azurelinuxagent.common.utils.shellutil as shellutil
-from azurelinuxagent.common.utils import fileutil
 from azurelinuxagent.common.utils.textutil import hex_dump, hex_dump2, \
     hex_dump3, \
     compare_bytes, str_to_ord, \
@@ -29,9 +27,10 @@ from azurelinuxagent.common.utils.textutil import hex_dump, hex_dump2, \
 from azurelinuxagent.common.exception import DhcpError
 from azurelinuxagent.common.osutil import get_osutil
 
+
 # the kernel routing table representation of 168.63.129.16
 KNOWN_WIRESERVER_IP_ENTRY = '10813FA8'
-KNOWN_WIRESERVER_IP = '168.63.129.16'
+from azurelinuxagent.common.utils.restutil import KNOWN_WIRESERVER_IP
 
 
 def get_dhcp_handler():
@@ -152,10 +151,10 @@ class DhcpHandler(object):
         """
         Check if DHCP is available
         """
-        (dhcp_available, endpoint) =  self.osutil.is_dhcp_available()
+        dhcp_available =  self.osutil.is_dhcp_available()
         if not dhcp_available:
             logger.info("send_dhcp_req: DHCP not available")
-            self.endpoint = endpoint
+            self.endpoint = KNOWN_WIRESERVER_IP
             return
 
         """
diff --git a/azurelinuxagent/common/event.py b/azurelinuxagent/common/event.py
index 306faa44..99ea3bd9 100644
--- a/azurelinuxagent/common/event.py
+++ b/azurelinuxagent/common/event.py
@@ -18,27 +18,40 @@
 import atexit
 import json
 import os
+import re
 import sys
 import threading
 import time
 import traceback
+from collections import namedtuple
 from datetime import datetime
 
 import azurelinuxagent.common.conf as conf
 import azurelinuxagent.common.logger as logger
 from azurelinuxagent.common.exception import EventError
-from azurelinuxagent.common.future import ustr
-from azurelinuxagent.common.datacontract import get_properties
+from azurelinuxagent.common.future import ustr, OrderedDict
+from azurelinuxagent.common.datacontract import get_properties, DataContractList
 from azurelinuxagent.common.telemetryevent import TelemetryEventParam, TelemetryEvent
 from azurelinuxagent.common.utils import fileutil, textutil
 from azurelinuxagent.common.version import CURRENT_VERSION, CURRENT_AGENT
 
 _EVENT_MSG = "Event: name={0}, op={1}, message={2}, duration={3}"
 TELEMETRY_EVENT_PROVIDER_ID = "69B669B9-4AF8-4C50-BDC4-6006FA76E975"
+TELEMETRY_METRICS_EVENT_ID = 4
 
 # Store the last retrieved container id as an environment variable to be shared between threads for telemetry purposes
 CONTAINER_ID_ENV_VARIABLE = "AZURE_GUEST_AGENT_CONTAINER_ID"
 
+TELEMETRY_LOG_PROVIDER_ID = "FFF0196F-EE4C-4EAF-9AA5-776F622DEB4F"
+TELEMETRY_LOG_EVENT_ID = 7
+SEND_LOGS_TO_TELEMETRY = False
+
+MAX_NUMBER_OF_EVENTS = 1000
+
+
+def send_logs_to_telemetry():
+    return SEND_LOGS_TO_TELEMETRY
+
 
 def get_container_id_from_env():
     return os.environ.get(CONTAINER_ID_ENV_VARIABLE, "UNINITIALIZED")
@@ -221,16 +234,19 @@ class EventLogger(object):
             msg = "Failed to create events folder {0}. Error: {1}".format(self.event_dir, ustr(e))
             raise EventError(msg)
 
-        existing_events = os.listdir(self.event_dir)
-        if len(existing_events) >= 1000:
-            existing_events.sort()
-            oldest_files = existing_events[:-999]
-            logger.warn("Too many files under: {0}, removing oldest".format(self.event_dir))
-            try:
-                for f in oldest_files:
-                    os.remove(os.path.join(self.event_dir, f))
-            except IOError as e:
-                raise EventError(e)
+        try:
+            existing_events = os.listdir(self.event_dir)
+            if len(existing_events) >= MAX_NUMBER_OF_EVENTS:
+                logger.periodic_warn(logger.EVERY_MINUTE, "[PERIODIC] Too many files under: {0}, current count:  {1}, "
+                                                          "removing oldest event files".format(self.event_dir,
+                                                                                               len(existing_events)))
+                existing_events.sort()
+                oldest_files = existing_events[:-999]
+                for event_file in oldest_files:
+                    os.remove(os.path.join(self.event_dir, event_file))
+        except (IOError, OSError) as e:
+            msg = "Failed to remove old events from events folder {0}. Error: {1}".format(self.event_dir, ustr(e))
+            raise EventError(msg)
 
         filename = os.path.join(self.event_dir,
                                 ustr(int(time.time() * 1000000)))
@@ -238,7 +254,7 @@ class EventLogger(object):
             with open(filename + ".tmp", 'wb+') as hfile:
                 hfile.write(data.encode("utf-8"))
             os.rename(filename + ".tmp", filename + ".tld")
-        except IOError as e:
+        except (IOError, OSError) as e:
             msg = "Failed to write events to file: {0}".format(e)
             raise EventError(msg)
 
@@ -270,16 +286,17 @@ class EventLogger(object):
 
     def _add_event(self, duration, evt_type, is_internal, is_success, message, name, op, version, event_id):
         event = TelemetryEvent(event_id, TELEMETRY_EVENT_PROVIDER_ID)
-        event.parameters.append(TelemetryEventParam('Name', name))
+
+        event.parameters.append(TelemetryEventParam('Name', str(name)))
         event.parameters.append(TelemetryEventParam('Version', str(version)))
-        event.parameters.append(TelemetryEventParam('IsInternal', is_internal))
-        event.parameters.append(TelemetryEventParam('Operation', op))
-        event.parameters.append(TelemetryEventParam('OperationSuccess', is_success))
-        event.parameters.append(TelemetryEventParam('Message', message))
-        event.parameters.append(TelemetryEventParam('Duration', duration))
-        event.parameters.append(TelemetryEventParam('ExtensionType', evt_type))
-
-        self.add_default_parameters_to_event(event)
+        event.parameters.append(TelemetryEventParam('IsInternal', bool(is_internal)))
+        event.parameters.append(TelemetryEventParam('Operation', str(op)))
+        event.parameters.append(TelemetryEventParam('OperationSuccess', bool(is_success)))
+        event.parameters.append(TelemetryEventParam('Message', str(message)))
+        event.parameters.append(TelemetryEventParam('Duration', int(duration)))
+        event.parameters.append(TelemetryEventParam('ExtensionType', str(evt_type)))
+
+        event.parameters = self.add_default_parameters_to_event(event.parameters)
         data = get_properties(event)
         try:
             self.save_event(json.dumps(data))
@@ -287,26 +304,14 @@ class EventLogger(object):
             logger.periodic_error(logger.EVERY_FIFTEEN_MINUTES, "[PERIODIC] {0}".format(ustr(e)))
 
     def add_log_event(self, level, message):
-        # By the time the message has gotten to this point it is formatted as
-        #
-        #   YYYY/MM/DD HH:mm:ss.fffffff LEVEL <text>.
-        #
-        # The timestamp and the level are redundant, and should be stripped.
-        # The logging library does not schematize this data, so I am forced
-        # to parse the message.  The format is regular, so the burden is low.
-
-        parts = message.split(' ', 3)
-        msg = parts[3] if len(parts) == 4 \
-            else message
-
-        event = TelemetryEvent(7, "FFF0196F-EE4C-4EAF-9AA5-776F622DEB4F")
+        event = TelemetryEvent(TELEMETRY_LOG_EVENT_ID, TELEMETRY_LOG_PROVIDER_ID)
         event.parameters.append(TelemetryEventParam('EventName', WALAEventOperation.Log))
         event.parameters.append(TelemetryEventParam('CapabilityUsed', logger.LogLevel.STRINGS[level]))
-        event.parameters.append(TelemetryEventParam('Context1', msg))
+        event.parameters.append(TelemetryEventParam('Context1', self._clean_up_message(message)))
         event.parameters.append(TelemetryEventParam('Context2', ''))
         event.parameters.append(TelemetryEventParam('Context3', ''))
 
-        self.add_default_parameters_to_event(event)
+        event.parameters = self.add_default_parameters_to_event(event.parameters)
         data = get_properties(event)
         try:
             self.save_event(json.dumps(data))
@@ -328,40 +333,106 @@ class EventLogger(object):
             message = "Metric {0}/{1} [{2}] = {3}".format(category, counter, instance, value)
             _log_event(AGENT_NAME, "METRIC", message, 0)
 
-        event = TelemetryEvent(4, "69B669B9-4AF8-4C50-BDC4-6006FA76E975")
-        event.parameters.append(TelemetryEventParam('Category', category))
-        event.parameters.append(TelemetryEventParam('Counter', counter))
-        event.parameters.append(TelemetryEventParam('Instance', instance))
-        event.parameters.append(TelemetryEventParam('Value', value))
+        event = TelemetryEvent(TELEMETRY_METRICS_EVENT_ID, TELEMETRY_EVENT_PROVIDER_ID)
+        event.parameters.append(TelemetryEventParam('Category', str(category)))
+        event.parameters.append(TelemetryEventParam('Counter', str(counter)))
+        event.parameters.append(TelemetryEventParam('Instance', str(instance)))
+        event.parameters.append(TelemetryEventParam('Value', float(value)))
 
-        self.add_default_parameters_to_event(event)
+        event.parameters = self.add_default_parameters_to_event(event.parameters)
         data = get_properties(event)
         try:
             self.save_event(json.dumps(data))
         except EventError as e:
-            logger.error("{0}", e)
+            logger.periodic_error(logger.EVERY_FIFTEEN_MINUTES, "[PERIODIC] {0}".format(ustr(e)))
 
     @staticmethod
-    def add_default_parameters_to_event(event, set_default_values=False):
-        # We write the GAVersion here rather than add it in azurelinuxagent.ga.monitor.MonitorHandler.add_sysinfo
-        # as there could be a possibility of events being sent with newer version of the agent, rather than the agent
-        # version generating the event.
-        # Old behavior example: V1 writes the event on the disk and finds an update immediately, and updates. Now the
-        # new monitor thread would pick up the events from the disk and send it with the CURRENT_AGENT, which would have
-        # newer version of the agent. This causes confusion.
+    def _clean_up_message(message):
+        # By the time the message has gotten to this point it is formatted as
         #
-        # ContainerId can change due to live migration and we want to preserve the container Id of the container writing
-        # the event, rather than sending the event.
-        # OpcodeName: This is used as the actual time of event generation.
+        #   Old Time format
+        #   YYYY/MM/DD HH:mm:ss.fffffff LEVEL <text>.
+        #   YYYY/MM/DD HH:mm:ss.fffffff <text>.
+        #   YYYY/MM/DD HH:mm:ss LEVEL <text>.
+        #   YYYY/MM/DD HH:mm:ss <text>.
+        #
+        #   UTC ISO Time format added in #1716
+        #   YYYY-MM-DDTHH:mm:ss.fffffffZ LEVEL <text>.
+        #   YYYY-MM-DDTHH:mm:ss.fffffffZ <text>.
+        #   YYYY-MM-DDTHH:mm:ssZ LEVEL <text>.
+        #   YYYY-MM-DDTHH:mm:ssZ <text>.
+        #
+        # The timestamp and the level are redundant, and should be stripped. The logging library does not schematize
+        # this data, so I am forced to parse the message using a regex.  The format is regular, so the burden is low,
+        # and usability on the telemetry side is high.
+
+        if not message:
+            return message
+
+        # Adding two regexs to simplify the handling of logs and to keep it maintainable. Most of the logs would have
+        # level includent in the log itself, but if it doesn't have, the second regex is a catch all case and will work
+        # for all the cases.
+        log_level_format_parser = re.compile(r"^.*(INFO|WARNING|ERROR|VERBOSE)\s*(.*)$")
+        log_format_parser = re.compile(r"^[0-9:/\-TZ\s.]*\s(.*)$")
+
+        # Parsing the log messages containing levels in it
+        extract_level_message = log_level_format_parser.search(message)
+        if extract_level_message:
+            return extract_level_message.group(2)  # The message bit
+        else:
+            # Parsing the log messages without levels in it.
+            extract_message = log_format_parser.search(message)
+            if extract_message:
+                return extract_message.group(1)  # The message bit
+            else:
+                return message
 
-        default_parameters = [("GAVersion", CURRENT_AGENT), ('ContainerId', get_container_id_from_env()),
-                              ('OpcodeName', datetime.utcnow().__str__()),
-                              ('EventTid', threading.current_thread().ident),
-                              ('EventPid', os.getpid()), ("TaskName", threading.current_thread().getName()),
-                              ("KeywordName", '')]
+    @staticmethod
+    def add_default_parameters_to_event(event_parameters, set_values_for_agent=True):
+        """
+        Default fields are only populated by Agent and not the extension. Agent will fill up any event if they don't
+        have the default params. Example: GAVersion and ContainerId are populated for agent events on the fly,
+        but not for extension events. Add it if it's missing.
+
+        We write the GAVersion here rather than add it in azurelinuxagent.ga.monitor.MonitorHandler.add_sysinfo
+        as there could be a possibility of events being sent with newer version of the agent, rather than the agent
+        version generating the event.
+        # Old behavior example: V1 writes the event on the disk and finds an update immediately, and updates. Now the
+        new monitor thread would pick up the events from the disk and send it with the CURRENT_AGENT, which would have
+        newer version of the agent. This causes confusion.
+
+        ContainerId can change due to live migration and we want to preserve the container Id of the container writing
+        the event, rather than sending the event.
+        OpcodeName - This is used as the actual time of event generation.
+
+        :param event_parameters: List of parameters of the event.
+        :param set_values_for_agent: Need default values populated or not. Extensions need only GAVersion and
+                                            ContainerId to be populated and others should be
+        :return: Event with default parameters populated (either values for agent or extension)
+        """
+        DefaultParameter = namedtuple('DefaultParameter', ['name', 'value'])
+        default_parameters = [DefaultParameter("GAVersion", CURRENT_AGENT),
+                              DefaultParameter('ContainerId', get_container_id_from_env()),
+                              DefaultParameter('OpcodeName', datetime.utcnow().__str__() if set_values_for_agent else ""),
+                              DefaultParameter('EventTid', threading.current_thread().ident if set_values_for_agent else 0),
+                              DefaultParameter('EventPid', os.getpid() if set_values_for_agent else 0),
+                              DefaultParameter("TaskName", threading.current_thread().getName() if set_values_for_agent else ""),
+                              DefaultParameter("KeywordName", '')]
+
+        # Converting the event_parameters into a dictionary as it helps to easily look up and get values
+        param_names = OrderedDict([(param.name, param.value) for param in event_parameters])
 
         for param in default_parameters:
-            event.parameters.append(TelemetryEventParam(param[0], param[1]))
+            if param.name not in param_names or set_values_for_agent:
+                # If set_values_for_agent, we disregard any values already set for an existing default property and
+                # replaces it with a latest entry.
+                param_names[param.name] = param.value
+
+        parameters = DataContractList(TelemetryEventParam)
+        for name, value in param_names.items():
+            parameters.append(TelemetryEventParam(name, value))
+
+        return parameters
 
 
 __event_logger__ = EventLogger()
@@ -412,7 +483,11 @@ def report_metric(category, counter, instance, value, log_event=False, reporter=
         message = "Metric {0}/{1} [{2}] = {3}".format(category, counter, instance, value)
         _log_event(AGENT_NAME, "METRIC", message, 0)
         return
-    reporter.add_metric(category, counter, instance, value, log_event)
+    try:
+        reporter.add_metric(category, counter, instance, float(value), log_event)
+    except ValueError:
+        logger.periodic_warn(logger.EVERY_HALF_HOUR, "[PERIODIC] Cannot cast the metric value. Details of the Metric - "
+                                                     "{0}/{1} [{2}] = {3}".format(category, counter, instance, value))
 
 
 def add_event(name, op=WALAEventOperation.Unknown, is_success=True, duration=0, version=str(CURRENT_VERSION), message="",
@@ -429,10 +504,20 @@ def add_event(name, op=WALAEventOperation.Unknown, is_success=True, duration=0,
 
 
 def add_log_event(level, message, reporter=__event_logger__):
+    """
+    :param level: LoggerLevel of the log event
+    :param message: Message
+    :param reporter:
+    :return:
+    """
     if reporter.event_dir is None:
         return
 
-    reporter.add_log_event(level, message)
+    if not send_logs_to_telemetry():
+        return
+
+    if level >= logger.LogLevel.WARNING:
+        reporter.add_log_event(level, message)
 
 
 def add_periodic(delta, name, op=WALAEventOperation.Unknown, is_success=True, duration=0,
diff --git a/azurelinuxagent/common/future.py b/azurelinuxagent/common/future.py
index f546bc15..3f2fa8c3 100644
--- a/azurelinuxagent/common/future.py
+++ b/azurelinuxagent/common/future.py
@@ -23,6 +23,8 @@ if sys.version_info[0] == 3:
 
     bytebuffer = memoryview
 
+    from collections import OrderedDict
+
 elif sys.version_info[0] == 2:
     import httplib as httpclient
     from urlparse import urlparse
@@ -32,6 +34,10 @@ elif sys.version_info[0] == 2:
 
     bytebuffer = buffer
 
+    if sys.version_info[1] >= 7:
+        from collections import OrderedDict  # For Py 2.7+
+    else:
+        from ordereddict import OrderedDict  # Works only on 2.6
 else:
     raise ImportError("Unknown python version: {0}".format(sys.version_info))
 
diff --git a/azurelinuxagent/common/logger.py b/azurelinuxagent/common/logger.py
index 5d94afbf..89974cbd 100644
--- a/azurelinuxagent/common/logger.py
+++ b/azurelinuxagent/common/logger.py
@@ -18,9 +18,9 @@
 Log utils
 """
 import sys
+from datetime import datetime, timedelta
 
 from azurelinuxagent.common.future import ustr
-from datetime import datetime, timedelta
 
 EVERY_DAY = timedelta(days=1)
 EVERY_HALF_DAY = timedelta(hours=12)
@@ -28,6 +28,7 @@ EVERY_SIX_HOURS = timedelta(hours=6)
 EVERY_HOUR = timedelta(hours=1)
 EVERY_HALF_HOUR = timedelta(minutes=30)
 EVERY_FIFTEEN_MINUTES = timedelta(minutes=15)
+EVERY_MINUTE = timedelta(minutes=1)
 
 
 class Logger(object):
@@ -81,6 +82,43 @@ class Logger(object):
         self.log(LogLevel.ERROR, msg_format, *args)
 
     def log(self, level, msg_format, *args):
+        def write_log(log_appender):
+            """
+            The appender_lock flag is used to signal if the logger is currently in use. This prevents a subsequent log
+            coming in due to writing of a log statement to be not written.
+
+            Eg:
+            Assuming a logger with two appenders - FileAppender and TelemetryAppender. Here is an example of
+            how using appender_lock flag can help.
+
+            logger.warn("foo")
+                |- log.warn() (azurelinuxagent.common.logger.Logger.warn)
+                    |- log() (azurelinuxagent.common.logger.Logger.log)
+                        |- FileAppender.appender_lock is currently False not log_appender.appender_lock is True
+                            |- We sets it to True.
+                        |- FileAppender.write completes.
+                        |- FileAppender.appender_lock sets to False.
+                        |- TelemetryAppender.appender_lock is currently False not log_appender.appender_lock is True
+                            |- We sets it to True.
+                    [A] |- TelemetryAppender.write gets called but has an error and writes a log.warn("bar")
+                            |- log() (azurelinuxagent.common.logger.Logger.log)
+                            |- FileAppender.appender_lock is set to True (log_appender.appender_lock was false when entering).
+                            |- FileAppender.write completes.
+                            |- FileAppender.appender_lock sets to False.
+                            |- TelemetryAppender.appender_lock is already True, not log_appender.appender_lock is False
+                            Thus [A] cannot happen again if TelemetryAppender.write is not getting called. It prevents
+                            faulty appenders to not get called again and again.
+
+            :param log_appender: Appender
+            :return: None
+            """
+            if not log_appender.appender_lock:
+                try:
+                    log_appender.appender_lock = True
+                    log_appender.write(level, log_item)
+                finally:
+                    log_appender.appender_lock = False
+
         # if msg_format is not unicode convert it to unicode
         if type(msg_format) is not ustr:
             msg_format = ustr(msg_format, errors="backslashreplace")
@@ -88,7 +126,8 @@ class Logger(object):
             msg = msg_format.format(*args)
         else:
             msg = msg_format
-        time = datetime.now().strftime(u'%Y/%m/%d %H:%M:%S.%f')
+            # This format is based on ISO-8601, Z represents UTC (Zero offset)
+        time = datetime.utcnow().isoformat() + "Z"
         level_str = LogLevel.STRINGS[level]
         if self.prefix is not None:
             log_item = u"{0} {1} {2} {3}\n".format(time, level_str, self.prefix,
@@ -100,19 +139,28 @@ class Logger(object):
                         encoding="ascii")
 
         for appender in self.appenders:
-            appender.write(level, log_item)
+            write_log(appender)
         if self.logger != self:
             for appender in self.logger.appenders:
-                appender.write(level, log_item)
+                write_log(appender)
 
     def add_appender(self, appender_type, level, path):
         appender = _create_logger_appender(appender_type, level, path)
         self.appenders.append(appender)
 
 
-class ConsoleAppender(object):
-    def __init__(self, level, path):
+class Appender(object):
+    def __init__(self, level):
+        self.appender_lock = False
         self.level = level
+
+    def write(self, level, msg):
+        pass
+
+
+class ConsoleAppender(Appender):
+    def __init__(self, level, path):
+        super(ConsoleAppender, self).__init__(level)
         self.path = path
 
     def write(self, level, msg):
@@ -124,9 +172,9 @@ class ConsoleAppender(object):
                 pass
 
 
-class FileAppender(object):
+class FileAppender(Appender):
     def __init__(self, level, path):
-        self.level = level
+        super(FileAppender, self).__init__(level)
         self.path = path
 
     def write(self, level, msg):
@@ -138,9 +186,9 @@ class FileAppender(object):
                 pass
 
 
-class StdoutAppender(object):
+class StdoutAppender(Appender):
     def __init__(self, level):
-        self.level = level
+        super(StdoutAppender, self).__init__(level)
 
     def write(self, level, msg):
         if self.level <= level:
@@ -150,9 +198,9 @@ class StdoutAppender(object):
                 pass
 
 
-class TelemetryAppender(object):
+class TelemetryAppender(Appender):
     def __init__(self, level, event_func):
-        self.level = level
+        super(TelemetryAppender, self).__init__(level)
         self.event_func = event_func
 
     def write(self, level, msg):
diff --git a/azurelinuxagent/common/osutil/default.py b/azurelinuxagent/common/osutil/default.py
index 7ccc5344..b99bca43 100644
--- a/azurelinuxagent/common/osutil/default.py
+++ b/azurelinuxagent/common/osutil/default.py
@@ -1072,7 +1072,7 @@ class DefaultOSUtil(object):
                       chk_err=False)
 
     def is_dhcp_available(self):
-        return (True, '')
+        return True
 
     def is_dhcp_enabled(self):
         return False
diff --git a/azurelinuxagent/common/osutil/iosxe.py b/azurelinuxagent/common/osutil/iosxe.py
index 3152ada8..0d45b0e2 100644
--- a/azurelinuxagent/common/osutil/iosxe.py
+++ b/azurelinuxagent/common/osutil/iosxe.py
@@ -63,7 +63,7 @@ class IosxeOSUtil(DefaultOSUtil):
         DefaultOSUtil.openssl_to_openssh(self, input_file, output_file)
 
     def is_dhcp_available(self):
-        return (False, '168.63.129.16')
+        return False
 
     def get_instance_id(self):
         '''
diff --git a/azurelinuxagent/common/protocol/util.py b/azurelinuxagent/common/protocol/util.py
index 692b5489..dab5a26a 100644
--- a/azurelinuxagent/common/protocol/util.py
+++ b/azurelinuxagent/common/protocol/util.py
@@ -35,9 +35,9 @@ from azurelinuxagent.common.osutil import get_osutil
 from azurelinuxagent.common.dhcp import get_dhcp_handler
 from azurelinuxagent.common.protocol.ovfenv import OvfEnv
 from azurelinuxagent.common.protocol.wire import WireProtocol
-from azurelinuxagent.common.protocol.metadata import MetadataProtocol, \
-                                                     METADATA_ENDPOINT
-from azurelinuxagent.common.utils.restutil import IOErrorCounter
+from azurelinuxagent.common.protocol.metadata import MetadataProtocol
+from azurelinuxagent.common.utils.restutil import KNOWN_WIRESERVER_IP, \
+                                                  IOErrorCounter
 
 OVF_FILE_NAME = "ovf-env.xml"
 TAG_FILE_NAME = "useMetadataEndpoint.tag"
@@ -64,14 +64,16 @@ def get_protocol_util():
 
 
 class ProtocolUtil(object):
-
     """
     ProtocolUtil handles initialization for protocol instance. 2 protocol types
     are invoked, wire protocol and metadata protocols.
     """
+
     def __init__(self):
         self.lock = threading.Lock()
+        self.lock_wireserver_endpoint = threading.Lock()
         self.protocol = None
+        self.endpoint = None
         self.osutil = get_osutil()
         self.dhcp_handler = get_dhcp_handler()
 
@@ -95,7 +97,7 @@ class ProtocolUtil(object):
         try:
             ovfxml = fileutil.read_file(ovf_file_path_on_dvd, remove_bom=True)
             ovfenv = OvfEnv(ovfxml)
-        except IOError as e:
+        except (IOError, OSError) as e:
             raise ProtocolError("[CopyOvfEnv] Error reading file "
                                 "{0}: {1}".format(ovf_file_path_on_dvd,
                                                   ustr(e)))
@@ -105,7 +107,7 @@ class ProtocolUtil(object):
                             PASSWORD_REPLACEMENT,
                             ovfxml)
             fileutil.write_file(ovf_file_path, ovfxml)
-        except IOError as e:
+        except (IOError, OSError) as e:
             raise ProtocolError("[CopyOvfEnv] Error writing file "
                                 "{0}: {1}".format(ovf_file_path,
                                                   ustr(e)))
@@ -114,7 +116,7 @@ class ProtocolUtil(object):
             if os.path.isfile(tag_file_path_on_dvd):
                 logger.info("Found {0} in provisioning ISO", TAG_FILE_NAME)
                 shutil.copyfile(tag_file_path_on_dvd, tag_file_path)
-        except IOError as e:
+        except (IOError, OSError) as e:
             raise ProtocolError("[CopyOvfEnv] Error copying file "
                                 "{0} to {1}: {2}".format(tag_file_path,
                                                          tag_file_path,
@@ -147,24 +149,77 @@ class ProtocolUtil(object):
             conf.get_lib_dir(),
             PROTOCOL_FILE_NAME)
 
+    def _get_wireserver_endpoint_file_path(self):
+        return os.path.join(
+            conf.get_lib_dir(),
+            ENDPOINT_FILE_NAME)
+
     def _get_tag_file_path(self):
         return os.path.join(
             conf.get_lib_dir(),
             TAG_FILE_NAME)
 
     def get_wireserver_endpoint(self):
+        self.lock_wireserver_endpoint.acquire()
+
         try:
-            file_path = os.path.join(conf.get_lib_dir(), ENDPOINT_FILE_NAME)
-            return fileutil.read_file(file_path)
-        except IOError as e:
-            raise OSUtilError(ustr(e))
+            if self.endpoint:
+                return self.endpoint
+
+            file_path = self._get_wireserver_endpoint_file_path()
+            if os.path.isfile(file_path):
+                try:
+                    self.endpoint = fileutil.read_file(file_path)
+
+                    if self.endpoint:
+                        logger.info("WireServer endpoint {0} read from file", self.endpoint)
+                        return self.endpoint
+
+                    logger.error("[GetWireserverEndpoint] Unexpected empty file {0}: {1}", file_path, str(e))
+                except (IOError, OSError) as e:
+                    logger.error("[GetWireserverEndpoint] Error reading file {0}: {1}", file_path, str(e))
+            else:
+                logger.error("[GetWireserverEndpoint] Missing file {0}", file_path)
+
+            self.endpoint = KNOWN_WIRESERVER_IP
+            logger.info("Using hardcoded Wireserver endpoint {0}", self.endpoint)
+
+            return self.endpoint
+        finally:
+            self.lock_wireserver_endpoint.release()
 
     def _set_wireserver_endpoint(self, endpoint):
+        self.lock_wireserver_endpoint.acquire()
         try:
-            file_path = os.path.join(conf.get_lib_dir(), ENDPOINT_FILE_NAME)
+            self.endpoint = endpoint
+            file_path = self._get_wireserver_endpoint_file_path()
             fileutil.write_file(file_path, endpoint)
-        except IOError as e:
+        except (IOError, OSError) as e:
             raise OSUtilError(ustr(e))
+        finally:
+            self.lock_wireserver_endpoint.release()
+
+    def _clear_wireserver_endpoint(self):
+        """
+        Cleanup previous saved wireserver endpoint.
+        """
+        self.lock_wireserver_endpoint.acquire()
+
+        try:
+            self.endpoint = None
+            endpoint_file_path = self._get_wireserver_endpoint_file_path()
+            if not os.path.isfile(endpoint_file_path):
+                return
+
+            try:
+                os.remove(endpoint_file_path)
+            except (IOError, OSError) as e:
+                # Ignore file-not-found errors (since the file is being removed)
+                if e.errno == errno.ENOENT:
+                    return
+                logger.error("Failed to clear wiresever endpoint: {0}", e)
+        finally:
+            self.lock_wireserver_endpoint.release()
 
     def _detect_wire_protocol(self):
         endpoint = self.dhcp_handler.endpoint
@@ -172,7 +227,7 @@ class ProtocolUtil(object):
             '''
             Check if DHCP can be used to get the wire protocol endpoint
             '''
-            (dhcp_available, conf_endpoint) =  self.osutil.is_dhcp_available()
+            dhcp_available = self.osutil.is_dhcp_available()
             if dhcp_available:
                 logger.info("WireServer endpoint is not found. Rerun dhcp handler")
                 try:
@@ -183,11 +238,6 @@ class ProtocolUtil(object):
             else:
                 logger.info("_detect_wire_protocol: DHCP not available")
                 endpoint = self.get_wireserver_endpoint()
-                if endpoint == None:
-                    endpoint = conf_endpoint
-                    logger.info("Using hardcoded WireServer endpoint {0}", endpoint)
-                else:
-                    logger.info("WireServer endpoint {0} read from file", endpoint)
 
         try:
             protocol = WireProtocol(endpoint)
@@ -195,7 +245,7 @@ class ProtocolUtil(object):
             self._set_wireserver_endpoint(endpoint)
             return protocol
         except ProtocolError as e:
-            logger.info("WireServer is not responding. Reset endpoint")
+            logger.info("WireServer is not responding. Reset dhcp endpoint")
             self.dhcp_handler.endpoint = None
             self.dhcp_handler.skip_cache = True
             raise e
@@ -254,14 +304,15 @@ class ProtocolUtil(object):
         protocol_file_path = self._get_protocol_file_path()
         try:
             fileutil.write_file(protocol_file_path, protocol_name)
-        except IOError as e:
+        except (IOError, OSError) as e:
             logger.error("Failed to save protocol endpoint: {0}", e)
 
     def clear_protocol(self):
         """
-        Cleanup previous saved endpoint.
+        Cleanup previous saved protocol endpoint.
         """
-        logger.info("Clean protocol")
+        logger.info("Clean protocol and wireserver endpoint")
+        self._clear_wireserver_endpoint()
         self.protocol = None
         protocol_file_path = self._get_protocol_file_path()
         if not os.path.isfile(protocol_file_path):
@@ -269,7 +320,7 @@ class ProtocolUtil(object):
 
         try:
             os.remove(protocol_file_path)
-        except IOError as e:
+        except (IOError, OSError) as e:
             # Ignore file-not-found errors (since the file is being removed)
             if e.errno == errno.ENOENT:
                 return
diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py
index 7f875963..93c30900 100644
--- a/azurelinuxagent/common/protocol/wire.py
+++ b/azurelinuxagent/common/protocol/wire.py
@@ -891,11 +891,11 @@ class WireClient(object):
 
     def get_ext_conf(self):
         if self.ext_conf is None:
-            goal_state = self.get_goal_state()
-            if goal_state.ext_uri is None:
+            local_goal_state = self.get_goal_state()
+            if local_goal_state.ext_uri is None:
                 self.ext_conf = ExtensionsConfig(None)
             else:
-                local_file = EXT_CONF_FILE_NAME.format(goal_state.incarnation)
+                local_file = EXT_CONF_FILE_NAME.format(local_goal_state.incarnation)
                 local_file = os.path.join(conf.get_lib_dir(), local_file)
                 xml_text = self.fetch_cache(local_file)
                 self.ext_conf = ExtensionsConfig(xml_text)
diff --git a/azurelinuxagent/common/utils/restutil.py b/azurelinuxagent/common/utils/restutil.py
index addba28b..fd78b969 100644
--- a/azurelinuxagent/common/utils/restutil.py
+++ b/azurelinuxagent/common/utils/restutil.py
@@ -98,13 +98,13 @@ HTTP_USER_AGENT_HEALTH = "{0}+health".format(HTTP_USER_AGENT)
 INVALID_CONTAINER_CONFIGURATION = "InvalidContainerConfiguration"
 REQUEST_ROLE_CONFIG_FILE_NOT_FOUND = "RequestRoleConfigFileNotFound"
 
-DEFAULT_PROTOCOL_ENDPOINT = '168.63.129.16'
+KNOWN_WIRESERVER_IP = '168.63.129.16'
 HOST_PLUGIN_PORT = 32526
 
 
 class IOErrorCounter(object):
     _lock = threading.RLock()
-    _protocol_endpoint = DEFAULT_PROTOCOL_ENDPOINT
+    _protocol_endpoint = KNOWN_WIRESERVER_IP
     _counts = {"hostplugin":0, "protocol":0, "other":0}
 
     @staticmethod
@@ -131,7 +131,7 @@ class IOErrorCounter(object):
             IOErrorCounter._counts = {"hostplugin":0, "protocol":0, "other":0}
 
     @staticmethod
-    def set_protocol_endpoint(endpoint=DEFAULT_PROTOCOL_ENDPOINT):
+    def set_protocol_endpoint(endpoint=KNOWN_WIRESERVER_IP):
         IOErrorCounter._protocol_endpoint = endpoint
 
 
diff --git a/azurelinuxagent/daemon/resourcedisk/default.py b/azurelinuxagent/daemon/resourcedisk/default.py
index 5ed14b01..35ddfb4e 100644
--- a/azurelinuxagent/daemon/resourcedisk/default.py
+++ b/azurelinuxagent/daemon/resourcedisk/default.py
@@ -249,14 +249,20 @@ class ResourceDiskHandler(object):
 
         return err_code, output
 
-    @staticmethod
-    def get_mount_string(mount_options, partition, mount_point):
+    def get_mount_string(self, mount_options, partition, mount_point):
         if mount_options is not None:
-            return 'mount -o {0} {1} {2}'.format(mount_options,
-                                                 partition,
-                                                 mount_point)
+            return 'mount -t {0} -o {1} {2} {3}'.format(
+                self.fs,
+                mount_options,
+                partition,
+                mount_point
+            )
         else:
-            return 'mount {0} {1}'.format(partition, mount_point)
+            return 'mount -t {0} {1} {2}'.format(
+                self.fs,
+                partition,
+                mount_point
+            )
 
     @staticmethod
     def check_existing_swap_file(swapfile, swaplist, size):
diff --git a/azurelinuxagent/ga/monitor.py b/azurelinuxagent/ga/monitor.py
index cbdbf8d2..102018e6 100644
--- a/azurelinuxagent/ga/monitor.py
+++ b/azurelinuxagent/ga/monitor.py
@@ -26,11 +26,11 @@ import uuid
 import azurelinuxagent.common.conf as conf
 import azurelinuxagent.common.logger as logger
 import azurelinuxagent.common.utils.networkutil as networkutil
-
 from azurelinuxagent.common.cgroupstelemetry import CGroupsTelemetry
+from azurelinuxagent.common.datacontract import set_properties
 from azurelinuxagent.common.errorstate import ErrorState
-from azurelinuxagent.common.event import add_event, WALAEventOperation, CONTAINER_ID_ENV_VARIABLE, \
-    get_container_id_from_env
+from azurelinuxagent.common.event import EventLogger
+from azurelinuxagent.common.event import add_event, WALAEventOperation, report_metric
 from azurelinuxagent.common.exception import EventError, ProtocolError, OSUtilError, HttpError
 from azurelinuxagent.common.future import ustr
 from azurelinuxagent.common.osutil import get_osutil
@@ -38,11 +38,10 @@ from azurelinuxagent.common.protocol import get_protocol_util
 from azurelinuxagent.common.protocol.healthservice import HealthService
 from azurelinuxagent.common.protocol.imds import get_imds_client
 from azurelinuxagent.common.telemetryevent import TelemetryEvent, TelemetryEventParam, TelemetryEventList
-from azurelinuxagent.common.datacontract import set_properties
 from azurelinuxagent.common.utils.restutil import IOErrorCounter
 from azurelinuxagent.common.utils.textutil import parse_doc, findall, find, getattrib, hash_strings
 from azurelinuxagent.common.version import DISTRO_NAME, DISTRO_VERSION, \
-    DISTRO_CODE_NAME, AGENT_NAME, CURRENT_AGENT, CURRENT_VERSION, AGENT_EXECUTION_MODE
+    DISTRO_CODE_NAME, AGENT_NAME, CURRENT_VERSION, AGENT_EXECUTION_MODE
 
 
 def parse_event(data_str):
@@ -178,8 +177,8 @@ class MonitorHandler(object):
         try:
             ram = self.osutil.get_total_mem()
             processors = self.osutil.get_processor_cores()
-            self.sysinfo.append(TelemetryEventParam("RAM", ram))
-            self.sysinfo.append(TelemetryEventParam("Processors", processors))
+            self.sysinfo.append(TelemetryEventParam("RAM", int(ram)))
+            self.sysinfo.append(TelemetryEventParam("Processors", int(processors)))
         except OSUtilError as e:
             logger.warn("Failed to get system info: {0}", ustr(e))
 
@@ -207,7 +206,7 @@ class MonitorHandler(object):
             self.sysinfo.append(TelemetryEventParam('VMId',
                                                     vminfo.vmId))
             self.sysinfo.append(TelemetryEventParam('ImageOrigin',
-                                                    vminfo.image_origin))
+                                                    int(vminfo.image_origin)))
         except (HttpError, ValueError) as e:
             logger.warn("failed to get IMDS info: {0}", ustr(e))
 
@@ -221,7 +220,7 @@ class MonitorHandler(object):
             logger.verbose("Processed event file: {0}", evt_file_name)
             os.remove(evt_file_name)
             return data_str
-        except (IOError, UnicodeDecodeError) as e:
+        except (IOError, OSError, UnicodeDecodeError) as e:
             os.remove(evt_file_name)
             msg = "Failed to process {0}, {1}".format(evt_file_name, e)
             raise EventError(msg)
@@ -281,7 +280,7 @@ class MonitorHandler(object):
         while self.should_run:
             self.send_telemetry_heartbeat()
             self.poll_telemetry_metrics()
-            self.send_telemetry_metrics()
+            self.send_telemetry_metrics()   # This will be removed in favor of poll_telemetry_metrics() and it'll directly send the perf data for each cgroup.
             self.collect_and_send_events()
             self.send_host_plugin_heartbeat()
             self.send_imds_heartbeat()
@@ -320,14 +319,6 @@ class MonitorHandler(object):
         sysinfo_names = [v.name for v in self.sysinfo]
         final_parameters = []
 
-        # Refer: azurelinuxagent.common.event.EventLogger.add_default_parameters_to_event for agent specific values.
-        #
-        # Default fields are only populated by Agent and not the extension. Agent will fill up any event if they don't
-        # have the default params. Example: GAVersion and ContainerId are populated for agent events on the fly,
-        # but not for extension events. Add it if it's missing.
-        default_values = [("ContainerId", get_container_id_from_env()), ("GAVersion", CURRENT_AGENT),
-                          ("OpcodeName", ""), ("EventTid", 0), ("EventPid", 0), ("TaskName", ""), ("KeywordName", "")]
-
         for param in event.parameters:
             # Discard any sys_info parameters already in the event, since they will be overwritten
             if param.name in sysinfo_names:
@@ -336,10 +327,7 @@ class MonitorHandler(object):
 
         # Add sys_info params populated by the agent
         final_parameters.extend(self.sysinfo)
-
-        for default_value in default_values:
-            if default_value[0] not in event:
-                final_parameters.append(TelemetryEventParam(default_value[0], default_value[1]))
+        final_parameters = EventLogger.add_default_parameters_to_event(final_parameters, set_values_for_agent=False)
 
         event.parameters = final_parameters
 
@@ -467,16 +455,30 @@ class MonitorHandler(object):
             self.last_telemetry_heartbeat = datetime.datetime.utcnow()
 
     def poll_telemetry_metrics(self):
+        """
+        This method polls the tracked cgroups to get data from the cgroups filesystem and send the data directly.
+
+        :return:
+        """
         time_now = datetime.datetime.utcnow()
         if not self.last_cgroup_polling_telemetry:
             self.last_cgroup_polling_telemetry = time_now
 
         if time_now >= (self.last_cgroup_polling_telemetry +
                         MonitorHandler.CGROUP_TELEMETRY_POLLING_PERIOD):
-            CGroupsTelemetry.poll_all_tracked()
+            metrics = CGroupsTelemetry.poll_all_tracked()
             self.last_cgroup_polling_telemetry = time_now
 
+            if metrics:
+                for metric in metrics:
+                    report_metric(metric.category, metric.counter, metric.instance, metric.value)
+
     def send_telemetry_metrics(self):
+        """
+        The send_telemetry_metrics would soon be removed in favor of sending performance metrics directly.
+
+        :return:
+        """
         time_now = datetime.datetime.utcnow()
 
         if not self.last_cgroup_report_telemetry:


Test patch:
diff --git a/tests/common/dhcp/test_dhcp.py b/tests/common/dhcp/test_dhcp.py
index 4be5e622..0b6adb0f 100644
--- a/tests/common/dhcp/test_dhcp.py
+++ b/tests/common/dhcp/test_dhcp.py
@@ -18,7 +18,7 @@
 import mock
 import azurelinuxagent.common.dhcp as dhcp
 import azurelinuxagent.common.osutil.default as osutil
-from tests.tools import *
+from tests.tools import AgentTestCase, open_patch, patch
 
 
 class TestDHCP(AgentTestCase):
diff --git a/tests/common/osutil/test_alpine.py b/tests/common/osutil/test_alpine.py
index d2f52b8d..ea0c6d8a 100644
--- a/tests/common/osutil/test_alpine.py
+++ b/tests/common/osutil/test_alpine.py
@@ -16,7 +16,8 @@
 #
 from azurelinuxagent.common.osutil.alpine import AlpineOSUtil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase
+import unittest
 
 
 class TestAlpineOSUtil(AgentTestCase):
diff --git a/tests/common/osutil/test_arch.py b/tests/common/osutil/test_arch.py
index f3c4b64a..eeda8560 100644
--- a/tests/common/osutil/test_arch.py
+++ b/tests/common/osutil/test_arch.py
@@ -16,7 +16,8 @@
 #
 from azurelinuxagent.common.osutil.arch import ArchUtil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase
+import unittest
 
 
 class TestArchUtil(AgentTestCase):
diff --git a/tests/common/osutil/test_bigip.py b/tests/common/osutil/test_bigip.py
index f8067eb6..43516167 100644
--- a/tests/common/osutil/test_bigip.py
+++ b/tests/common/osutil/test_bigip.py
@@ -15,16 +15,20 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
+import os
 import socket
+import time
+import unittest
 
 import azurelinuxagent.common.osutil.bigip as osutil
 import azurelinuxagent.common.osutil.default as default
 import azurelinuxagent.common.utils.shellutil as shellutil
 
 from azurelinuxagent.common.exception import OSUtilError
+import azurelinuxagent.common.logger as logger
 from azurelinuxagent.common.osutil.bigip import BigIpOSUtil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
 
 
 class TestBigIpOSUtil_wait_until_mcpd_is_initialized(AgentTestCase):
diff --git a/tests/common/osutil/test_clearlinux.py b/tests/common/osutil/test_clearlinux.py
index 03782f9b..a11d79a9 100644
--- a/tests/common/osutil/test_clearlinux.py
+++ b/tests/common/osutil/test_clearlinux.py
@@ -16,7 +16,8 @@
 #
 from azurelinuxagent.common.osutil.clearlinux import ClearLinuxUtil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase
+import unittest
 
 
 class TestClearLinuxUtil(AgentTestCase):
diff --git a/tests/common/osutil/test_coreos.py b/tests/common/osutil/test_coreos.py
index f5425873..fca73f6f 100644
--- a/tests/common/osutil/test_coreos.py
+++ b/tests/common/osutil/test_coreos.py
@@ -16,7 +16,8 @@
 #
 from azurelinuxagent.common.osutil.coreos import CoreOSUtil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase
+import unittest
 
 
 class TestAlpineOSUtil(AgentTestCase):
diff --git a/tests/common/osutil/test_default.py b/tests/common/osutil/test_default.py
index 968499b7..f2dd87d1 100644
--- a/tests/common/osutil/test_default.py
+++ b/tests/common/osutil/test_default.py
@@ -19,16 +19,20 @@ import socket
 import glob
 import mock
 import traceback
-import re
+import os
+import tempfile
+import unittest
 
 import azurelinuxagent.common.osutil.default as osutil
 import azurelinuxagent.common.utils.shellutil as shellutil
 import azurelinuxagent.common.utils.textutil as textutil
+import azurelinuxagent.common.conf as conf
 from azurelinuxagent.common.exception import OSUtilError
 from azurelinuxagent.common.future import ustr
 from azurelinuxagent.common.osutil import get_osutil
-from tests.tools import *
-
+from azurelinuxagent.common.utils import fileutil
+from tests.tools import AgentTestCase, call, patch, open_patch, load_data, \
+    running_under_travis, skip_if_predicate_true
 
 actual_get_proc_net_route = 'azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_net_route'
 
diff --git a/tests/common/osutil/test_default_osutil.py b/tests/common/osutil/test_default_osutil.py
index 2105e8c5..b0299ade 100644
--- a/tests/common/osutil/test_default_osutil.py
+++ b/tests/common/osutil/test_default_osutil.py
@@ -16,7 +16,8 @@
 #
 
 from azurelinuxagent.common.osutil.default import DefaultOSUtil, shellutil
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
+import os
 
 
 class DefaultOsUtilTestCase(AgentTestCase):
diff --git a/tests/common/osutil/test_factory.py b/tests/common/osutil/test_factory.py
index 92aa7d6e..adc099d5 100644
--- a/tests/common/osutil/test_factory.py
+++ b/tests/common/osutil/test_factory.py
@@ -32,7 +32,7 @@ from azurelinuxagent.common.osutil.bigip import BigIpOSUtil
 from azurelinuxagent.common.osutil.gaia import GaiaOSUtil
 from azurelinuxagent.common.osutil.iosxe import IosxeOSUtil
 from azurelinuxagent.common.osutil.openwrt import OpenWRTOSUtil
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
 
 
 class TestOsUtilFactory(AgentTestCase):
diff --git a/tests/common/osutil/test_freebsd.py b/tests/common/osutil/test_freebsd.py
index 1b1f687b..b7caa609 100644
--- a/tests/common/osutil/test_freebsd.py
+++ b/tests/common/osutil/test_freebsd.py
@@ -14,12 +14,14 @@
 #
 # Requires Python 2.6+ and Openssl 1.0+
 #
-import mock
 
 from azurelinuxagent.common.osutil.freebsd import FreeBSDOSUtil
 import azurelinuxagent.common.utils.shellutil as shellutil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
+import traceback
+import unittest
+
 
 class TestFreeBSDOSUtil(AgentTestCase):
     def setUp(self):
diff --git a/tests/common/osutil/test_nsbsd.py b/tests/common/osutil/test_nsbsd.py
index 4e7082e5..87615f66 100644
--- a/tests/common/osutil/test_nsbsd.py
+++ b/tests/common/osutil/test_nsbsd.py
@@ -16,9 +16,9 @@
 #
 from azurelinuxagent.common.utils.fileutil import read_file
 from azurelinuxagent.common.osutil.nsbsd import NSBSDOSUtil
-from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
 from os import path
+import unittest
 
 
 class TestNSBSDOSUtil(AgentTestCase):
diff --git a/tests/common/osutil/test_openbsd.py b/tests/common/osutil/test_openbsd.py
index 76f214ef..1cee03f4 100644
--- a/tests/common/osutil/test_openbsd.py
+++ b/tests/common/osutil/test_openbsd.py
@@ -16,7 +16,8 @@
 #
 from azurelinuxagent.common.osutil.openbsd import OpenBSDOSUtil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase
+import unittest
 
 
 class TestAlpineOSUtil(AgentTestCase):
diff --git a/tests/common/osutil/test_openwrt.py b/tests/common/osutil/test_openwrt.py
index 3d72acd2..b6286dc9 100644
--- a/tests/common/osutil/test_openwrt.py
+++ b/tests/common/osutil/test_openwrt.py
@@ -16,7 +16,8 @@
 #
 from azurelinuxagent.common.osutil.openwrt import OpenWRTOSUtil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase
+import unittest
 
 
 class TestOpenWRTOSUtil(AgentTestCase):
diff --git a/tests/common/osutil/test_redhat.py b/tests/common/osutil/test_redhat.py
index ef8a3f96..c2926e03 100644
--- a/tests/common/osutil/test_redhat.py
+++ b/tests/common/osutil/test_redhat.py
@@ -16,7 +16,8 @@
 #
 from azurelinuxagent.common.osutil.redhat import Redhat6xOSUtil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase
+import unittest
 
 
 class TestRedhat6xOSUtil(AgentTestCase):
diff --git a/tests/common/osutil/test_suse.py b/tests/common/osutil/test_suse.py
index 8dbfce9c..e3ea661d 100644
--- a/tests/common/osutil/test_suse.py
+++ b/tests/common/osutil/test_suse.py
@@ -16,7 +16,8 @@
 #
 from azurelinuxagent.common.osutil.suse import SUSE11OSUtil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase
+import unittest
 
 
 class TestSUSE11OSUtil(AgentTestCase):
diff --git a/tests/common/osutil/test_ubuntu.py b/tests/common/osutil/test_ubuntu.py
index 6ca9aa2f..995c1c4b 100644
--- a/tests/common/osutil/test_ubuntu.py
+++ b/tests/common/osutil/test_ubuntu.py
@@ -14,9 +14,12 @@
 #
 # Requires Python 2.6+ and Openssl 1.0+
 #
+
+import unittest
+
 from azurelinuxagent.common.osutil.ubuntu import Ubuntu12OSUtil, Ubuntu18OSUtil
 from .test_default import osutil_get_dhcp_pid_should_return_a_list_of_pids
-from tests.tools import *
+from tests.tools import AgentTestCase
 
 
 class TestUbuntu12OSUtil(AgentTestCase):
diff --git a/tests/common/test_cgroups.py b/tests/common/test_cgroups.py
index 711ef62e..b33bc94f 100644
--- a/tests/common/test_cgroups.py
+++ b/tests/common/test_cgroups.py
@@ -46,7 +46,10 @@ class TestCGroup(AgentTestCase):
         with open(os.path.join(data_dir, "cgroups", "memory_mount", "tasks"), mode="wb") as tasks:
             tasks.truncate(0)
 
-    def test_correct_creation(self):
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    def test_correct_creation(self, *_):
         test_cgroup = CGroup.create("dummy_path", "cpu", "test_extension")
         self.assertIsInstance(test_cgroup, CpuCgroup)
         self.assertEqual(test_cgroup.controller, "cpu")
@@ -59,7 +62,10 @@ class TestCGroup(AgentTestCase):
         self.assertEqual(test_cgroup.path, "dummy_path")
         self.assertEqual(test_cgroup.name, "test_extension")
 
-    def test_is_active(self):
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    def test_is_active(self, *_):
         test_cgroup = CGroup.create(os.path.join(data_dir, "cgroups", "cpu_mount"), "cpu", "test_extension")
         self.assertEqual(False, test_cgroup.is_active())
 
@@ -76,8 +82,11 @@ class TestCGroup(AgentTestCase):
 
         self.assertEqual(True, test_cgroup.is_active())
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch("azurelinuxagent.common.logger.periodic_warn")
-    def test_is_active_file_not_present(self, patch_periodic_warn):
+    def test_is_active_file_not_present(self, patch_periodic_warn, *_):
         test_cgroup = CGroup.create(os.path.join(data_dir, "cgroups", "not_cpu_mount"), "cpu", "test_extension")
         self.assertEqual(False, test_cgroup.is_active())
 
@@ -86,8 +95,11 @@ class TestCGroup(AgentTestCase):
 
         self.assertEqual(0, patch_periodic_warn.call_count)
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch("azurelinuxagent.common.logger.periodic_warn")
-    def test_is_active_incorrect_file(self, patch_periodic_warn):
+    def test_is_active_incorrect_file(self, patch_periodic_warn, *_):
         test_cgroup = CGroup.create(os.path.join(data_dir, "cgroups", "cpu_mount", "tasks"), "cpu", "test_extension")
         self.assertEqual(False, test_cgroup.is_active())
         self.assertEqual(1, patch_periodic_warn.call_count)
@@ -101,6 +113,8 @@ class TestCpuCgroup(AgentTestCase):
     def setUp(self):
         AgentTestCase.setUp(self)
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_cpu_cgroup_create(self, patch_get_proc_stat):
         patch_get_proc_stat.return_value = fileutil.read_file(os.path.join(data_dir, "cgroups", "dummy_proc_stat"))
@@ -113,6 +127,8 @@ class TestCpuCgroup(AgentTestCase):
 
         self.assertEqual("cpu", test_cpu_cg.controller)
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_processor_cores", return_value=1)
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_get_cpu_usage(self, patch_get_proc_stat, *args):
@@ -127,7 +143,10 @@ class TestCpuCgroup(AgentTestCase):
 
         self.assertEqual(5.114, cpu_usage)
 
-    def test_get_current_cpu_total_exception_handling(self):
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    def test_get_current_cpu_total_exception_handling(self, *_):
         test_cpu_cg = CpuCgroup("test_extension", "dummy_path")
         self.assertRaises(IOError, test_cpu_cg._get_current_cpu_total)
 
diff --git a/tests/common/test_cgroupstelemetry.py b/tests/common/test_cgroupstelemetry.py
index 0556cd1b..e53b08cc 100644
--- a/tests/common/test_cgroupstelemetry.py
+++ b/tests/common/test_cgroupstelemetry.py
@@ -19,17 +19,22 @@ import os
 import random
 import time
 
-from mock import patch
-
 from azurelinuxagent.common.cgroup import CGroup
 from azurelinuxagent.common.cgroupconfigurator import CGroupConfigurator
 from azurelinuxagent.common.cgroupstelemetry import CGroupsTelemetry, Metric
-from azurelinuxagent.common.osutil.default import BASE_CGROUPS
+from azurelinuxagent.common.osutil.default import BASE_CGROUPS, DefaultOSUtil
 from azurelinuxagent.common.protocol.restapi import ExtHandlerProperties, ExtHandler
 from azurelinuxagent.ga.exthandlers import ExtHandlerInstance
 from nose.plugins.attrib import attr
 from tests.tools import AgentTestCase, skip_if_predicate_false, skip_if_predicate_true, \
-                        are_cgroups_enabled, is_trusty_in_travis, i_am_root
+                        are_cgroups_enabled, is_trusty_in_travis, i_am_root, patch
+
+
+def raise_ioerror(*_):
+    e = IOError()
+    from errno import EIO
+    e.errno = EIO
+    raise e
 
 
 def median(lst):
@@ -86,6 +91,19 @@ class TestCGroupsTelemetry(AgentTestCase):
             self.assertListEqual(cgroup_metric.get_max_memory_usage()._data, max_memory_usage)
             self.assertListEqual(cgroup_metric.get_cpu_usage()._data, cpu_usage)
 
+    def _assert_cgroup_polling_metrics_equal(self, metrics, cpu_metric_value, memory_metric_value, max_memory_metric_value):
+        for metric in metrics:
+            self.assertIn(metric.category, ["Process", "Memory"])
+            if metric.category == "Process":
+                self.assertEqual(metric.counter, "% Processor Time")
+                self.assertEqual(metric.value, cpu_metric_value)
+            if metric.category == "Memory":
+                self.assertIn(metric.counter, ["Total Memory Usage", "Max Memory Usage"])
+                if metric.counter == "Total Memory Usage":
+                    self.assertEqual(metric.value, memory_metric_value)
+                elif metric.counter == "Max Memory Usage":
+                    self.assertEqual(metric.value, max_memory_metric_value)
+
     @patch("azurelinuxagent.common.cgroup.CpuCgroup._get_current_cpu_total")
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_total_cpu_ticks_since_boot")
     def test_telemetry_polling_with_active_cgroups(self, *args):
@@ -115,12 +133,14 @@ class TestCGroupsTelemetry(AgentTestCase):
                         poll_count = 1
 
                         for data_count in range(poll_count, 10):
-                            CGroupsTelemetry.poll_all_tracked()
+                            metrics = CGroupsTelemetry.poll_all_tracked()
                             self.assertEqual(len(CGroupsTelemetry._cgroup_metrics), num_extensions)
                             self._assert_cgroup_metrics_equal(
                                 cpu_usage=[current_cpu] * data_count,
                                 memory_usage=[current_memory] * data_count,
                                 max_memory_usage=[current_max_memory] * data_count)
+                            self.assertEqual(len(metrics), num_extensions * 3)
+                            self._assert_cgroup_polling_metrics_equal(metrics, current_cpu, current_memory, current_max_memory)
 
                         CGroupsTelemetry.report_all_tracked()
 
@@ -159,7 +179,7 @@ class TestCGroupsTelemetry(AgentTestCase):
                             self.assertTrue(CGroupsTelemetry.is_tracked("dummy_cpu_path_{0}".format(i)))
                             self.assertTrue(CGroupsTelemetry.is_tracked("dummy_memory_path_{0}".format(i)))
 
-                        CGroupsTelemetry.poll_all_tracked()
+                        metrics = CGroupsTelemetry.poll_all_tracked()
 
                         for i in range(num_extensions):
                             self.assertFalse(CGroupsTelemetry.is_tracked("dummy_cpu_path_{0}".format(i)))
@@ -170,6 +190,8 @@ class TestCGroupsTelemetry(AgentTestCase):
                             cpu_usage=[current_cpu] * data_count,
                             memory_usage=[current_memory] * data_count,
                             max_memory_usage=[current_max_memory] * data_count)
+                        self.assertEqual(len(metrics), num_extensions * 3)
+                        self._assert_cgroup_polling_metrics_equal(metrics, current_cpu, current_memory, current_max_memory)
 
                         CGroupsTelemetry.report_all_tracked()
 
@@ -235,6 +257,8 @@ class TestCGroupsTelemetry(AgentTestCase):
                         self.assertEqual(CGroupsTelemetry._cgroup_metrics.__len__(), no_extensions_expected)
                         self._assert_cgroup_metrics_equal([], [], [])
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch("azurelinuxagent.common.logger.periodic_warn")
     @patch("azurelinuxagent.common.utils.fileutil.read_file")
@@ -261,6 +285,8 @@ class TestCGroupsTelemetry(AgentTestCase):
             CGroupsTelemetry.poll_all_tracked()
             self.assertEqual(0, patch_periodic_warn.call_count)
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch("azurelinuxagent.common.logger.periodic_warn")
     @patch("azurelinuxagent.common.utils.fileutil.read_file")
@@ -294,6 +320,8 @@ class TestCGroupsTelemetry(AgentTestCase):
             CGroupsTelemetry.poll_all_tracked()
             self.assertEqual(poll_count * expected_count_per_call, patch_periodic_warn.call_count)
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch("azurelinuxagent.common.utils.fileutil.read_file")
     def test_telemetry_polling_to_generate_transient_logs_index_error(self, mock_read_file, *args):
@@ -349,7 +377,10 @@ class TestCGroupsTelemetry(AgentTestCase):
                             patch_get_cpu_percent.return_value = cpu_percent_values[i]
                             patch_get_memory_usage.return_value = memory_usage_values[i]  # example 200 MB
                             patch_get_memory_max_usage.return_value = max_memory_usage_values[i]  # example 450 MB
-                            CGroupsTelemetry.poll_all_tracked()
+                            metrics = CGroupsTelemetry.poll_all_tracked()
+                            self.assertEqual(len(metrics), 3 * num_extensions)
+                            self._assert_cgroup_polling_metrics_equal(metrics, cpu_percent_values[i], memory_usage_values[i],
+                                                                      max_memory_usage_values[i])
 
         collected_metrics = CGroupsTelemetry.report_all_tracked()
         for i in range(num_extensions):
@@ -373,8 +404,8 @@ class TestCGroupsTelemetry(AgentTestCase):
             self.assertListEqual(generate_metric_list(cpu_percent_values),
                                  collected_metrics[name]["cpu"]["cur_cpu"][0:5])
 
-    # mocking get_proc_stat to make it run on Mac and other systems
-    # this test does not need to read the values of the /proc/stat file
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_cgroup_tracking(self, *args):
         num_extensions = 5
@@ -393,8 +424,8 @@ class TestCGroupsTelemetry(AgentTestCase):
 
         self.assertEqual(num_extensions * num_controllers, len(CGroupsTelemetry._tracked))
 
-    # mocking get_proc_stat to make it run on Mac and other systems
-    # this test does not need to read the values of the /proc/stat file
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_cgroup_pruning(self, *args):
         num_extensions = 5
@@ -421,8 +452,8 @@ class TestCGroupsTelemetry(AgentTestCase):
 
         self.assertEqual(0, len(CGroupsTelemetry._tracked))
 
-    # mocking get_proc_stat to make it run on Mac and other systems
-    # this test does not need to read the values of the /proc/stat file
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_cgroup_is_tracked(self, *args):
         num_extensions = 5
@@ -441,8 +472,8 @@ class TestCGroupsTelemetry(AgentTestCase):
         self.assertFalse(CGroupsTelemetry.is_tracked("not_present_cpu_dummy_path"))
         self.assertFalse(CGroupsTelemetry.is_tracked("not_present_memory_dummy_path"))
 
-    # mocking get_proc_stat to make it run on Mac and other systems
-    # this test does not need to read the values of the /proc/stat file
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_process_cgroup_metric_with_incorrect_cgroups_mounted(self, *args):
         num_extensions = 5
@@ -460,7 +491,8 @@ class TestCGroupsTelemetry(AgentTestCase):
                 patch_get_memory_usage.side_effect = Exception("File not found")
 
                 for data_count in range(1, 10):
-                    CGroupsTelemetry.poll_all_tracked()
+                    metrics = CGroupsTelemetry.poll_all_tracked()
+                    self.assertEqual(len(metrics), 0)
 
                 self.assertEqual(CGroupsTelemetry._cgroup_metrics.__len__(), num_extensions)
 
@@ -494,10 +526,12 @@ class TestCGroupsTelemetry(AgentTestCase):
                     poll_count = 1
 
                     for data_count in range(poll_count, 10):
-                        CGroupsTelemetry.poll_all_tracked()
+                        metrics = CGroupsTelemetry.poll_all_tracked()
 
                         self.assertEqual(CGroupsTelemetry._cgroup_metrics.__len__(), num_extensions)
                         self._assert_cgroup_metrics_equal(cpu_usage=[current_cpu] * data_count, memory_usage=[], max_memory_usage=[])
+                        self.assertEqual(len(metrics), num_extensions * 1)  # Only CPU populated
+                        self._assert_cgroup_polling_metrics_equal(metrics, current_cpu, 0, 0)
 
                     CGroupsTelemetry.report_all_tracked()
 
@@ -533,30 +567,33 @@ class TestCGroupsTelemetry(AgentTestCase):
                         poll_count = 1
 
                         for data_count in range(poll_count, 10):
-                            CGroupsTelemetry.poll_all_tracked()
+                            metrics = CGroupsTelemetry.poll_all_tracked()
                             self.assertEqual(len(CGroupsTelemetry._cgroup_metrics), num_extensions)
                             self._assert_cgroup_metrics_equal(
                                 cpu_usage=[],
                                 memory_usage=[current_memory] * data_count,
                                 max_memory_usage=[current_max_memory] * data_count)
+                            # Memory is only populated, CPU is not. Thus 2 metrics per cgroup.
+                            self.assertEqual(len(metrics), num_extensions * 2)
+                            self._assert_cgroup_polling_metrics_equal(metrics, 0, current_memory, current_max_memory)
 
                         CGroupsTelemetry.report_all_tracked()
 
                         self.assertEqual(len(CGroupsTelemetry._cgroup_metrics), num_extensions)
                         self._assert_cgroup_metrics_equal([], [], [])
 
-    @patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage")
-    @patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_max_memory_usage")
-    @patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage")
+    @patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage", side_effect=raise_ioerror)
+    @patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_max_memory_usage", side_effect=raise_ioerror)
+    @patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage", side_effect=raise_ioerror)
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_total_cpu_ticks_since_boot")
-    def test_extension_temetry_not_sent_for_empty_perf_metrics(self, *args):
+    def test_extension_telemetry_not_sent_for_empty_perf_metrics(self, *args):
         num_extensions = 5
         for i in range(num_extensions):
             dummy_cpu_cgroup = CGroup.create("dummy_cpu_path_{0}".format(i), "cpu", "dummy_extension_{0}".format(i))
             CGroupsTelemetry.track_cgroup(dummy_cpu_cgroup)
 
-            dummy_memory_cgroup = CGroup.create("dummy_memory_path_{0}".format(i), "memory",
-                                                "dummy_extension_{0}".format(i))
+            dummy_memory_cgroup = CGroup.create("dummy_memory_path_{0}".format(i),
+                                                "memory", "dummy_extension_{0}".format(i))
             CGroupsTelemetry.track_cgroup(dummy_memory_cgroup)
 
         with patch("azurelinuxagent.common.cgroupstelemetry.CGroupsTelemetry._process_cgroup_metric") as \
@@ -568,39 +605,39 @@ class TestCGroupsTelemetry(AgentTestCase):
                 poll_count = 1
 
                 for data_count in range(poll_count, 10):
-                    CGroupsTelemetry.poll_all_tracked()
+                    metrics = CGroupsTelemetry.poll_all_tracked()
+                    self.assertEqual(0, len(metrics))
 
                 collected_metrics = CGroupsTelemetry.report_all_tracked()
                 self.assertEqual(0, len(collected_metrics))
 
+    @skip_if_predicate_true(lambda: True, "Skipping this test currently: We need two different tests - one for "
+                                  "FileSystemCgroupAPI based test and one for SystemDCgroupAPI based test. @vrdmr will "
+                                  "be splitting this test in subsequent PRs")
     @skip_if_predicate_false(are_cgroups_enabled, "Does not run when Cgroups are not enabled")
     @skip_if_predicate_true(is_trusty_in_travis, "Does not run on Trusty in Travis")
     @attr('requires_sudo')
-    def test_telemetry_with_tracked_cgroup(self):
+    @patch("azurelinuxagent.common.cgroupconfigurator.get_osutil", return_value=DefaultOSUtil())
+    @patch("azurelinuxagent.common.cgroupapi.CGroupsApi._is_systemd", return_value=False)
+    def test_telemetry_with_tracked_cgroup(self, *_):
         self.assertTrue(i_am_root(), "Test does not run when non-root")
+        CGroupConfigurator._instance = None
 
-        # This test has some timing issues when systemd is managing cgroups, so we force the file system API
-        # by creating a new instance of the CGroupConfigurator
-        with patch("azurelinuxagent.common.cgroupapi.CGroupsApi._is_systemd", return_value=False):
-            cgroup_configurator_instance = CGroupConfigurator._instance
-            CGroupConfigurator._instance = None
-
-            try:
-                max_num_polls = 30
-                time_to_wait = 3
-                extn_name = "foobar-1.0.0"
-                num_summarization_values = 7
+        max_num_polls = 30
+        time_to_wait = 3
+        extn_name = "foobar-1.0.0"
+        num_summarization_values = 7
 
-                cgs = make_new_cgroup(extn_name)
-                self.assertEqual(len(cgs), 2)
+        cgs = make_new_cgroup(extn_name)
+        self.assertEqual(len(cgs), 2)
 
-                ext_handler_properties = ExtHandlerProperties()
-                ext_handler_properties.version = "1.0.0"
-                self.ext_handler = ExtHandler(name='foobar')
-                self.ext_handler.properties = ext_handler_properties
-                self.ext_handler_instance = ExtHandlerInstance(ext_handler=self.ext_handler, protocol=None)
+        ext_handler_properties = ExtHandlerProperties()
+        ext_handler_properties.version = "1.0.0"
+        self.ext_handler = ExtHandler(name='foobar')
+        self.ext_handler.properties = ext_handler_properties
+        self.ext_handler_instance = ExtHandlerInstance(ext_handler=self.ext_handler, protocol=None)
 
-                command = self.create_script("keep_cpu_busy_and_consume_memory_for_5_seconds", '''
+        command = self.create_script("keep_cpu_busy_and_consume_memory_for_5_seconds", '''
 nohup python -c "import time
 
 for i in range(5):
@@ -610,59 +647,48 @@ for i in range(5):
     print('Test loop')" &
 '''.format(time_to_wait))
 
-                self.log_dir = os.path.join(self.tmp_dir, "log")
-
-                with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_base_dir", lambda *_: self.tmp_dir) as \
-                        patch_get_base_dir:
-                    with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_log_dir", lambda *_: self.log_dir) as \
-                            patch_get_log_dir:
-                        self.ext_handler_instance.launch_command(command)
-
-                #
-                # If the test is made to run using the systemd API, then the paths of the cgroups need to be checked differently:
-                #
-                #     self.assertEquals(len(CGroupsTelemetry._tracked), 2)
-                #     cpu = os.path.join(BASE_CGROUPS, "cpu", "system.slice", r"foobar_1.0.0_.*\.scope")
-                #     self.assertTrue(any(re.match(cpu, tracked.path) for tracked in CGroupsTelemetry._tracked))
-                #     memory = os.path.join(BASE_CGROUPS, "memory", "system.slice", r"foobar_1.0.0_.*\.scope")
-                #     self.assertTrue(any(re.match(memory, tracked.path) for tracked in CGroupsTelemetry._tracked))
-                #
-                self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
-                    BASE_CGROUPS, "cpu", "walinuxagent.extensions", "foobar_1.0.0")))
-                self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
-                    BASE_CGROUPS, "memory", "walinuxagent.extensions", "foobar_1.0.0")))
-
-                for i in range(max_num_polls):
-                    CGroupsTelemetry.poll_all_tracked()
-                    time.sleep(0.5)
+        self.log_dir = os.path.join(self.tmp_dir, "log")
 
-                collected_metrics = CGroupsTelemetry.report_all_tracked()
+        with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_base_dir", lambda *_: self.tmp_dir) as \
+                patch_get_base_dir:
+            with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_log_dir", lambda *_: self.log_dir) as \
+                    patch_get_log_dir:
+                self.ext_handler_instance.launch_command(command)
+
+        self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
+            BASE_CGROUPS, "cpu", "walinuxagent.extensions", "foobar_1.0.0")))
+        self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
+            BASE_CGROUPS, "memory", "walinuxagent.extensions", "foobar_1.0.0")))
+
+        for i in range(max_num_polls):
+            CGroupsTelemetry.poll_all_tracked()
+            time.sleep(0.5)
+
+        collected_metrics = CGroupsTelemetry.report_all_tracked()
 
-                self.assertIn("memory", collected_metrics[extn_name])
-                self.assertIn("cur_mem", collected_metrics[extn_name]["memory"])
-                self.assertIn("max_mem", collected_metrics[extn_name]["memory"])
-                self.assertEqual(len(collected_metrics[extn_name]["memory"]["cur_mem"]), num_summarization_values)
-                self.assertEqual(len(collected_metrics[extn_name]["memory"]["max_mem"]), num_summarization_values)
-
-                self.assertIsInstance(collected_metrics[extn_name]["memory"]["cur_mem"][5], str)
-                self.assertIsInstance(collected_metrics[extn_name]["memory"]["cur_mem"][6], str)
-                self.assertIsInstance(collected_metrics[extn_name]["memory"]["max_mem"][5], str)
-                self.assertIsInstance(collected_metrics[extn_name]["memory"]["max_mem"][6], str)
-
-                self.assertIn("cpu", collected_metrics[extn_name])
-                self.assertIn("cur_cpu", collected_metrics[extn_name]["cpu"])
-                self.assertEqual(len(collected_metrics[extn_name]["cpu"]["cur_cpu"]), num_summarization_values)
-
-                self.assertIsInstance(collected_metrics[extn_name]["cpu"]["cur_cpu"][5], str)
-                self.assertIsInstance(collected_metrics[extn_name]["cpu"]["cur_cpu"][6], str)
-
-                for i in range(5):
-                    self.assertGreater(collected_metrics[extn_name]["memory"]["cur_mem"][i], 0)
-                    self.assertGreater(collected_metrics[extn_name]["memory"]["max_mem"][i], 0)
-                    self.assertGreaterEqual(collected_metrics[extn_name]["cpu"]["cur_cpu"][i], 0)
-                    # Equal because CPU could be zero for minimum value.
-            finally:
-                CGroupConfigurator._instance = cgroup_configurator_instance
+        self.assertIn("memory", collected_metrics[extn_name])
+        self.assertIn("cur_mem", collected_metrics[extn_name]["memory"])
+        self.assertIn("max_mem", collected_metrics[extn_name]["memory"])
+        self.assertEqual(len(collected_metrics[extn_name]["memory"]["cur_mem"]), num_summarization_values)
+        self.assertEqual(len(collected_metrics[extn_name]["memory"]["max_mem"]), num_summarization_values)
+
+        self.assertIsInstance(collected_metrics[extn_name]["memory"]["cur_mem"][5], str)
+        self.assertIsInstance(collected_metrics[extn_name]["memory"]["cur_mem"][6], str)
+        self.assertIsInstance(collected_metrics[extn_name]["memory"]["max_mem"][5], str)
+        self.assertIsInstance(collected_metrics[extn_name]["memory"]["max_mem"][6], str)
+
+        self.assertIn("cpu", collected_metrics[extn_name])
+        self.assertIn("cur_cpu", collected_metrics[extn_name]["cpu"])
+        self.assertEqual(len(collected_metrics[extn_name]["cpu"]["cur_cpu"]), num_summarization_values)
+
+        self.assertIsInstance(collected_metrics[extn_name]["cpu"]["cur_cpu"][5], str)
+        self.assertIsInstance(collected_metrics[extn_name]["cpu"]["cur_cpu"][6], str)
+
+        for i in range(5):
+            self.assertGreater(collected_metrics[extn_name]["memory"]["cur_mem"][i], 0)
+            self.assertGreater(collected_metrics[extn_name]["memory"]["max_mem"][i], 0)
+            self.assertGreaterEqual(collected_metrics[extn_name]["cpu"]["cur_cpu"][i], 0)
+            # Equal because CPU could be zero for minimum value.
 
 
 class TestMetric(AgentTestCase):
diff --git a/tests/common/test_conf.py b/tests/common/test_conf.py
index b4805d34..725f7e57 100644
--- a/tests/common/test_conf.py
+++ b/tests/common/test_conf.py
@@ -15,12 +15,12 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
-import mock
 import os.path
 
 from azurelinuxagent.common.conf import *
+import azurelinuxagent.common.conf as conf
 
-from tests.tools import *
+from tests.tools import AgentTestCase, data_dir, patch
 
 
 class TestConf(AgentTestCase):
diff --git a/tests/common/test_errorstate.py b/tests/common/test_errorstate.py
index a0a7761d..d578bdd9 100644
--- a/tests/common/test_errorstate.py
+++ b/tests/common/test_errorstate.py
@@ -1,7 +1,7 @@
-from datetime import timedelta
+import unittest
 
 from azurelinuxagent.common.errorstate import *
-from tests.tools import *
+from tests.tools import Mock, patch
 
 
 class TestErrorState(unittest.TestCase):
diff --git a/tests/common/test_event.py b/tests/common/test_event.py
index 4c676eee..8f71f1c1 100644
--- a/tests/common/test_event.py
+++ b/tests/common/test_event.py
@@ -22,19 +22,17 @@ import os
 import threading
 from datetime import datetime, timedelta
 
-from mock import patch, Mock
-
 from azurelinuxagent.common import event, logger
-from azurelinuxagent.common.event import add_event, \
-    WALAEventOperation, elapsed_milliseconds
+from azurelinuxagent.common.event import add_event, elapsed_milliseconds, EventLogger, report_metric, WALAEventOperation
 from azurelinuxagent.common.exception import EventError
-from azurelinuxagent.common.future import ustr
+from azurelinuxagent.common.future import OrderedDict, ustr
 from azurelinuxagent.common.protocol.wire import GoalState
+from azurelinuxagent.common.telemetryevent import TelemetryEventParam
 from azurelinuxagent.common.utils import fileutil
 from azurelinuxagent.common.utils.extensionprocessutil import read_output
-from azurelinuxagent.common.version import CURRENT_VERSION, CURRENT_AGENT
+from azurelinuxagent.common.version import CURRENT_AGENT, CURRENT_VERSION
 from azurelinuxagent.ga.monitor import MonitorHandler
-from tests.tools import AgentTestCase, load_data, data_dir
+from tests.tools import AgentTestCase, data_dir, load_data, Mock, patch
 
 
 class TestEvent(AgentTestCase):
@@ -439,19 +437,201 @@ class TestEvent(AgentTestCase):
         utc_start = datetime.utcnow() + timedelta(days=1)
         self.assertEqual(0, elapsed_milliseconds(utc_start))
 
+    def _assert_default_params_get_correctly_added(self, param_list_actual, parameters_expected):
+        default_parameters_expected_names = set(parameters_expected.keys())
+
+        # Converting list of TelemetryEventParam into a dictionary, for easier look up of values.
+        param_list_dict = OrderedDict([(param.name, param.value) for param in param_list_actual])
+
+        counter = 0
+        for p in default_parameters_expected_names:
+            self.assertIn(p, param_list_dict)
+            self.assertEqual(param_list_dict[p], parameters_expected[p])
+            counter += 1
+
+        self.assertEqual(len(default_parameters_expected_names), counter)
+
+    @patch("azurelinuxagent.common.event.get_container_id_from_env", return_value="TEST_CONTAINER_ID")
+    def test_add_default_parameters_to_extension_event(self, *args):
+        default_parameters_expected = {"GAVersion": CURRENT_AGENT, 'ContainerId': "TEST_CONTAINER_ID", 'OpcodeName': "",
+                                       'EventTid': 0, 'EventPid': 0, "TaskName": "", "KeywordName": ""}
+
+        # When no values are populated in the TelemetryEventParamList.
+        extension_param_list_empty = EventLogger.add_default_parameters_to_event([], set_values_for_agent=False)
+        self._assert_default_params_get_correctly_added(extension_param_list_empty, default_parameters_expected)
+
+        # When some values are already populated in the TelemetryEventParamList.
+        extension_param_list_populated = [TelemetryEventParam('Name', "DummyExtension"),
+                                          TelemetryEventParam('Version', CURRENT_VERSION),
+                                          TelemetryEventParam('Operation', "DummyOperation"),
+                                          TelemetryEventParam('OperationSuccess', True),
+                                          TelemetryEventParam('Message', "TestMessage"),
+                                          TelemetryEventParam('Duration', 10), TelemetryEventParam('ExtensionType', ''),
+                                          TelemetryEventParam('OpcodeName', '')]
+        extension_param_list_with_defaults = EventLogger.add_default_parameters_to_event(extension_param_list_populated,
+                                                                                         set_values_for_agent=False)
+        self._assert_default_params_get_correctly_added(extension_param_list_with_defaults, default_parameters_expected)
+
+        parameters_expected = {"GAVersion": CURRENT_AGENT, 'ContainerId': "TEST_CONTAINER_ID", 'OpcodeName': "",
+                               'EventTid': 100, 'EventPid': 10, "TaskName": "", "KeywordName": ""}
+
+        # When some values are already populated in the TelemetryEventParamList.
+        extension_param_list_populated = [TelemetryEventParam('Name', "DummyExtension"),
+                                          TelemetryEventParam('Version', CURRENT_VERSION),
+                                          TelemetryEventParam('Operation', "DummyOperation"),
+                                          TelemetryEventParam('OperationSuccess', True),
+                                          TelemetryEventParam('Message', "TestMessage"),
+                                          TelemetryEventParam('Duration', 10),
+                                          TelemetryEventParam('ExtensionType', ''),
+                                          TelemetryEventParam('OpcodeName', ''),
+                                          TelemetryEventParam('EventTid', 100),
+                                          TelemetryEventParam('EventPid', 10)]
+        extension_param_list_with_defaults = EventLogger.add_default_parameters_to_event(extension_param_list_populated,
+                                                                                         set_values_for_agent=False)
+        self._assert_default_params_get_correctly_added(extension_param_list_with_defaults,
+                                                        parameters_expected)
+
+    @patch("threading.Thread.getName", return_value="HelloWorldTask")
+    @patch('os.getpid', return_value=42)
+    @patch("azurelinuxagent.common.event.get_container_id_from_env", return_value="TEST_CONTAINER_ID")
+    @patch("azurelinuxagent.common.event.datetime")
+    def test_add_default_parameters_to_agent_event(self, patch_datetime, *args):
+        patch_datetime.utcnow = Mock(return_value=datetime.strptime("2019-01-01 01:30:00",
+                                                                    '%Y-%m-%d %H:%M:%S'))
+        default_parameters_expected = {"GAVersion": CURRENT_AGENT,
+                                       'ContainerId': "TEST_CONTAINER_ID",
+                                       'OpcodeName': "2019-01-01 01:30:00",
+                                       'EventTid': threading.current_thread().ident,
+                                       'EventPid': 42,
+                                       "TaskName": "HelloWorldTask",
+                                       "KeywordName": ""}
+        agent_param_list_empty = EventLogger.add_default_parameters_to_event([], set_values_for_agent=True)
+        self._assert_default_params_get_correctly_added(agent_param_list_empty, default_parameters_expected)
+
+        # When some values are already populated in the TelemetryEventParamList.
+        agent_param_list_populated = [TelemetryEventParam('Name', "DummyExtension"),
+                                      TelemetryEventParam('Version', CURRENT_VERSION),
+                                      TelemetryEventParam('Operation', "DummyOperation"),
+                                      TelemetryEventParam('OperationSuccess', True),
+                                      TelemetryEventParam('Message', "TestMessage"),
+                                      TelemetryEventParam('Duration', 10), TelemetryEventParam('ExtensionType', ''),
+                                      TelemetryEventParam('OpcodeName', '')]
+        agent_param_list_after_defaults_added = EventLogger.add_default_parameters_to_event(agent_param_list_populated,
+                                                                                            set_values_for_agent=True)
+        self._assert_default_params_get_correctly_added(agent_param_list_after_defaults_added,
+                                                        default_parameters_expected)
+
+        # When some values are already populated in the TelemetryEventParamList, along with some
+        # default values already populated and it should be replaced, when set_values_for_agent=True
+        agent_param_list_populated = [TelemetryEventParam('Name', "DummyExtension"),
+                                      TelemetryEventParam('Version', CURRENT_VERSION),
+                                      TelemetryEventParam('Operation', "DummyOperation"),
+                                      TelemetryEventParam('OperationSuccess', True),
+                                      TelemetryEventParam('Message', "TestMessage"),
+                                      TelemetryEventParam('Duration', 10), TelemetryEventParam('ExtensionType', ''),
+                                      TelemetryEventParam('OpcodeName', 'timestamp'),
+                                      TelemetryEventParam('ContainerId', 'SOME-CONTAINER'),
+                                      TelemetryEventParam('EventTid', 10101010), TelemetryEventParam('EventPid', 110),
+                                      TelemetryEventParam('TaskName', 'Test-TaskName')]
+
+        agent_param_list_after_defaults_added = EventLogger.add_default_parameters_to_event(agent_param_list_populated,
+                                                                                            set_values_for_agent=True)
+        self._assert_default_params_get_correctly_added(agent_param_list_after_defaults_added,
+                                                        default_parameters_expected)
+
+
+class TestMetrics(AgentTestCase):
     @patch('azurelinuxagent.common.event.EventLogger.save_event')
     def test_report_metric(self, mock_event):
         event.report_metric("cpu", "%idle", "_total", 10.0)
         self.assertEqual(1, mock_event.call_count)
         event_json = mock_event.call_args[0][0]
-        self.assertIn("69B669B9-4AF8-4C50-BDC4-6006FA76E975", event_json)
+        self.assertIn(event.TELEMETRY_EVENT_PROVIDER_ID, event_json)
         self.assertIn("%idle", event_json)
         import json
         event_dictionary = json.loads(event_json)
-        self.assertEqual(event_dictionary['providerId'], "69B669B9-4AF8-4C50-BDC4-6006FA76E975")
+        self.assertEqual(event_dictionary['providerId'], event.TELEMETRY_EVENT_PROVIDER_ID)
         for parameter in event_dictionary["parameters"]:
             if parameter['name'] == 'Counter':
                 self.assertEqual(parameter['value'], '%idle')
                 break
         else:
             self.fail("Counter '%idle' not found in event parameters: {0}".format(repr(event_dictionary)))
+
+    def test_save_metric(self):
+        category_present, counter_present, instance_present, value_present = False, False, False, False
+        report_metric("DummyCategory", "DummyCounter", "DummyInstance", 100)
+        self.assertTrue(len(os.listdir(self.tmp_dir)) == 1)
+
+        # checking the extension of the file created.
+        for filename in os.listdir(self.tmp_dir):
+            self.assertEqual(".tld", filename[-4:])
+            perf_metric_event = json.loads(fileutil.read_file(os.path.join(self.tmp_dir, filename)))
+            self.assertEqual(perf_metric_event["eventId"], event.TELEMETRY_METRICS_EVENT_ID)
+            self.assertEqual(perf_metric_event["providerId"], event.TELEMETRY_EVENT_PROVIDER_ID)
+            for i in perf_metric_event["parameters"]:
+                self.assertIn(i["name"], ["Category", "Counter", "Instance", "Value", "GAVersion", "ContainerId",
+                                          "OpcodeName", "EventTid", "EventPid", "TaskName", "KeywordName"])
+                if i["name"] == "Category":
+                    self.assertEqual(i["value"], "DummyCategory")
+                    category_present = True
+                if i["name"] == "Counter":
+                    self.assertEqual(i["value"], "DummyCounter")
+                    counter_present = True
+                if i["name"] == "Instance":
+                    self.assertEqual(i["value"], "DummyInstance")
+                    instance_present = True
+                if i["name"] == "Value":
+                    self.assertEqual(i["value"], 100)
+                    value_present = True
+            
+            self.assertTrue(category_present and counter_present and instance_present and value_present)
+
+    def test_cleanup_message(self):
+        ev_logger = event.EventLogger()
+
+        self.assertEqual(None, ev_logger._clean_up_message(None))
+        self.assertEqual("", ev_logger._clean_up_message(""))
+        self.assertEqual("Daemon Activate resource disk failure", ev_logger._clean_up_message(
+            "Daemon Activate resource disk failure"))
+        self.assertEqual("[M.A.E.CS-2.0.7] Target handler state", ev_logger._clean_up_message(
+            '2019/10/07 21:54:16.629444 INFO [M.A.E.CS-2.0.7] Target handler state'))
+        self.assertEqual("[M.A.E.CS-2.0.7] Initializing extension M.A.E.CS-2.0.7", ev_logger._clean_up_message(
+            '2019/10/07 21:54:17.284385 INFO [M.A.E.CS-2.0.7] Initializing extension M.A.E.CS-2.0.7'))
+        self.assertEqual("ExtHandler ProcessGoalState completed [incarnation 4; 4197 ms]", ev_logger._clean_up_message(
+            "2019/10/07 21:55:38.474861 INFO ExtHandler ProcessGoalState completed [incarnation 4; 4197 ms]"))
+        self.assertEqual("Daemon Azure Linux Agent Version:2.2.43", ev_logger._clean_up_message(
+            "2019/10/07 21:52:28.615720 INFO Daemon Azure Linux Agent Version:2.2.43"))
+        self.assertEqual('Daemon Cgroup controller "memory" is not mounted. Failed to create a cgroup for the VM Agent;'
+                         ' resource usage will not be tracked',
+                         ev_logger._clean_up_message('Daemon Cgroup controller "memory" is not mounted. Failed to '
+                                                     'create a cgroup for the VM Agent; resource usage will not be '
+                                                     'tracked'))
+        self.assertEqual('ExtHandler Root directory /sys/fs/cgroup/memory/walinuxagent.extensions does not exist.',
+                         ev_logger._clean_up_message("2019/10/08 23:45:05.691037 WARNING ExtHandler Root directory "
+                                                     "/sys/fs/cgroup/memory/walinuxagent.extensions does not exist."))
+        self.assertEqual("LinuxAzureDiagnostic started to handle.",
+                         ev_logger._clean_up_message("2019/10/07 22:02:40 LinuxAzureDiagnostic started to handle."))
+        self.assertEqual("VMAccess started to handle.",
+                         ev_logger._clean_up_message("2019/10/07 21:56:58 VMAccess started to handle."))
+        self.assertEqual(
+            '[PERIODIC] ExtHandler Root directory /sys/fs/cgroup/memory/walinuxagent.extensions does not exist.',
+            ev_logger._clean_up_message("2019/10/08 23:45:05.691037 WARNING [PERIODIC] ExtHandler Root directory "
+                                        "/sys/fs/cgroup/memory/walinuxagent.extensions does not exist."))
+        self.assertEqual("[PERIODIC] LinuxAzureDiagnostic started to handle.", ev_logger._clean_up_message(
+            "2019/10/07 22:02:40 [PERIODIC] LinuxAzureDiagnostic started to handle."))
+        self.assertEqual("[PERIODIC] VMAccess started to handle.",
+                         ev_logger._clean_up_message("2019/10/07 21:56:58 [PERIODIC] VMAccess started to handle."))
+        self.assertEqual('[PERIODIC] Daemon Cgroup controller "memory" is not mounted. Failed to create a cgroup for '
+                         'the VM Agent; resource usage will not be tracked',
+                         ev_logger._clean_up_message('[PERIODIC] Daemon Cgroup controller "memory" is not mounted. '
+                                                     'Failed to create a cgroup for the VM Agent; resource usage will '
+                                                     'not be tracked'))
+        self.assertEquals('The time should be in UTC', ev_logger._clean_up_message(
+            '2019-11-26T18:15:06.866746Z INFO The time should be in UTC'))
+        self.assertEquals('The time should be in UTC', ev_logger._clean_up_message(
+            '2019-11-26T18:15:06.866746Z The time should be in UTC'))
+        self.assertEquals('[PERIODIC] The time should be in UTC', ev_logger._clean_up_message(
+            '2019-11-26T18:15:06.866746Z INFO [PERIODIC] The time should be in UTC'))
+        self.assertEquals('[PERIODIC] The time should be in UTC', ev_logger._clean_up_message(
+            '2019-11-26T18:15:06.866746Z [PERIODIC] The time should be in UTC'))
diff --git a/tests/common/test_logger.py b/tests/common/test_logger.py
index 2f745f99..3d0fdffb 100644
--- a/tests/common/test_logger.py
+++ b/tests/common/test_logger.py
@@ -16,13 +16,15 @@
 #
 
 import json
-from datetime import datetime
+import os
+import tempfile
+from datetime import datetime, timedelta
 
-from mock import patch, MagicMock
-
-from azurelinuxagent.common import logger
-from azurelinuxagent.common.event import add_log_event
-from tests.tools import AgentTestCase
+from azurelinuxagent.common.event import __event_logger__, add_log_event, MAX_NUMBER_OF_EVENTS, TELEMETRY_LOG_EVENT_ID,\
+    TELEMETRY_LOG_PROVIDER_ID
+import azurelinuxagent.common.logger as logger
+from azurelinuxagent.common.utils import fileutil
+from tests.tools import AgentTestCase, MagicMock, patch
 
 _MSG_INFO = "This is our test info logging message {0} {1}"
 _MSG_WARN = "This is our test warn logging message {0} {1}"
@@ -34,11 +36,20 @@ _DATA = ["arg1", "arg2"]
 class TestLogger(AgentTestCase):
     def setUp(self):
         AgentTestCase.setUp(self)
+
+        self.lib_dir = tempfile.mkdtemp()
+        self.event_dir = os.path.join(self.lib_dir, "events")
+        fileutil.mkdir(self.event_dir)
+
+        self.log_file = tempfile.mkstemp(prefix="logfile-")[1]
+
         logger.reset_periodic()
 
     def tearDown(self):
         AgentTestCase.tearDown(self)
         logger.reset_periodic()
+        logger.DEFAULT_LOGGER.appenders *= 0
+        fileutil.rm_dirs(self.event_dir)
 
     @patch('azurelinuxagent.common.logger.Logger.verbose')
     @patch('azurelinuxagent.common.logger.Logger.warn')
@@ -160,37 +171,397 @@ class TestLogger(AgentTestCase):
         logger.periodic_verbose(logger.EVERY_DAY, _MSG_VERBOSE, *_DATA)
         mock_verbose.assert_called_once_with(_MSG_VERBOSE, *_DATA)
 
+    def test_logger_should_log_in_utc(self):
+        file_name = "test.log"
+        file_path = os.path.join(self.tmp_dir, file_name)
+        test_logger = logger.Logger()
+        test_logger.add_appender(logger.AppenderType.FILE, logger.LogLevel.INFO, path=file_path)
+
+        before_write_utc = datetime.utcnow()
+        test_logger.info("The time should be in UTC")
+
+        with open(file_path, "r") as log_file:
+            log = log_file.read()
+            try:
+                time_in_file = datetime.strptime(log.split(logger.LogLevel.STRINGS[logger.LogLevel.INFO])[0].strip()
+                                                 , u'%Y-%m-%dT%H:%M:%S.%fZ')
+            except ValueError:
+                self.fail("Ensure timestamp follows ISO-8601 format + 'Z' for UTC")
+
+            # If the time difference is > 5secs, there's a high probability that the time_in_file is in different TZ
+            self.assertTrue((time_in_file-before_write_utc) <= timedelta(seconds=5))
+
     def test_telemetry_logger(self):
         mock = MagicMock()
         appender = logger.TelemetryAppender(logger.LogLevel.WARNING, mock)
-        appender.write(logger.LogLevel.WARNING, "--unit-test--")
 
-        mock.assert_called_once_with(logger.LogLevel.WARNING, "--unit-test--")
+        appender.write(logger.LogLevel.WARNING, "--unit-test-WARNING--")
+        mock.assert_called_with(logger.LogLevel.WARNING, "--unit-test-WARNING--")
+        mock.reset_mock()
 
+        appender.write(logger.LogLevel.ERROR, "--unit-test-ERROR--")
+        mock.assert_called_with(logger.LogLevel.ERROR, "--unit-test-ERROR--")
+        mock.reset_mock()
+
+        appender.write(logger.LogLevel.INFO, "--unit-test-INFO--")
+        mock.assert_not_called()
+        mock.reset_mock()
+
+        for i in range(5):
+            appender.write(logger.LogLevel.ERROR, "--unit-test-ERROR--")
+            appender.write(logger.LogLevel.INFO, "--unit-test-INFO--")
+
+        self.assertEqual(5, mock.call_count)  # Only ERROR should be called.
+
+    @patch("azurelinuxagent.common.event.send_logs_to_telemetry", return_value=True)
     @patch('azurelinuxagent.common.event.EventLogger.save_event')
-    def test_telemetry_logger1(self, mock_save):
+    def test_telemetry_logger_sending_correct_fields(self, mock_save, patch_conf_get_logs_to_telemetry):
         appender = logger.TelemetryAppender(logger.LogLevel.WARNING, add_log_event)
-        appender.write(logger.LogLevel.WARNING, "--unit-test--")
+        appender.write(logger.LogLevel.WARNING, 'Cgroup controller "memory" is not mounted. '
+                                                'Failed to create a cgroup for extension '
+                                                'Microsoft.OSTCExtensions.DummyExtension-1.2.3.4')
 
         self.assertEqual(1, mock_save.call_count)
         telemetry_json = json.loads(mock_save.call_args[0][0])
 
-        self.assertEqual('FFF0196F-EE4C-4EAF-9AA5-776F622DEB4F', telemetry_json['providerId'])
-        self.assertEqual(7, telemetry_json['eventId'])
+        self.assertEqual(TELEMETRY_LOG_PROVIDER_ID, telemetry_json['providerId'])
+        self.assertEqual(TELEMETRY_LOG_EVENT_ID, telemetry_json['eventId'])
 
         self.assertEqual(12, len(telemetry_json['parameters']))
         for x in telemetry_json['parameters']:
             if x['name'] == 'EventName':
                 self.assertEqual(x['value'], 'Log')
-
             elif x['name'] == 'CapabilityUsed':
                 self.assertEqual(x['value'], 'WARNING')
-
             elif x['name'] == 'Context1':
-                self.assertEqual(x['value'], '--unit-test--')
-
+                self.assertEqual(x['value'], 'Cgroup controller "memory" is not mounted. '
+                                             'Failed to create a cgroup for extension '
+                                             'Microsoft.OSTCExtensions.DummyExtension-1.2.3.4')
             elif x['name'] == 'Context2':
                 self.assertEqual(x['value'], '')
-
             elif x['name'] == 'Context3':
                 self.assertEqual(x['value'], '')
+
+    @patch('azurelinuxagent.common.event.EventLogger.save_event')
+    def test_telemetry_logger_not_on_by_default(self, mock_save):
+        appender = logger.TelemetryAppender(logger.LogLevel.WARNING, add_log_event)
+        appender.write(logger.LogLevel.WARNING, 'Cgroup controller "memory" is not mounted. '
+                                                'Failed to create a cgroup for extension '
+                                                'Microsoft.OSTCExtensions.DummyExtension-1.2.3.4')
+        self.assertEqual(0, mock_save.call_count)
+
+    @patch("azurelinuxagent.common.logger.StdoutAppender.write")
+    @patch("azurelinuxagent.common.logger.TelemetryAppender.write")
+    @patch("azurelinuxagent.common.logger.ConsoleAppender.write")
+    @patch("azurelinuxagent.common.logger.FileAppender.write")
+    def test_add_appender(self, mock_file_write, mock_console_write, mock_telem_write, mock_stdout_write):
+        lg = logger.Logger(logger.DEFAULT_LOGGER, "TestLogger1")
+
+        lg.add_appender(logger.AppenderType.FILE, logger.LogLevel.INFO, path=self.log_file)
+        lg.add_appender(logger.AppenderType.TELEMETRY, logger.LogLevel.WARNING, path=add_log_event)
+        lg.add_appender(logger.AppenderType.CONSOLE, logger.LogLevel.WARNING, path="/dev/null")
+        lg.add_appender(logger.AppenderType.STDOUT, logger.LogLevel.WARNING, path=None)
+
+        counter = 0
+        for appender in lg.appenders:
+            if isinstance(appender, logger.FileAppender):
+                counter += 1
+            elif isinstance(appender, logger.TelemetryAppender):
+                counter += 1
+            elif isinstance(appender, logger.ConsoleAppender):
+                counter += 1
+            elif isinstance(appender, logger.StdoutAppender):
+                counter += 1
+
+        # All 4 appenders should have been included.
+        self.assertEqual(4, counter)
+
+        # The write for all the loggers will get called, but the levels are honored in the individual write method
+        # itself. Each appender has its own test to validate the writing of the log message for different levels.
+        # For Reference: tests.common.test_logger.TestAppender
+
+        lg.warn("Test Log")
+        self.assertEqual(1, mock_file_write.call_count)
+        self.assertEqual(1, mock_console_write.call_count)
+        self.assertEqual(1, mock_telem_write.call_count)
+        self.assertEqual(1, mock_stdout_write.call_count)
+
+        lg.info("Test Log")
+        self.assertEqual(2, mock_file_write.call_count)
+        self.assertEqual(2, mock_console_write.call_count)
+        self.assertEqual(2, mock_telem_write.call_count)
+        self.assertEqual(2, mock_stdout_write.call_count)
+
+        lg.error("Test Log")
+        self.assertEqual(3, mock_file_write.call_count)
+        self.assertEqual(3, mock_console_write.call_count)
+        self.assertEqual(3, mock_telem_write.call_count)
+        self.assertEqual(3, mock_stdout_write.call_count)
+
+    @patch("azurelinuxagent.common.logger.StdoutAppender.write")
+    @patch("azurelinuxagent.common.logger.TelemetryAppender.write")
+    @patch("azurelinuxagent.common.logger.ConsoleAppender.write")
+    @patch("azurelinuxagent.common.logger.FileAppender.write")
+    def test_set_prefix(self, mock_file_write, mock_console_write, mock_telem_write, mock_stdout_write):
+        lg = logger.Logger(logger.DEFAULT_LOGGER)
+        prefix = "YoloLogger"
+
+        lg.set_prefix(prefix)
+        self.assertEquals(lg.prefix, prefix)
+
+        lg.add_appender(logger.AppenderType.FILE, logger.LogLevel.INFO, path=self.log_file)
+        lg.add_appender(logger.AppenderType.TELEMETRY, logger.LogLevel.WARNING, path=add_log_event)
+        lg.add_appender(logger.AppenderType.CONSOLE, logger.LogLevel.WARNING, path="/dev/null")
+        lg.add_appender(logger.AppenderType.STDOUT, logger.LogLevel.WARNING, path=None)
+
+        lg.error("Test Log")
+
+        self.assertIn(prefix, mock_file_write.call_args[0][1])
+        self.assertIn(prefix, mock_console_write.call_args[0][1])
+        self.assertIn(prefix, mock_telem_write.call_args[0][1])
+        self.assertIn(prefix, mock_stdout_write.call_args[0][1])
+
+    @patch("azurelinuxagent.common.logger.StdoutAppender.write")
+    @patch("azurelinuxagent.common.logger.TelemetryAppender.write")
+    @patch("azurelinuxagent.common.logger.ConsoleAppender.write")
+    @patch("azurelinuxagent.common.logger.FileAppender.write")
+    def test_nested_logger(self, mock_file_write, mock_console_write, mock_telem_write, mock_stdout_write):
+        """
+        The purpose of this test is to see if the logger gets correctly created when passed it another logger and also
+        if the appender correctly gets the messages logged. This is how the ExtHandlerInstance logger works.
+
+        I initialize the default logger(logger), then create a new logger(lg) from it, and then log using logger & lg.
+        See if both logs are flowing through or not.
+        """
+
+        parent_prefix = "ParentLogger"
+        child_prefix = "ChildLogger"
+
+        logger.add_logger_appender(logger.AppenderType.FILE, logger.LogLevel.INFO, path=self.log_file)
+        logger.add_logger_appender(logger.AppenderType.TELEMETRY, logger.LogLevel.WARNING, path=add_log_event)
+        logger.add_logger_appender(logger.AppenderType.CONSOLE, logger.LogLevel.WARNING, path="/dev/null")
+        logger.add_logger_appender(logger.AppenderType.STDOUT, logger.LogLevel.WARNING)
+        logger.set_prefix(parent_prefix)
+
+        lg = logger.Logger(logger.DEFAULT_LOGGER, child_prefix)
+
+        lg.error("Test Log")
+        self.assertEqual(1, mock_file_write.call_count)
+        self.assertEqual(1, mock_console_write.call_count)
+        self.assertEqual(1, mock_telem_write.call_count)
+        self.assertEqual(1, mock_stdout_write.call_count)
+
+        self.assertIn(child_prefix, mock_file_write.call_args[0][1])
+        self.assertIn(child_prefix, mock_console_write.call_args[0][1])
+        self.assertIn(child_prefix, mock_telem_write.call_args[0][1])
+        self.assertIn(child_prefix, mock_stdout_write.call_args[0][1])
+
+        logger.error("Test Log")
+        self.assertEqual(2, mock_file_write.call_count)
+        self.assertEqual(2, mock_console_write.call_count)
+        self.assertEqual(2, mock_telem_write.call_count)
+        self.assertEqual(2, mock_stdout_write.call_count)
+
+        self.assertIn(parent_prefix, mock_file_write.call_args[0][1])
+        self.assertIn(parent_prefix, mock_console_write.call_args[0][1])
+        self.assertIn(parent_prefix, mock_telem_write.call_args[0][1])
+        self.assertIn(parent_prefix, mock_stdout_write.call_args[0][1])
+
+    @patch("azurelinuxagent.common.event.send_logs_to_telemetry", return_value=True)
+    @patch("azurelinuxagent.common.conf.get_lib_dir")
+    def test_telemetry_logger_add_log_event(self, mock_lib_dir, *_):
+        mock_lib_dir.return_value = self.lib_dir
+        __event_logger__.event_dir = self.event_dir
+        prefix = "YoloLogger"
+
+        logger.add_logger_appender(logger.AppenderType.TELEMETRY, logger.LogLevel.WARNING, path=add_log_event)
+        logger.set_prefix(prefix)
+
+        logger.warn('Test Log - Warning')
+
+        event_files = os.listdir(__event_logger__.event_dir)
+        self.assertEqual(1, len(event_files))
+
+        log_file_event = os.path.join(__event_logger__.event_dir, event_files[0])
+        try:
+            with open(log_file_event) as logfile:
+                logcontent = logfile.read()
+                # Checking the contents of the event file.
+                self.assertIn("Test Log - Warning", logcontent)
+        except Exception as e:
+            self.assertFalse(True, "The log file looks like it isn't correctly setup for this test. Take a look. "
+                                   "{0}".format(e))
+
+    @patch("azurelinuxagent.common.logger.StdoutAppender.write")
+    @patch("azurelinuxagent.common.logger.ConsoleAppender.write")
+    @patch("azurelinuxagent.common.event.send_logs_to_telemetry", return_value=True)
+    def test_telemetry_logger_verify_maximum_recursion_depths_doesnt_happen(self, *_):
+        logger.add_logger_appender(logger.AppenderType.FILE, logger.LogLevel.INFO, path="/dev/null")
+        logger.add_logger_appender(logger.AppenderType.TELEMETRY, logger.LogLevel.WARNING, path=add_log_event)
+
+        for i in range(MAX_NUMBER_OF_EVENTS):
+            logger.warn('Test Log - {0} - 1 - Warning'.format(i))
+
+        exception_caught = False
+
+        # #1035 was caused due to too many files being written in an error condition. Adding even one more here broke
+        # the camels back earlier - It would go into an infinite recursion as telemetry would call log, which in turn
+        # would call telemetry, and so on.
+        # The description of the fix is given in the comments @ azurelinuxagent.common.logger.Logger#log.write_log.
+        try:
+            for i in range(10):
+                logger.warn('Test Log - {0} - 2 - Warning'.format(i))
+        except RuntimeError:
+            exception_caught = True
+
+        self.assertFalse(exception_caught, msg="Caught a Runtime Error. This should not have been raised.")
+
+    @patch("azurelinuxagent.common.logger.StdoutAppender.write")
+    @patch("azurelinuxagent.common.logger.ConsoleAppender.write")
+    @patch("azurelinuxagent.common.event.send_logs_to_telemetry", return_value=True)
+    @patch("azurelinuxagent.common.conf.get_lib_dir")
+    def test_telemetry_logger_check_all_file_logs_written_when_events_gt_MAX_NUMBER_OF_EVENTS(self, mock_lib_dir, *_):
+        mock_lib_dir.return_value = self.lib_dir
+        __event_logger__.event_dir = self.event_dir
+        no_of_log_statements = MAX_NUMBER_OF_EVENTS + 100
+        exception_caught = False
+        prefix = "YoloLogger"
+
+        logger.add_logger_appender(logger.AppenderType.FILE, logger.LogLevel.INFO, path=self.log_file)
+        logger.add_logger_appender(logger.AppenderType.TELEMETRY, logger.LogLevel.WARNING, path=add_log_event)
+        logger.set_prefix(prefix)
+
+        # Calling logger.warn no_of_log_statements times would cause the telemetry appender to writing
+        # 1000 events into the events dir, and then drop the remaining events. It should not generate the RuntimeError
+        try:
+            for i in range(0, no_of_log_statements):
+                logger.warn('Test Log - {0} - 1 - Warning'.format(i))
+        except RuntimeError:
+            exception_caught = True
+
+        self.assertFalse(exception_caught, msg="Caught a Runtime Error. This should not have been raised.")
+        self.assertEqual(MAX_NUMBER_OF_EVENTS, len(os.listdir(__event_logger__.event_dir)))
+
+        try:
+            with open(self.log_file) as logfile:
+                logcontent = logfile.readlines()
+
+                # Checking the last log entry.
+                # Subtracting 1 as range is exclusive of the upper bound
+                self.assertIn("WARNING {1} Test Log - {0} - 1 - Warning".format(no_of_log_statements - 1, prefix),
+                              logcontent[-1])
+
+                # Checking the 1001st log entry. We know that 1001st entry would generate a PERIODIC message of too many
+                # events, which should be captured in the log file as well.
+                self.assertRegex(logcontent[1001], r"(.*WARNING\s*{0}\s*\[PERIODIC\]\s*Too many files under:.*{1}, "
+                                                   r"current count\:\s*\d+,\s*removing oldest\s*.*)".format(prefix,
+                                                                                                            self.event_dir))
+        except Exception as e:
+            self.assertFalse(True, "The log file looks like it isn't correctly setup for this test. "
+                                   "Take a look. {0}".format(e))
+
+
+class TestAppender(AgentTestCase):
+    def setUp(self):
+        AgentTestCase.setUp(self)
+
+        self.lib_dir = tempfile.mkdtemp()
+        self.event_dir = os.path.join(self.lib_dir, "events")
+        fileutil.mkdir(self.event_dir)
+
+        self.log_file = tempfile.mkstemp(prefix="logfile-")[1]
+
+        logger.reset_periodic()
+
+    def tearDown(self):
+        AgentTestCase.tearDown(self)
+        logger.reset_periodic()
+        fileutil.rm_dirs(self.event_dir)
+        logger.DEFAULT_LOGGER.appenders *= 0
+
+    @patch("azurelinuxagent.common.event.send_logs_to_telemetry", return_value=True)
+    @patch("azurelinuxagent.common.logger.sys.stdout.write")
+    @patch("azurelinuxagent.common.event.EventLogger.add_log_event")
+    def test_no_appenders_added(self, mock_add_log_event, mock_sys_stdout, *_):
+        # Validating no logs are written in any appender
+
+        logger.verbose("test-verbose")
+        logger.info("test-info")
+        logger.warn("test-warn")
+        logger.error("test-error")
+
+        # Validating Console and File logs
+        with open(self.log_file) as logfile:
+            logcontent = logfile.readlines()
+            self.assertEqual(0, len(logcontent))
+
+        # Validating telemetry call
+        self.assertEqual(0, mock_add_log_event.call_count)
+        # Validating stdout call
+        self.assertEqual(0, mock_sys_stdout.call_count)
+
+    def test_console_appender(self):
+        logger.add_logger_appender(logger.AppenderType.CONSOLE, logger.LogLevel.WARNING, path=self.log_file)
+
+        logger.verbose("test-verbose")
+        with open(self.log_file) as logfile:
+            logcontent = logfile.readlines()
+            # Levels are honored and Verbose should not be written.
+            self.assertEqual(0, len(logcontent))
+
+        logger.info("test-info")
+        with open(self.log_file) as logfile:
+            logcontent = logfile.readlines()
+            # Levels are honored and Info should not be written.
+            self.assertEqual(0, len(logcontent))
+
+        # As console has a mode of w, it'll always only have 1 line only.
+        logger.warn("test-warn")
+        with open(self.log_file) as logfile:
+            logcontent = logfile.readlines()
+            self.assertEqual(1, len(logcontent))
+            self.assertRegex(logcontent[0], r"(.*WARNING\s*test-warn.*)")
+
+        logger.error("test-error")
+        with open(self.log_file) as logfile:
+            logcontent = logfile.readlines()
+            # Levels are honored and Info, Verbose should not be written.
+            self.assertEqual(1, len(logcontent))
+            self.assertRegex(logcontent[0], r"(.*ERROR\s*test-error.*)")
+
+    def test_file_appender(self):
+        logger.add_logger_appender(logger.AppenderType.FILE, logger.LogLevel.INFO, path=self.log_file)
+        logger.verbose("test-verbose")
+        logger.info("test-info")
+        logger.warn("test-warn")
+        logger.error("test-error")
+
+        with open(self.log_file) as logfile:
+            logcontent = logfile.readlines()
+            # Levels are honored and Verbose should not be written.
+            self.assertEqual(3, len(logcontent))
+            self.assertRegex(logcontent[0], r"(.*INFO\s*test-info.*)")
+            self.assertRegex(logcontent[1], r"(.*WARNING\s*test-warn.*)")
+            self.assertRegex(logcontent[2], r"(.*ERROR\s*test-error.*)")
+
+    @patch("azurelinuxagent.common.event.send_logs_to_telemetry", return_value=True)
+    @patch("azurelinuxagent.common.event.EventLogger.add_log_event")
+    def test_telemetry_appender(self, mock_add_log_event, *_):
+        logger.add_logger_appender(logger.AppenderType.TELEMETRY, logger.LogLevel.WARNING, path=add_log_event)
+        logger.verbose("test-verbose")
+        logger.info("test-info")
+        logger.warn("test-warn")
+        logger.error("test-error")
+
+        self.assertEqual(2, mock_add_log_event.call_count)
+
+    @patch("azurelinuxagent.common.logger.sys.stdout.write")
+    def test_stdout_appender(self, mock_sys_stdout):
+        logger.add_logger_appender(logger.AppenderType.STDOUT, logger.LogLevel.ERROR)
+        logger.verbose("test-verbose")
+        logger.info("test-info")
+        logger.warn("test-warn")
+        logger.error("test-error")
+
+        # Validating only test-error gets logged and not others.
+        self.assertEqual(1, mock_sys_stdout.call_count)
diff --git a/tests/common/test_version.py b/tests/common/test_version.py
index 14c16a86..6a5c56cd 100644
--- a/tests/common/test_version.py
+++ b/tests/common/test_version.py
@@ -17,14 +17,15 @@
 
 from __future__ import print_function
 
-import textwrap
-
 import mock
+import os
+import textwrap
 
+import azurelinuxagent.common.conf as conf
 from azurelinuxagent.common.version import set_current_agent, \
     AGENT_LONG_VERSION, AGENT_VERSION, AGENT_NAME, AGENT_NAME_PATTERN, \
     get_f5_platform, get_distro
-from tests.tools import *
+from tests.tools import AgentTestCase, open_patch, patch
 
 
 def freebsd_system():
diff --git a/tests/daemon/test_daemon.py b/tests/daemon/test_daemon.py
index 4e87e5a0..91b68bd3 100644
--- a/tests/daemon/test_daemon.py
+++ b/tests/daemon/test_daemon.py
@@ -14,12 +14,17 @@
 #
 # Requires Python 2.6+ and Openssl 1.0+
 #
+
+import os
+import unittest
+
 from multiprocessing import Process
 
+import azurelinuxagent.common.conf as conf
 from azurelinuxagent.daemon import *
 from azurelinuxagent.daemon.main import OPENSSL_FIPS_ENVIRONMENT
 from azurelinuxagent.pa.provision.default import ProvisionHandler
-from tests.tools import *
+from tests.tools import AgentTestCase, Mock, patch
 
 
 class MockDaemonCall(object):
diff --git a/tests/daemon/test_resourcedisk.py b/tests/daemon/test_resourcedisk.py
index 836d7b1c..ebaa18c9 100644
--- a/tests/daemon/test_resourcedisk.py
+++ b/tests/daemon/test_resourcedisk.py
@@ -15,17 +15,18 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
-from tests.tools import *
-from azurelinuxagent.common.exception import *
-from azurelinuxagent.daemon import *
+import unittest
+
+from tests.tools import AgentTestCase
 from azurelinuxagent.daemon.resourcedisk.default import ResourceDiskHandler
 
+
 class TestResourceDisk(AgentTestCase):
     def test_mount_flags_empty(self):
         partition = '/dev/sdb1'
         mountpoint = '/mnt/resource'
         options = None
-        expected = 'mount /dev/sdb1 /mnt/resource'
+        expected = 'mount -t ext3 /dev/sdb1 /mnt/resource'
         rdh = ResourceDiskHandler()
         mount_string = rdh.get_mount_string(options, partition, mountpoint)
         self.assertEqual(expected, mount_string)
@@ -34,7 +35,7 @@ class TestResourceDisk(AgentTestCase):
         partition = '/dev/sdb1'
         mountpoint = '/mnt/resource'
         options = 'noexec,noguid,nodev'
-        expected = 'mount -o noexec,noguid,nodev /dev/sdb1 /mnt/resource'
+        expected = 'mount -t ext3 -o noexec,noguid,nodev /dev/sdb1 /mnt/resource'
         rdh = ResourceDiskHandler()
         mount_string = rdh.get_mount_string(options, partition, mountpoint)
         self.assertEqual(expected, mount_string)
diff --git a/tests/data/wire/ext_conf.xml b/tests/data/wire/ext_conf.xml
index 508fb982..3bafcef1 100644
--- a/tests/data/wire/ext_conf.xml
+++ b/tests/data/wire/ext_conf.xml
@@ -22,5 +22,5 @@
     <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]}</RuntimeSettings>
   </Plugin>
 </PluginSettings>
-<StatusUploadBlob statusBlobType="BlockBlob">https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions>
+<StatusUploadBlob statusBlobType="BlockBlob">https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo</StatusUploadBlob></Extensions>
 
diff --git a/tests/data/wire/ext_conf_autoupgrade.xml b/tests/data/wire/ext_conf_autoupgrade.xml
index 1d6919e0..67e95c3d 100644
--- a/tests/data/wire/ext_conf_autoupgrade.xml
+++ b/tests/data/wire/ext_conf_autoupgrade.xml
@@ -24,5 +24,5 @@
     <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]}</RuntimeSettings>
   </Plugin>
 </PluginSettings>
-<StatusUploadBlob>https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions>
+<StatusUploadBlob>https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo</StatusUploadBlob></Extensions>
 
diff --git a/tests/data/wire/ext_conf_autoupgrade_internalversion.xml b/tests/data/wire/ext_conf_autoupgrade_internalversion.xml
index 9b61556b..d918482f 100644
--- a/tests/data/wire/ext_conf_autoupgrade_internalversion.xml
+++ b/tests/data/wire/ext_conf_autoupgrade_internalversion.xml
@@ -24,5 +24,5 @@
     <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]}</RuntimeSettings>
   </Plugin>
 </PluginSettings>
-<StatusUploadBlob>https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions>
+<StatusUploadBlob>https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo</StatusUploadBlob></Extensions>
 
diff --git a/tests/data/wire/ext_conf_internalversion.xml b/tests/data/wire/ext_conf_internalversion.xml
index 9b61556b..d918482f 100644
--- a/tests/data/wire/ext_conf_internalversion.xml
+++ b/tests/data/wire/ext_conf_internalversion.xml
@@ -24,5 +24,5 @@
     <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]}</RuntimeSettings>
   </Plugin>
 </PluginSettings>
-<StatusUploadBlob>https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions>
+<StatusUploadBlob>https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo</StatusUploadBlob></Extensions>
 
diff --git a/tests/data/wire/ext_conf_multiple_extensions.xml b/tests/data/wire/ext_conf_multiple_extensions.xml
index 838decb7..c68f35eb 100644
--- a/tests/data/wire/ext_conf_multiple_extensions.xml
+++ b/tests/data/wire/ext_conf_multiple_extensions.xml
@@ -1,5 +1,5 @@
 <Extensions version="1.0.0.0" goalStateIncarnation="9">
-    <GuestAgentExtension xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
+    <GuestAgentExtension>
         <GAFamilies>
             <GAFamily>
                 <Name>Prod</Name>
@@ -70,7 +70,7 @@
         </Plugin>
     </PluginSettings>
     <StatusUploadBlob statusBlobType="BlockBlob">
-        https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D
+        https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo
     </StatusUploadBlob>
 </Extensions>
 
diff --git a/tests/data/wire/ext_conf_no_public.xml b/tests/data/wire/ext_conf_no_public.xml
index abbde800..d96b9f53 100644
--- a/tests/data/wire/ext_conf_no_public.xml
+++ b/tests/data/wire/ext_conf_no_public.xml
@@ -42,5 +42,5 @@
     <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK"}}]}</RuntimeSettings>
   </Plugin>
 </PluginSettings>
-<StatusUploadBlob>https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions>
+<StatusUploadBlob>https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo</StatusUploadBlob></Extensions>
 
diff --git a/tests/data/wire/ext_conf_no_settings.xml b/tests/data/wire/ext_conf_no_settings.xml
index df76d547..16972250 100644
--- a/tests/data/wire/ext_conf_no_settings.xml
+++ b/tests/data/wire/ext_conf_no_settings.xml
@@ -37,5 +37,5 @@
 <Plugins>
   <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.0" location="http://rdfepirv2hknprdstr03.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" config="" state="enabled" autoUpgrade="false" failoverlocation="http://rdfepirv2hknprdstr04.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" runAsStartupTask="false" isJson="true" />
 </Plugins>
-<StatusUploadBlob>https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions>
+<StatusUploadBlob>https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo</StatusUploadBlob></Extensions>
 
diff --git a/tests/data/wire/ext_conf_sequencing.xml b/tests/data/wire/ext_conf_sequencing.xml
index 3120a979..bb215d0d 100644
--- a/tests/data/wire/ext_conf_sequencing.xml
+++ b/tests/data/wire/ext_conf_sequencing.xml
@@ -31,4 +31,4 @@
     <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]}</RuntimeSettings>
   </Plugin>
 </PluginSettings>
-<StatusUploadBlob statusBlobType="BlockBlob">https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions>
+<StatusUploadBlob statusBlobType="BlockBlob">https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo</StatusUploadBlob></Extensions>
diff --git a/tests/data/wire/ext_conf_upgradeguid.xml b/tests/data/wire/ext_conf_upgradeguid.xml
index 1526a939..e4c30daf 100644
--- a/tests/data/wire/ext_conf_upgradeguid.xml
+++ b/tests/data/wire/ext_conf_upgradeguid.xml
@@ -22,5 +22,5 @@
     <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]}</RuntimeSettings>
   </Plugin>
 </PluginSettings>
-<StatusUploadBlob statusBlobType="BlockBlob">https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions>
+<StatusUploadBlob statusBlobType="BlockBlob">https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&amp;sp=rw&amp;se=9999-01-01&amp;sk=key1&amp;sv=2014-02-14&amp;sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo</StatusUploadBlob></Extensions>
 
diff --git a/tests/distro/test_resourceDisk.py b/tests/distro/test_resourceDisk.py
index 5f9db0a3..32358992 100644
--- a/tests/distro/test_resourceDisk.py
+++ b/tests/distro/test_resourceDisk.py
@@ -21,9 +21,10 @@
 import os
 import stat
 import sys
+import unittest
 from azurelinuxagent.common.utils import shellutil
 from azurelinuxagent.daemon.resourcedisk import get_resourcedisk_handler
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
 
 
 class TestResourceDisk(AgentTestCase):
diff --git a/tests/distro/test_scvmm.py b/tests/distro/test_scvmm.py
index fdca1e5d..a0743596 100644
--- a/tests/distro/test_scvmm.py
+++ b/tests/distro/test_scvmm.py
@@ -19,12 +19,14 @@
 # http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx
 
 import mock
-from tests.tools import *
+from tests.tools import AgentTestCase, Mock, patch
+import unittest
 
 import azurelinuxagent.daemon.scvmm as scvmm
 from azurelinuxagent.daemon.main import *
 from azurelinuxagent.common.osutil.default import DefaultOSUtil
 
+
 class TestSCVMM(AgentTestCase):
     def test_scvmm_detection_with_file(self):
         # setup
diff --git a/tests/ga/test_env.py b/tests/ga/test_env.py
index b69303d9..c0dc7cf1 100644
--- a/tests/ga/test_env.py
+++ b/tests/ga/test_env.py
@@ -16,7 +16,7 @@
 #
 from azurelinuxagent.common.osutil.default import DefaultOSUtil, shellutil
 from azurelinuxagent.ga.env import EnvHandler
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
 
 
 class TestEnvHandler(AgentTestCase):
@@ -34,7 +34,6 @@ class TestEnvHandler(AgentTestCase):
         self.mock_get_osutil = patch("azurelinuxagent.common.osutil.factory._get_osutil", return_value=DefaultOSUtil())
         self.mock_get_osutil.start()
 
-
     def tearDown(self):
         self.mock_get_osutil.stop()
         AgentTestCase.tearDown(self)
diff --git a/tests/ga/test_extension.py b/tests/ga/test_extension.py
index 2644d59a..1868f52b 100644
--- a/tests/ga/test_extension.py
+++ b/tests/ga/test_extension.py
@@ -16,13 +16,17 @@
 #
 
 import os.path
+import unittest
 
 from datetime import timedelta
 
 from azurelinuxagent.ga.monitor import get_monitor_handler
 from nose.plugins.attrib import attr
-from tests.protocol.mockwiredata import *
+from tests.protocol import mockwiredata
+from tests.tools import are_cgroups_enabled, AgentTestCase, data_dir, i_am_root, MagicMock, Mock, \
+    skip_if_predicate_false, patch, is_trusty_in_travis, skip_if_predicate_true
 
+from azurelinuxagent.common.exception import ResourceGoneError
 from azurelinuxagent.common.protocol.restapi import Extension, ExtHandlerProperties
 from azurelinuxagent.ga.exthandlers import *
 from azurelinuxagent.common.protocol.wire import WireProtocol, InVMArtifactsProfile
@@ -360,7 +364,7 @@ class TestExtension(ExtensionTestCase):
         :param args: Any additional args passed to the function, needed for creating a mock for handler and protocol
         :return: test_data, exthandlers_handler, protocol
         """
-        test_data = WireProtocolData(DATA_FILE_EXT_SINGLE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SINGLE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Ensure initial install and enable is successful
@@ -381,7 +385,7 @@ class TestExtension(ExtensionTestCase):
         return test_data, exthandlers_handler, protocol
 
     def test_ext_handler(self, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Test enable scenario.
@@ -444,7 +448,7 @@ class TestExtension(ExtensionTestCase):
         self._assert_no_handler_status(protocol.report_vm_status)
 
     def test_ext_zip_file_packages_removed_in_update_case(self, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Test enable scenario.
@@ -483,7 +487,7 @@ class TestExtension(ExtensionTestCase):
                                          extension_version="1.2.0")
 
     def test_ext_zip_file_packages_removed_in_uninstall_case(self, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         extension_version = "1.0.0"
 
@@ -504,7 +508,7 @@ class TestExtension(ExtensionTestCase):
                                          extension_version=extension_version)
 
     def test_ext_zip_file_packages_removed_in_update_and_uninstall_case(self, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Test enable scenario.
@@ -552,21 +556,21 @@ class TestExtension(ExtensionTestCase):
                                          extension_version="1.2.0")
 
     def test_ext_handler_no_settings(self, *args):
-        test_data = WireProtocolData(DATA_FILE_EXT_NO_SETTINGS)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_NO_SETTINGS)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         exthandlers_handler.run()
         self._assert_handler_status(protocol.report_vm_status, "Ready", 0, "1.0.0")
 
     def test_ext_handler_no_public_settings(self, *args):
-        test_data = WireProtocolData(DATA_FILE_EXT_NO_PUBLIC)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_NO_PUBLIC)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         exthandlers_handler.run()
         self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
 
     def test_ext_handler_no_ext(self, *args):
-        test_data = WireProtocolData(DATA_FILE_NO_EXT)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_NO_EXT)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Assert no extension handler status
@@ -574,7 +578,7 @@ class TestExtension(ExtensionTestCase):
         self._assert_no_handler_status(protocol.report_vm_status)
 
     def test_ext_handler_sequencing(self, *args):
-        test_data = WireProtocolData(DATA_FILE_EXT_SEQUENCING)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SEQUENCING)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Test enable scenario.
@@ -647,14 +651,14 @@ class TestExtension(ExtensionTestCase):
         self.assertEqual(exthandlers_handler.ext_handlers.extHandlers[1].properties.extensions[0].dependencyLevel, 5)
 
     def test_ext_handler_sequencing_default_dependency_level(self, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         exthandlers_handler.run()
         self.assertEqual(exthandlers_handler.ext_handlers.extHandlers[0].properties.extensions[0].dependencyLevel, 0)
         self.assertEqual(exthandlers_handler.ext_handlers.extHandlers[0].properties.extensions[0].dependencyLevel, 0)
 
     def test_ext_handler_sequencing_invalid_dependency_level(self, *args):
-        test_data = WireProtocolData(DATA_FILE_EXT_SEQUENCING)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SEQUENCING)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         test_data.goal_state = test_data.goal_state.replace("<Incarnation>1<",
@@ -716,7 +720,7 @@ class TestExtension(ExtensionTestCase):
 
         expected_status_json = json.loads(expected_status)
 
-        test_data = WireProtocolData(DATA_FILE_MULTIPLE_EXT)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_MULTIPLE_EXT)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         exthandlers_handler.run()
 
@@ -726,7 +730,7 @@ class TestExtension(ExtensionTestCase):
         self.assertEquals(expected_status_json, actual_status_json)
 
     def test_ext_handler_rollingupgrade(self, *args):
-        test_data = WireProtocolData(DATA_FILE_EXT_ROLLINGUPGRADE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_ROLLINGUPGRADE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Test enable scenario.
@@ -806,7 +810,7 @@ class TestExtension(ExtensionTestCase):
     def test_ext_handler_download_failure_transient(self, mock_add_event, *args):
         original_sleep = time.sleep
 
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         protocol.download_ext_handler_pkg = Mock(side_effect=ProtocolError)
 
@@ -817,7 +821,7 @@ class TestExtension(ExtensionTestCase):
     @patch('azurelinuxagent.common.errorstate.ErrorState.is_triggered')
     @patch('azurelinuxagent.ga.exthandlers.add_event')
     def test_ext_handler_report_status_permanent(self, mock_add_event, mock_error_state, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         protocol.report_vm_status = Mock(side_effect=ProtocolError)
 
@@ -831,7 +835,7 @@ class TestExtension(ExtensionTestCase):
 
     @patch('azurelinuxagent.ga.exthandlers.add_event')
     def test_ext_handler_report_status_resource_gone(self, mock_add_event, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         protocol.report_vm_status = Mock(side_effect=ResourceGoneError)
 
@@ -845,7 +849,7 @@ class TestExtension(ExtensionTestCase):
     @patch('azurelinuxagent.common.errorstate.ErrorState.is_triggered')
     @patch('azurelinuxagent.ga.exthandlers.ExtHandlerInstance.report_event')
     def test_ext_handler_download_failure_permanent_ProtocolError(self, mock_add_event, mock_error_state, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         protocol.get_ext_handler_pkgs = Mock(side_effect=ProtocolError)
 
@@ -863,7 +867,7 @@ class TestExtension(ExtensionTestCase):
     @patch('azurelinuxagent.common.event.add_event')
     def test_ext_handler_download_failure_permanent_with_ExtensionDownloadError_and_triggered(self, mock_add_event,
                                                                                               mock_error_state, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         protocol.get_ext_handler_pkgs = Mock(side_effect=ExtensionDownloadError)
 
@@ -883,7 +887,7 @@ class TestExtension(ExtensionTestCase):
     def test_ext_handler_download_failure_permanent_with_ExtensionDownloadError_and_not_triggered(self, mock_add_event,
                                                                                                   mock_error_state,
                                                                                                   *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         protocol.get_ext_handler_pkgs = Mock(side_effect=ExtensionDownloadError)
 
@@ -895,7 +899,7 @@ class TestExtension(ExtensionTestCase):
 
     @patch('azurelinuxagent.ga.exthandlers.fileutil')
     def test_ext_handler_io_error(self, mock_fileutil, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         mock_fileutil.write_file.return_value = IOError("Mock IO Error")
@@ -932,7 +936,7 @@ class TestExtension(ExtensionTestCase):
                         self.assertTrue(exthandlers_handler.extension_processing_allowed())
 
     def test_handle_ext_handlers_on_hold_true(self, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         exthandlers_handler.ext_handlers, exthandlers_handler.last_etag = protocol.get_ext_handlers()
         protocol.get_artifacts_profile = MagicMock()
@@ -951,7 +955,7 @@ class TestExtension(ExtensionTestCase):
             self.assertEqual(1, patch_handle_ext_handlers.call_count)
 
     def test_handle_ext_handlers_on_hold_false(self, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         exthandlers_handler.ext_handlers, exthandlers_handler.last_etag = protocol.get_ext_handlers()
         exthandlers_handler.protocol = protocol
@@ -975,7 +979,7 @@ class TestExtension(ExtensionTestCase):
             self.assertEqual(1, patch_handle_ext_handler.call_count)
 
     def test_last_etag_on_extension_processing(self, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         exthandlers_handler.ext_handlers, etag = protocol.get_ext_handlers()
         exthandlers_handler.protocol = protocol
@@ -1002,7 +1006,7 @@ class TestExtension(ExtensionTestCase):
         self.assertEquals(expected_seq_no, ext_status.sequenceNumber)
 
     def test_ext_handler_no_reporting_status(self, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         exthandlers_handler.run()
         self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
@@ -1023,7 +1027,7 @@ class TestExtension(ExtensionTestCase):
         Testing wait_for_handler_successful_completion() when there is no extension in a handler.
         Expected to return True.
         '''
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         handler = ExtHandler(name="handler")
@@ -1051,7 +1055,7 @@ class TestExtension(ExtensionTestCase):
         Testing wait_for_handler_successful_completion() when there is no status file or seq_no is negative.
         Expected to return False.
         '''
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         ExtHandlerInstance.get_ext_handling_status = MagicMock(return_value=None)
@@ -1062,7 +1066,7 @@ class TestExtension(ExtensionTestCase):
         Testing wait_for_handler_successful_completion() when there is successful status.
         Expected to return True.
         '''
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         status = "success"
@@ -1075,7 +1079,7 @@ class TestExtension(ExtensionTestCase):
         Testing wait_for_handler_successful_completion() when there is error status.
         Expected to return False.
         '''
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         status = "error"
@@ -1088,7 +1092,7 @@ class TestExtension(ExtensionTestCase):
         Testing wait_for_handler_successful_completion() when there is non terminal status.
         Expected to return False.
         '''
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Choose a non-terminal status
@@ -1102,7 +1106,7 @@ class TestExtension(ExtensionTestCase):
         Testing get_ext_handling_status() function with various cases and
         verifying against the expected values
         '''
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         handler_name = "Handler"
@@ -1145,7 +1149,7 @@ class TestExtension(ExtensionTestCase):
         Testing is_ext_handling_complete() with various input and
         verifying against the expected output values.
         '''
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         handler_name = "Handler"
@@ -1183,18 +1187,18 @@ class TestExtension(ExtensionTestCase):
                     config_version = '1.3.0'
                     decision_version = '1.3.0'
                     if autoupgrade:
-                        datafile = DATA_FILE_EXT_AUTOUPGRADE_INTERNALVERSION
+                        datafile = mockwiredata.DATA_FILE_EXT_AUTOUPGRADE_INTERNALVERSION
                     else:
-                        datafile = DATA_FILE_EXT_INTERNALVERSION
+                        datafile = mockwiredata.DATA_FILE_EXT_INTERNALVERSION
                 else:
                     config_version = '1.0.0'
                     decision_version = '1.0.0'
                     if autoupgrade:
-                        datafile = DATA_FILE_EXT_AUTOUPGRADE
+                        datafile = mockwiredata.DATA_FILE_EXT_AUTOUPGRADE
                     else:
-                        datafile = DATA_FILE
+                        datafile = mockwiredata.DATA_FILE
 
-                _, protocol = self._create_mock(WireProtocolData(datafile), *args)
+                _, protocol = self._create_mock(mockwiredata.WireProtocolData(datafile), *args)
                 ext_handlers, _ = protocol.get_ext_handlers()
                 self.assertEqual(1, len(ext_handlers.extHandlers))
                 ext_handler = ext_handlers.extHandlers[0]
@@ -1227,7 +1231,7 @@ class TestExtension(ExtensionTestCase):
             (None, '4.1', '4.1.0.0'),
         ]
 
-        _, protocol = self._create_mock(WireProtocolData(DATA_FILE), *args)
+        _, protocol = self._create_mock(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE), *args)
         version_uri = Mock()
         version_uri.uri = 'http://some/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml'
 
@@ -1247,19 +1251,19 @@ class TestExtension(ExtensionTestCase):
     @patch('azurelinuxagent.common.conf.get_extensions_enabled', return_value=False)
     def test_extensions_disabled(self, _, *args):
         # test status is reported for no extensions
-        test_data = WireProtocolData(DATA_FILE_NO_EXT)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_NO_EXT)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         exthandlers_handler.run()
         self._assert_no_handler_status(protocol.report_vm_status)
 
         # test status is reported, but extensions are not processed
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         exthandlers_handler.run()
         self._assert_no_handler_status(protocol.report_vm_status)
 
     def test_extensions_deleted(self, *args):
-        test_data = WireProtocolData(DATA_FILE_EXT_DELETION)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_DELETION)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Ensure initial enable is successful
@@ -1286,7 +1290,7 @@ class TestExtension(ExtensionTestCase):
         """
         When extension install fails, the operation should not be retried.
         """
-        test_data = WireProtocolData(DATA_FILE_EXT_SINGLE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SINGLE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Ensure initial install is unsuccessful
@@ -1309,7 +1313,7 @@ class TestExtension(ExtensionTestCase):
         """
         When extension install fails, the operation should be reported to our telemetry service.
         """
-        test_data = WireProtocolData(DATA_FILE_EXT_SINGLE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SINGLE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Ensure install is unsuccessful
@@ -1324,7 +1328,7 @@ class TestExtension(ExtensionTestCase):
         """
         When extension enable fails, the operation should not be retried.
         """
-        test_data = WireProtocolData(DATA_FILE_EXT_SINGLE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SINGLE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Ensure initial install is successful, but enable fails
@@ -1347,7 +1351,7 @@ class TestExtension(ExtensionTestCase):
         """
         When extension enable fails, the operation should be reported.
         """
-        test_data = WireProtocolData(DATA_FILE_EXT_SINGLE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SINGLE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Ensure initial install is successful, but enable fails
@@ -1364,7 +1368,7 @@ class TestExtension(ExtensionTestCase):
         """
         When extension disable fails, the operation should not be retried.
         """
-        test_data = WireProtocolData(DATA_FILE_EXT_SINGLE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SINGLE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Ensure initial install and enable is successful, but disable fails
@@ -1400,7 +1404,7 @@ class TestExtension(ExtensionTestCase):
         """
         When extension disable fails, the operation should be reported.
         """
-        test_data = WireProtocolData(DATA_FILE_EXT_SINGLE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SINGLE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Ensure initial install and enable is successful, but disable fails
@@ -1428,7 +1432,7 @@ class TestExtension(ExtensionTestCase):
         """
         When extension uninstall fails, the operation should not be retried.
         """
-        test_data = WireProtocolData(DATA_FILE_EXT_SINGLE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SINGLE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         # Ensure initial install and enable is successful, but uninstall fails
@@ -1743,7 +1747,7 @@ class TestExtension(ExtensionTestCase):
         self._assert_ext_status(protocol.report_ext_status, "success", 0)
 
     def test_ext_path_and_version_env_variables_set_for_ever_operation(self, *args):
-        test_data = WireProtocolData(DATA_FILE_EXT_SINGLE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SINGLE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         with patch.object(CGroupConfigurator.get_instance(), "start_extension_command") as patch_start_cmd:
@@ -1761,7 +1765,7 @@ class TestExtension(ExtensionTestCase):
 
     @patch("azurelinuxagent.common.cgroupconfigurator.handle_process_completion", side_effect="Process Successful")
     def test_ext_sequence_no_should_be_set_for_every_command_call(self, _, *args):
-        test_data = WireProtocolData(DATA_FILE_MULTIPLE_EXT)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_MULTIPLE_EXT)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
 
         with patch("subprocess.Popen") as patch_popen:
@@ -1812,7 +1816,7 @@ class TestExtension(ExtensionTestCase):
         base_dir = os.path.join(conf.get_lib_dir(), 'OSTCExtensions.ExampleHandlerLinux-1.0.0', test_file_name)
         self.create_script(test_file_name, test_file, base_dir)
 
-        test_data = WireProtocolData(DATA_FILE_EXT_SINGLE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_SINGLE)
         exthandlers_handler, protocol = self._create_mock(test_data, *args)
         expected_seq_no = 0
 
@@ -1899,7 +1903,7 @@ class TestExtension(ExtensionTestCase):
 class TestExtensionSequencing(AgentTestCase):
 
     def _create_mock(self, mock_http_get, MockCryptUtil):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
 
         # Mock protocol to return test data
         mock_http_get.side_effect = test_data.mock_http_get
@@ -2156,7 +2160,7 @@ class TestExtensionWithCGroupsEnabled(AgentTestCase):
     def test_ext_handler_with_cgroup_enabled(self, *args):
         self.assertTrue(i_am_root(), "Test does not run when non-root")
 
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, _, protocol = self._create_mock(test_data, *args)
 
         # Test enable scenario.
@@ -2218,38 +2222,53 @@ class TestExtensionWithCGroupsEnabled(AgentTestCase):
         exthandlers_handler.run()
         self._assert_no_handler_status(protocol.report_vm_status)
 
+    @skip_if_predicate_true(lambda: True, "Skipping this test currently: We need two different tests - one for "
+                                  "FileSystemCgroupAPI based test and one for SystemDCgroupAPI based test. @vrdmr will "
+                                  "be splitting this test in subsequent PRs")
+    @skip_if_predicate_true(is_trusty_in_travis, "Does not run on Trusty in Travis as CPU cgroup is not mounted")
+    @patch('azurelinuxagent.common.event.EventLogger.add_metric')
     @patch('azurelinuxagent.common.event.EventLogger.add_event')
     @attr('requires_sudo')
-    def test_ext_handler_and_monitor_handler_with_cgroup_enabled(self, patch_add_event, *args):
+    def test_ext_handler_and_monitor_handler_with_cgroup_enabled(self, patch_add_event, patch_add_metric, *args):
         self.assertTrue(i_am_root(), "Test does not run when non-root")
 
-        test_data = WireProtocolData(DATA_FILE)
-        exthandlers_handler, monitor_handler, protocol = self._create_mock(test_data, *args)
+        # This test has some timing issues when systemd is managing cgroups, so we force the file system API
+        # by creating a new instance of the CGroupConfigurator
+        with patch("azurelinuxagent.common.cgroupapi.CGroupsApi._is_systemd", return_value=False):
+            cgroup_configurator_instance = CGroupConfigurator._instance
+            CGroupConfigurator._instance = None
 
-        monitor_handler.last_cgroup_polling_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
-        monitor_handler.last_cgroup_report_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+            try:
+                test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
+                exthandlers_handler, monitor_handler, protocol = self._create_mock(test_data, *args)
 
-        # Test enable scenario.
-        exthandlers_handler.run()
-        self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
-        self._assert_ext_status(protocol.report_ext_status, "success", 0)
+                monitor_handler.last_cgroup_polling_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+                monitor_handler.last_cgroup_report_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+
+                # Test enable scenario.
+                exthandlers_handler.run()
+                self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0")
+                self._assert_ext_status(protocol.report_ext_status, "success", 0)
 
-        monitor_handler.poll_telemetry_metrics()
-        monitor_handler.send_telemetry_metrics()
+                monitor_handler.poll_telemetry_metrics()
+                monitor_handler.send_telemetry_metrics()
 
-        self.assertEqual(patch_add_event.call_count, 4)
+                self.assertEqual(patch_add_event.call_count, 5)
+                self.assertEqual(patch_add_metric.call_count, 3)
 
-        name = patch_add_event.call_args[0][0]
-        fields = patch_add_event.call_args[1]
+                name = patch_add_event.call_args[0][0]
+                fields = patch_add_event.call_args[1]
 
-        self.assertEqual(name, "WALinuxAgent")
-        self.assertEqual(fields["op"], "ExtensionMetricsData")
-        self.assertEqual(fields["is_success"], True)
-        self.assertEqual(fields["log_event"], False)
-        self.assertEqual(fields["is_internal"], False)
-        self.assertIsInstance(fields["message"], ustr)
+                self.assertEqual(name, "WALinuxAgent")
+                self.assertEqual(fields["op"], "ExtensionMetricsData")
+                self.assertEqual(fields["is_success"], True)
+                self.assertEqual(fields["log_event"], False)
+                self.assertEqual(fields["is_internal"], False)
+                self.assertIsInstance(fields["message"], ustr)
 
-        monitor_handler.stop()
+                monitor_handler.stop()
+            finally:
+                CGroupConfigurator._instance = cgroup_configurator_instance
 
     @attr('requires_sudo')
     def test_ext_handler_with_systemd_cgroup_enabled(self, *args):
@@ -2258,7 +2277,7 @@ class TestExtensionWithCGroupsEnabled(AgentTestCase):
         from azurelinuxagent.common.cgroupapi import CGroupsApi
         print(CGroupsApi._is_systemd())
 
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         exthandlers_handler, _, protocol = self._create_mock(test_data, *args)
 
         # Test enable scenario.
diff --git a/tests/ga/test_exthandlers.py b/tests/ga/test_exthandlers.py
index d54843d2..76e84ea1 100644
--- a/tests/ga/test_exthandlers.py
+++ b/tests/ga/test_exthandlers.py
@@ -2,14 +2,17 @@
 # Licensed under the Apache License.
 import json
 import subprocess
+import os
+import time
 
 from azurelinuxagent.common.protocol.restapi import ExtensionStatus, Extension, ExtHandler, ExtHandlerProperties
 from azurelinuxagent.ga.exthandlers import parse_ext_status, ExtHandlerInstance, get_exthandlers_handler, \
     ExtCommandEnvVariable
+from azurelinuxagent.common.cgroupconfigurator import CGroupConfigurator
 from azurelinuxagent.common.exception import ProtocolError, ExtensionError, ExtensionErrorCodes
 from azurelinuxagent.common.event import WALAEventOperation
 from azurelinuxagent.common.utils.extensionprocessutil import TELEMETRY_MESSAGE_MAX_LEN, format_stdout_stderr, read_output
-from tests.tools import *
+from tests.tools import AgentTestCase, patch, mock_sleep
 
 
 class TestExtHandlers(AgentTestCase):
diff --git a/tests/ga/test_exthandlers_download_extension.py b/tests/ga/test_exthandlers_download_extension.py
index 329399cf..dc1e478b 100644
--- a/tests/ga/test_exthandlers_download_extension.py
+++ b/tests/ga/test_exthandlers_download_extension.py
@@ -1,13 +1,13 @@
 # Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the Apache License.
 
-import zipfile, time
+import zipfile, time, os
 
 from azurelinuxagent.common.protocol.restapi import ExtHandler, ExtHandlerProperties, ExtHandlerPackage, ExtHandlerVersionUri
 from azurelinuxagent.common.protocol.wire import WireProtocol
 from azurelinuxagent.ga.exthandlers import ExtHandlerInstance, NUMBER_OF_DOWNLOAD_RETRIES
 from azurelinuxagent.common.exception import ExtensionDownloadError, ExtensionErrorCodes
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
 
 
 class DownloadExtensionTestCase(AgentTestCase):
diff --git a/tests/ga/test_exthandlers_exthandlerinstance.py b/tests/ga/test_exthandlers_exthandlerinstance.py
index 1f392c16..159fefb2 100644
--- a/tests/ga/test_exthandlers_exthandlerinstance.py
+++ b/tests/ga/test_exthandlers_exthandlerinstance.py
@@ -4,7 +4,10 @@
 from azurelinuxagent.ga.exthandlers import ExtHandlerInstance
 from azurelinuxagent.common.protocol.restapi import ExtHandler, ExtHandlerProperties, ExtHandlerPackage, \
     ExtHandlerVersionUri
-from tests.tools import *
+import os
+import shutil
+import sys
+from tests.tools import AgentTestCase, patch
 
 
 class ExtHandlerInstanceTestCase(AgentTestCase):
diff --git a/tests/ga/test_monitor.py b/tests/ga/test_monitor.py
index 217effee..33bd5208 100644
--- a/tests/ga/test_monitor.py
+++ b/tests/ga/test_monitor.py
@@ -26,27 +26,32 @@ import tempfile
 import time
 from datetime import timedelta
 
-from mock import Mock, MagicMock, patch
 from nose.plugins.attrib import attr
 
-from azurelinuxagent.common import logger
-from azurelinuxagent.common.cgroup import CGroup
-from azurelinuxagent.common.cgroupstelemetry import CGroupsTelemetry
+import azurelinuxagent.common.conf as conf
+from azurelinuxagent.common import event, logger
+from azurelinuxagent.common.cgroup import CGroup, CpuCgroup
+from azurelinuxagent.common.cgroupconfigurator import CGroupConfigurator
+from azurelinuxagent.common.cgroupstelemetry import CGroupsTelemetry, MetricValue
 from azurelinuxagent.common.datacontract import get_properties
-from azurelinuxagent.common.event import EventLogger, WALAEventOperation, CONTAINER_ID_ENV_VARIABLE
+from azurelinuxagent.common.event import CONTAINER_ID_ENV_VARIABLE, EventLogger, WALAEventOperation
 from azurelinuxagent.common.exception import HttpError
 from azurelinuxagent.common.future import ustr
+from azurelinuxagent.common.osutil.default import BASE_CGROUPS, DefaultOSUtil
 from azurelinuxagent.common.protocol.imds import ComputeInfo
 from azurelinuxagent.common.protocol.restapi import VMInfo
+from azurelinuxagent.common.protocol.wire import ExtHandler, ExtHandlerProperties
 from azurelinuxagent.common.protocol.wire import WireProtocol
-from azurelinuxagent.common.telemetryevent import TelemetryEventParam, TelemetryEvent
-from azurelinuxagent.common.utils import restutil, fileutil
-from azurelinuxagent.common.version import AGENT_VERSION, CURRENT_VERSION, AGENT_NAME, CURRENT_AGENT
-from azurelinuxagent.ga.monitor import parse_xml_event, get_monitor_handler, MonitorHandler, \
-    generate_extension_metrics_telemetry_dictionary, parse_json_event
-from tests.common.test_cgroupstelemetry import make_new_cgroup, consume_cpu_time, consume_memory
-from tests.protocol.mockwiredata import WireProtocolData, DATA_FILE, conf
-from tests.tools import load_data, AgentTestCase, data_dir, are_cgroups_enabled, i_am_root, skip_if_predicate_false
+from azurelinuxagent.common.telemetryevent import TelemetryEvent, TelemetryEventParam
+from azurelinuxagent.common.utils import fileutil, restutil
+from azurelinuxagent.common.version import AGENT_NAME, CURRENT_VERSION, AGENT_VERSION, CURRENT_AGENT
+from azurelinuxagent.ga.exthandlers import ExtHandlerInstance
+from azurelinuxagent.ga.monitor import generate_extension_metrics_telemetry_dictionary, get_monitor_handler, \
+    MonitorHandler, parse_json_event, parse_xml_event
+from tests.common.test_cgroupstelemetry import make_new_cgroup
+from tests.protocol.mockwiredata import DATA_FILE, WireProtocolData
+from tests.tools import Mock, MagicMock, patch, load_data, AgentTestCase, data_dir, are_cgroups_enabled, \
+    i_am_root, skip_if_predicate_false, is_trusty_in_travis, skip_if_predicate_true
 
 
 class ResponseMock(Mock):
@@ -554,8 +559,9 @@ class TestEventMonitoring(AgentTestCase):
                                                        "DISTRO_CODE_NAME",
                                                        platform.release())
 
+    @patch("azurelinuxagent.common.event.send_logs_to_telemetry", return_value=True)
     @patch("azurelinuxagent.common.conf.get_lib_dir")
-    def test_collect_and_send_events_should_prepare_all_fields_for_all_event_files(self, mock_lib_dir, *args):
+    def test_collect_and_send_events_should_prepare_all_fields_for_all_event_files(self, mock_lib_dir, _, *args):
         # Test collecting and sending both agent and extension events from the moment they're created to the moment
         # they are to be reported. Ensure all necessary fields from sysinfo are present, as well as the container id.
         mock_lib_dir.return_value = self.lib_dir
@@ -573,6 +579,12 @@ class TestEventMonitoring(AgentTestCase):
                                     message="Heartbeat",
                                     log_event=False)
 
+        # Add agent metric
+        self.event_logger.add_metric("Process", "% Processor Time", "walinuxagent.service", 10)
+
+        # Add agent log
+        self.event_logger.add_log_event(logger.LogLevel.WARNING, "Test sending a log event.")
+
         # Add extension event file the way extension do it, by dropping a .tld file in the events folder
         source_file = os.path.join(data_dir, "ext/dsc_event.json")
         dest_file = os.path.join(conf.get_lib_dir(), "events", "dsc_event.tld")
@@ -583,18 +595,24 @@ class TestEventMonitoring(AgentTestCase):
             monitor_handler.collect_and_send_events()
 
             telemetry_events_list = patch_report_event.call_args_list[0][0][0]
-            self.assertEqual(len(telemetry_events_list.events), 2)
+            self.assertEqual(len(telemetry_events_list.events), 4)
 
             for event in telemetry_events_list.events:
                 # All sysinfo parameters coming from the agent have to be present in the telemetry event to be emitted
                 for param in monitor_handler.sysinfo:
                     self.assertTrue(param in event.parameters)
 
-                # The container id is a special parameter that is not a part of the static sysinfo parameter list.
+                # The container id, GAVersion are special parameters that are not a part of the static sysinfo parameter
+                # list.
+
                 # The container id value is obtained from the goal state and must be present in all telemetry events.
                 container_id_param = TelemetryEventParam("ContainerId", protocol.client.goal_state.container_id)
                 self.assertTrue(container_id_param in event.parameters)
 
+                # Same for GAVersion
+                container_id_param = TelemetryEventParam("GAVersion", CURRENT_AGENT)
+                self.assertTrue(container_id_param in event.parameters)
+
     @patch("azurelinuxagent.common.protocol.wire.WireClient.send_event")
     @patch("azurelinuxagent.common.conf.get_lib_dir")
     def test_collect_and_send_events(self, mock_lib_dir, patch_send_event, *args):
@@ -613,8 +631,9 @@ class TestEventMonitoring(AgentTestCase):
         # Validating the crafted message by the collect_and_send_events call.
         self.assertEqual(1, patch_send_event.call_count)
         send_event_call_args = protocol.client.send_event.call_args[0]
-        sample_message = '<Event id="1">' \
-                         '<![CDATA[<Param Name="Name" Value="DummyExtension" T="mt:wstr" />' \
+
+        sample_message = '<Event id="1"><![CDATA[' \
+                         '<Param Name="Name" Value="DummyExtension" T="mt:wstr" />' \
                          '<Param Name="Version" Value="{0}" T="mt:wstr" />' \
                          '<Param Name="IsInternal" Value="False" T="mt:bool" />' \
                          '<Param Name="Operation" Value="Unknown" T="mt:wstr" />' \
@@ -637,13 +656,13 @@ class TestEventMonitoring(AgentTestCase):
                          '<Param Name="ResourceGroupName" Value="DummyRG" T="mt:wstr" />' \
                          '<Param Name="VMId" Value="DummyVmId" T="mt:wstr" />' \
                          '<Param Name="ImageOrigin" Value="1" T="mt:uint64" />' \
-                         '<Param Name="ContainerId" Value="c6d5526c-5ac2-4200-b6e2-56f2b70c5ab2" T="mt:wstr" />' \
                          '<Param Name="GAVersion" Value="{1}" T="mt:wstr" />' \
+                         '<Param Name="ContainerId" Value="c6d5526c-5ac2-4200-b6e2-56f2b70c5ab2" T="mt:wstr" />' \
                          '<Param Name="EventTid" Value="0" T="mt:uint64" />' \
                          '<Param Name="EventPid" Value="0" T="mt:uint64" />' \
                          '<Param Name="TaskName" Value="" T="mt:wstr" />' \
-                         '<Param Name="KeywordName" Value="" T="mt:wstr" />]]>' \
-                         '</Event>'.format(AGENT_VERSION, CURRENT_AGENT)
+                         '<Param Name="KeywordName" Value="" T="mt:wstr" />' \
+                         ']]></Event>'.format(AGENT_VERSION, CURRENT_AGENT)
 
         self.maxDiff = None
         self.assertEqual(sample_message, send_event_call_args[1])
@@ -730,7 +749,7 @@ class TestEventMonitoring(AgentTestCase):
                 return "builtins"
 
         with patch("{0}.open".format(builtins_version())) as mock_open:
-            mock_open.side_effect = OSError(13, "Permission denied")
+            mock_open.side_effect = IOError(13, "Permission denied")
             monitor_handler.collect_and_send_events()
 
             # Invalid events
@@ -815,20 +834,30 @@ class TestEventMonitoring(AgentTestCase):
 
 @patch('azurelinuxagent.common.osutil.get_osutil')
 @patch('azurelinuxagent.common.protocol.get_protocol_util')
-@patch('azurelinuxagent.common.protocol.util.ProtocolUtil.get_protocol')
 @patch("azurelinuxagent.common.protocol.healthservice.HealthService._report")
+@patch('azurelinuxagent.common.protocol.util.ProtocolUtil.get_protocol', return_value=WireProtocol('endpoint'))
 @patch("azurelinuxagent.common.utils.restutil.http_get")
 class TestExtensionMetricsDataTelemetry(AgentTestCase):
 
     def setUp(self):
         AgentTestCase.setUp(self)
+        event.init_event_logger(os.path.join(self.tmp_dir, "events"))
         CGroupsTelemetry.reset()
 
+    def tearDown(self):
+        AgentTestCase.tearDown(self)
+        CGroupsTelemetry.reset()
+
+    @patch('azurelinuxagent.common.event.EventLogger.add_metric')
     @patch('azurelinuxagent.common.event.EventLogger.add_event')
     @patch("azurelinuxagent.common.cgroupstelemetry.CGroupsTelemetry.poll_all_tracked")
     @patch("azurelinuxagent.common.cgroupstelemetry.CGroupsTelemetry.report_all_tracked")
     def test_send_extension_metrics_telemetry(self, patch_report_all_tracked, patch_poll_all_tracked, patch_add_event,
-                                              *args):
+                                              patch_add_metric, *args):
+        patch_poll_all_tracked.return_value = [MetricValue("Process", "% Processor Time", 1, 1),
+                                               MetricValue("Memory", "Total Memory Usage", 1, 1),
+                                               MetricValue("Memory", "Max Memory Usage", 1, 1)]
+
         patch_report_all_tracked.return_value = {
             "memory": {
                 "cur_mem": [1, 1, 1, 1, 1, str(datetime.datetime.utcnow()), str(datetime.datetime.utcnow())],
@@ -848,14 +877,17 @@ class TestExtensionMetricsDataTelemetry(AgentTestCase):
         self.assertEqual(1, patch_poll_all_tracked.call_count)
         self.assertEqual(1, patch_report_all_tracked.call_count)
         self.assertEqual(1, patch_add_event.call_count)
+        self.assertEqual(3, patch_add_metric.call_count)  # Three metrics being sent.
         monitor_handler.stop()
 
+    @patch('azurelinuxagent.common.event.EventLogger.add_metric')
     @patch('azurelinuxagent.common.event.EventLogger.add_event')
     @patch("azurelinuxagent.common.cgroupstelemetry.CGroupsTelemetry.poll_all_tracked")
     @patch("azurelinuxagent.common.cgroupstelemetry.CGroupsTelemetry.report_all_tracked", return_value={})
     def test_send_extension_metrics_telemetry_for_empty_cgroup(self, patch_report_all_tracked, patch_poll_all_tracked,
-                                                               patch_add_event, *args):
+                                                               patch_add_event, patch_add_metric,*args):
         patch_report_all_tracked.return_value = {}
+        patch_poll_all_tracked.return_value = []
 
         monitor_handler = get_monitor_handler()
         monitor_handler.init_protocols()
@@ -866,49 +898,251 @@ class TestExtensionMetricsDataTelemetry(AgentTestCase):
         self.assertEqual(1, patch_poll_all_tracked.call_count)
         self.assertEqual(1, patch_report_all_tracked.call_count)
         self.assertEqual(0, patch_add_event.call_count)
+        self.assertEqual(0, patch_add_metric.call_count)
         monitor_handler.stop()
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    @patch('azurelinuxagent.common.event.EventLogger.add_metric')
+    @patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage")
+    @patch('azurelinuxagent.common.logger.Logger.periodic_warn')
+    def test_send_extension_metrics_telemetry_handling_memory_cgroup_exceptions_errno2(self, patch_periodic_warn,
+                                                                                       patch_get_memory_usage,
+                                                                                       patch_add_metric, *args):
+        ioerror = IOError()
+        ioerror.errno = 2
+        patch_get_memory_usage.side_effect = ioerror
+
+        CGroupsTelemetry._tracked.append(CpuCgroup("cgroup_name", "/test/path"))
+
+        monitor_handler = get_monitor_handler()
+        monitor_handler.init_protocols()
+        monitor_handler.last_cgroup_polling_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+        monitor_handler.last_cgroup_report_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+        monitor_handler.poll_telemetry_metrics()
+        self.assertEqual(0, patch_periodic_warn.call_count)
+        self.assertEqual(0, patch_add_metric.call_count)  # No metrics should be sent.
+        monitor_handler.stop()
+
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    @patch('azurelinuxagent.common.event.EventLogger.add_metric')
+    @patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage")
+    @patch('azurelinuxagent.common.logger.Logger.periodic_warn')
+    def test_send_extension_metrics_telemetry_handling_cpu_cgroup_exceptions_errno2(self, patch_periodic_warn,
+                                                                                    patch_cpu_usage, patch_add_metric,
+                                                                                    *args):
+        ioerror = IOError()
+        ioerror.errno = 2
+        patch_cpu_usage.side_effect = ioerror
+
+        CGroupsTelemetry._tracked.append(CpuCgroup("cgroup_name", "/test/path"))
+
+        monitor_handler = get_monitor_handler()
+        monitor_handler.init_protocols()
+        monitor_handler.last_cgroup_polling_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+        monitor_handler.last_cgroup_report_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+        monitor_handler.poll_telemetry_metrics()
+        self.assertEqual(0, patch_periodic_warn.call_count)
+        self.assertEqual(0, patch_add_metric.call_count)  # No metrics should be sent.
+        monitor_handler.stop()
+
+    @patch('azurelinuxagent.common.event.EventLogger.add_metric')
+    @patch('azurelinuxagent.common.logger.Logger.periodic_warn')
+    def test_send_extension_metrics_telemetry_for_unsupported_cgroup(self, patch_periodic_warn, patch_add_metric, *args):
+        CGroupsTelemetry._tracked.append(CGroup("cgroup_name", "/test/path", "io"))
+
+        monitor_handler = get_monitor_handler()
+        monitor_handler.init_protocols()
+        monitor_handler.last_cgroup_polling_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+        monitor_handler.last_cgroup_report_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+        monitor_handler.poll_telemetry_metrics()
+        self.assertEqual(1, patch_periodic_warn.call_count)
+        self.assertEqual(0, patch_add_metric.call_count)  # No metrics should be sent.
+
+        monitor_handler.stop()
+
+    @skip_if_predicate_true(lambda: True, "Skipping this test currently: We need two different tests - one for "
+                                  "FileSystemCgroupAPI based test and one for SystemDCgroupAPI based test. @vrdmr will "
+                                  "be splitting this test in subsequent PRs")
     @skip_if_predicate_false(are_cgroups_enabled, "Does not run when Cgroups are not enabled")
+    @skip_if_predicate_true(is_trusty_in_travis, "Does not run on Trusty in Travis")
+    @patch('azurelinuxagent.common.event.EventLogger.add_metric')
     @patch('azurelinuxagent.common.event.EventLogger.add_event')
     @attr('requires_sudo')
-    def test_send_extension_metrics_telemetry_with_actual_cgroup(self, patch_add_event, *args):
+    def test_send_extension_metrics_telemetry_with_actual_cgroup(self, patch_add_event, patch_add_metric, *arg):
         self.assertTrue(i_am_root(), "Test does not run when non-root")
 
-        num_polls = 5
-        name = "test-cgroup"
+        # This test has some timing issues when systemd is managing cgroups, so we force the file system API
+        # by creating a new instance of the CGroupConfigurator
+        with patch("azurelinuxagent.common.cgroupapi.CGroupsApi._is_systemd", return_value=False):
+            cgroup_configurator_instance = CGroupConfigurator._instance
+            CGroupConfigurator._instance = None
+
+            try:
+                max_num_polls = 5
+                time_to_wait = 3
+                extn_name = "foobar-1.0.0"
+
+                cgs = make_new_cgroup(extn_name)
+                self.assertEqual(len(cgs), 2)
+
+                ext_handler_properties = ExtHandlerProperties()
+                ext_handler_properties.version = "1.0.0"
+                ext_handler = ExtHandler(name='foobar')
+                ext_handler.properties = ext_handler_properties
+                ext_handler_instance = ExtHandlerInstance(ext_handler=ext_handler, protocol=None)
+                ext_handler_instance.set_operation("Enable")
+
+                monitor_handler = get_monitor_handler()
+                monitor_handler.init_protocols()
+                monitor_handler.last_cgroup_polling_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+                monitor_handler.last_cgroup_report_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+
+                command = self.create_script("keep_cpu_busy_and_consume_memory_for_{0}_seconds".format(time_to_wait), '''
+nohup python -c "import time
+
+for i in range(5):
+    x = [1, 2, 3, 4, 5] * (i * 1000)
+    time.sleep({0})
+    x = [1, 2, 3, 4, 5] * (i * 1000)
+    x *= 0
+    print('Test loop')" &
+'''.format(time_to_wait))
+
+                self.log_dir = os.path.join(self.tmp_dir, "log")
+
+                with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_base_dir", lambda *_: self.tmp_dir) as \
+                        patch_get_base_dir:
+                    with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_log_dir", lambda *_: self.log_dir) as \
+                            patch_get_log_dir:
+                        ext_handler_instance.launch_command(command)
+
+                self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
+                    BASE_CGROUPS, "cpu", "walinuxagent.extensions", "foobar_1.0.0")))
+                self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
+                    BASE_CGROUPS, "memory", "walinuxagent.extensions", "foobar_1.0.0")))
+
+                for i in range(max_num_polls):
+                    metrics = CGroupsTelemetry.poll_all_tracked()
+                    self.assertEqual(len(metrics), 3)
+
+                monitor_handler.poll_telemetry_metrics()
+                self.assertEqual(3, patch_add_metric.call_count)
+
+                for call_arg in patch_add_metric.call_args_list:
+                    self.assertIn(call_arg[0][0], ["Process", "Memory"])
+                    if call_arg[0][0] == "Process":
+                        self.assertEqual(call_arg[0][1], "% Processor Time")
+                    if call_arg[0][0] == "Memory":
+                        self.assertIn(call_arg[0][1], ["Total Memory Usage", "Max Memory Usage"])
+                    self.assertIsInstance(call_arg[0][3], float)
+
+                    self.assertEqual(call_arg[0][2], extn_name)
+                    self.assertFalse(call_arg[0][4])
+
+                monitor_handler.send_telemetry_metrics()
+                self.assertEqual(3, patch_add_event.call_count)     # 1 for launch command, 1 for extension metrics data
+                                                                    # and 1 for Cgroups initialization
+                name = patch_add_event.call_args[0][0]
+                fields = patch_add_event.call_args[1]
+
+                self.assertEqual(name, "WALinuxAgent")
+                self.assertEqual(fields["op"], "ExtensionMetricsData")
+                self.assertEqual(fields["is_success"], True)
+                self.assertEqual(fields["log_event"], False)
+                self.assertEqual(fields["is_internal"], False)
+                self.assertIsInstance(fields["message"], ustr)
+                monitor_handler.stop()
+            finally:
+                CGroupConfigurator._instance = cgroup_configurator_instance
+
+    @skip_if_predicate_true(lambda: True, "Skipping this test currently: We need two different tests - one for "
+                                  "FileSystemCgroupAPI based test and one for SystemDCgroupAPI based test. @vrdmr will "
+                                  "be splitting this test in subsequent PRs")
+    @skip_if_predicate_false(are_cgroups_enabled, "Does not run when Cgroups are not enabled")
+    @skip_if_predicate_true(is_trusty_in_travis, "Does not run on Trusty in Travis")
+    @patch("azurelinuxagent.common.cgroupconfigurator.get_osutil", return_value=DefaultOSUtil())
+    @patch("azurelinuxagent.common.cgroupapi.CGroupsApi._is_systemd", return_value=False)
+    @patch('azurelinuxagent.common.protocol.wire.WireClient.report_event')
+    @attr('requires_sudo')
+    def test_report_event_metrics_sent_for_actual_cgroup(self, patch_report_event, patch__is_systemd, patch_get_osutil,
+                                                         http_get, patch_get_protocol, *args):
+        self.assertTrue(i_am_root(), "Test does not run when non-root")
+        CGroupConfigurator._instance = None
 
-        cgs = make_new_cgroup(name)
+        max_num_polls = 5
+        time_to_wait = 1
+        extn_name = "foobar-1.0.0"
 
+        cgs = make_new_cgroup(extn_name)
         self.assertEqual(len(cgs), 2)
 
-        for cgroup in cgs:
-            CGroupsTelemetry.track_cgroup(cgroup)
-
-        for i in range(num_polls):
-            CGroupsTelemetry.poll_all_tracked()
-            consume_cpu_time()  # Eat some CPU
-            consume_memory()
+        ext_handler_properties = ExtHandlerProperties()
+        ext_handler_properties.version = "1.0.0"
+        ext_handler = ExtHandler(name='foobar')
+        ext_handler.properties = ext_handler_properties
+        ext_handler_instance = ExtHandlerInstance(ext_handler=ext_handler, protocol=None)
+        ext_handler_instance.set_operation("Enable")
 
         monitor_handler = get_monitor_handler()
         monitor_handler.init_protocols()
         monitor_handler.last_cgroup_polling_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
         monitor_handler.last_cgroup_report_telemetry = datetime.datetime.utcnow() - timedelta(hours=1)
+
+        command = self.create_script("keep_cpu_busy_and_consume_memory_for_{0}_seconds".format(time_to_wait), '''
+nohup python -c "import time
+
+for i in range(3):
+    x = [1, 2, 3, 4, 5] * (i * 1000)
+    time.sleep({0})
+    x *= 0
+    print('Test loop')" &
+'''.format(time_to_wait))
+
+        self.log_dir = os.path.join(self.tmp_dir, "log")
+
+        with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_base_dir", lambda *_: self.tmp_dir) as \
+                patch_get_base_dir:
+            with patch("azurelinuxagent.ga.exthandlers.ExtHandlerInstance.get_log_dir", lambda *_: self.log_dir) as \
+                    patch_get_log_dir:
+                ext_handler_instance.launch_command(command)
+
+        self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
+            BASE_CGROUPS, "cpu", "walinuxagent.extensions", "foobar_1.0.0")))
+        self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
+            BASE_CGROUPS, "memory", "walinuxagent.extensions", "foobar_1.0.0")))
+
+        for i in range(max_num_polls):
+            metrics = CGroupsTelemetry.poll_all_tracked()
+            self.assertEqual(len(metrics), 3)
+
         monitor_handler.poll_telemetry_metrics()
         monitor_handler.send_telemetry_metrics()
-        self.assertEqual(1, patch_add_event.call_count)
+        monitor_handler.collect_and_send_events()
+
+        telemetry_event_list = patch_report_event.call_args_list[0][0][0]
 
-        name = patch_add_event.call_args[0][0]
-        fields = patch_add_event.call_args[1]
+        for e in telemetry_event_list.events:
+            details_of_event = [x for x in e.parameters if x.name in
+                                ["Category", "Counter", "Instance", "Value"]]
 
-        self.assertEqual(name, "WALinuxAgent")
-        self.assertEqual(fields["op"], "ExtensionMetricsData")
-        self.assertEqual(fields["is_success"], True)
-        self.assertEqual(fields["log_event"], False)
-        self.assertEqual(fields["is_internal"], False)
-        self.assertIsInstance(fields["message"], ustr)
+            for i in details_of_event:
+                if i.name == "Category":
+                    self.assertIn(i.value, ["Memory", "Process"])
+                if i.name == "Counter":
+                    self.assertIn(i.value, ["Max Memory Usage", "Total Memory Usage", "% Processor Time"])
+                if i.name == "Instance":
+                    self.assertEqual(i.value, extn_name)
+                if i.name == "Value":
+                    self.assertTrue(isinstance(i.value, int) or isinstance(i.value, float))
 
         monitor_handler.stop()
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
     @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_generate_extension_metrics_telemetry_dictionary(self, *args):
         num_polls = 10
diff --git a/tests/ga/test_remoteaccess.py b/tests/ga/test_remoteaccess.py
index 87eb64c5..c0d0cfc6 100644
--- a/tests/ga/test_remoteaccess.py
+++ b/tests/ga/test_remoteaccess.py
@@ -16,9 +16,9 @@
 #
 import xml
 
-from tests.tools import *
+from tests.tools import AgentTestCase, load_data, patch
 from azurelinuxagent.common.protocol.wire import *
-from azurelinuxagent.common.osutil import get_osutil
+
 
 class TestRemoteAccess(AgentTestCase):
     def test_parse_remote_access(self):
diff --git a/tests/ga/test_remoteaccess_handler.py b/tests/ga/test_remoteaccess_handler.py
index 71271c97..a54e4d54 100644
--- a/tests/ga/test_remoteaccess_handler.py
+++ b/tests/ga/test_remoteaccess_handler.py
@@ -21,7 +21,7 @@ from azurelinuxagent.common.exception import RemoteAccessError
 from azurelinuxagent.common.protocol.wire import *
 from azurelinuxagent.ga.remoteaccess import RemoteAccessHandler
 from tests.common.osutil.mock_osutil import MockOSUtil
-from tests.tools import *
+from tests.tools import AgentTestCase, load_data, patch
 
 
 info_messages = []
diff --git a/tests/ga/test_update.py b/tests/ga/test_update.py
index c435dcc7..38cb8712 100644
--- a/tests/ga/test_update.py
+++ b/tests/ga/test_update.py
@@ -3,14 +3,15 @@
 
 from __future__ import print_function
 
-from azurelinuxagent.common.event import *
+import tempfile
+import unittest
+
 from azurelinuxagent.common.protocol.hostplugin import *
 from azurelinuxagent.common.protocol.metadata import *
 from azurelinuxagent.common.protocol.wire import *
-from azurelinuxagent.common.utils.fileutil import *
 from azurelinuxagent.ga.update import *
+from tests.tools import AgentTestCase, call, data_dir, DEFAULT, patch, load_bin_data, load_data, Mock, MagicMock
 
-from tests.tools import *
 
 NO_ERROR = {
     "last_failure" : 0.0,
diff --git a/tests/pa/test_deprovision.py b/tests/pa/test_deprovision.py
index f4be81e2..591a2c67 100644
--- a/tests/pa/test_deprovision.py
+++ b/tests/pa/test_deprovision.py
@@ -15,14 +15,15 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
-import signal
+import os
 import tempfile
+import unittest
 
 import azurelinuxagent.common.utils.fileutil as fileutil
 
 from azurelinuxagent.pa.deprovision import get_deprovision_handler
 from azurelinuxagent.pa.deprovision.default import DeprovisionHandler
-from tests.tools import *
+from tests.tools import AgentTestCase, distros, Mock, patch
 
 
 class TestDeprovision(AgentTestCase):
diff --git a/tests/pa/test_provision.py b/tests/pa/test_provision.py
index 54c2f8c8..54175601 100644
--- a/tests/pa/test_provision.py
+++ b/tests/pa/test_provision.py
@@ -15,13 +15,20 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
+import os
+import re
+import tempfile
+import unittest
+
+import azurelinuxagent.common.conf as conf
 from azurelinuxagent.common.exception import ProvisionError
 from azurelinuxagent.common.osutil.default import DefaultOSUtil
 from azurelinuxagent.common.protocol import OVF_FILE_NAME
 from azurelinuxagent.pa.provision import get_provision_handler
 from azurelinuxagent.pa.provision.cloudinit import CloudInitProvisionHandler
 from azurelinuxagent.pa.provision.default import ProvisionHandler
-from tests.tools import *
+from azurelinuxagent.common.utils import fileutil
+from tests.tools import AgentTestCase, distros, load_data, MagicMock, Mock, patch
 
 
 class TestProvision(AgentTestCase):
@@ -372,6 +379,7 @@ class TestProvision(AgentTestCase):
         provisioning_handler = get_provision_handler()
         self.assertIsInstance(provisioning_handler, CloudInitProvisionHandler, 'Provisioning handler should be cloud-init if agent is set to cloud-init')
 
+
 if __name__ == '__main__':
     unittest.main()
 
diff --git a/tests/protocol/mockmetadata.py b/tests/protocol/mockmetadata.py
index 65399a85..6f6de003 100644
--- a/tests/protocol/mockmetadata.py
+++ b/tests/protocol/mockmetadata.py
@@ -15,9 +15,8 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
-from tests.tools import *
+from tests.tools import load_data, MagicMock, Mock
 from azurelinuxagent.common.future import httpclient
-from azurelinuxagent.common.utils.cryptutil import CryptUtil
 
 DATA_FILE = {
         "identity": "metadata/identity.json",
@@ -32,6 +31,7 @@ DATA_FILE = {
 DATA_FILE_NO_EXT = DATA_FILE.copy()
 DATA_FILE_NO_EXT["ext_handlers"] = "metadata/ext_handlers_no_ext.json"
 
+
 class MetadataProtocolData(object):
     def __init__(self, data_files):
         self.identity = load_data(data_files.get("identity"))
diff --git a/tests/protocol/mockwiredata.py b/tests/protocol/mockwiredata.py
index 2adf8c89..5202003e 100644
--- a/tests/protocol/mockwiredata.py
+++ b/tests/protocol/mockwiredata.py
@@ -15,7 +15,7 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
-from tests.tools import *
+from tests.tools import load_bin_data, load_data, MagicMock, Mock
 from azurelinuxagent.common.exception import HttpError, ResourceGoneError
 from azurelinuxagent.common.future import httpclient
 from azurelinuxagent.common.utils.cryptutil import CryptUtil
diff --git a/tests/protocol/test_healthservice.py b/tests/protocol/test_healthservice.py
index 1bd44adb..8af322f3 100644
--- a/tests/protocol/test_healthservice.py
+++ b/tests/protocol/test_healthservice.py
@@ -19,7 +19,7 @@ from azurelinuxagent.common.exception import HttpError
 from azurelinuxagent.common.protocol.healthservice import Observation, HealthService
 from azurelinuxagent.common.utils import restutil
 from tests.protocol.test_hostplugin import MockResponse
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
 
 
 class TestHealthService(AgentTestCase):
diff --git a/tests/protocol/test_hostplugin.py b/tests/protocol/test_hostplugin.py
index 842ef03e..3aa92669 100644
--- a/tests/protocol/test_hostplugin.py
+++ b/tests/protocol/test_hostplugin.py
@@ -19,6 +19,7 @@ import base64
 import json
 import sys
 import datetime
+import unittest
 
 import azurelinuxagent.common.protocol.restapi as restapi
 import azurelinuxagent.common.protocol.wire as wire
@@ -31,7 +32,7 @@ from azurelinuxagent.common.protocol.hostplugin import API_VERSION
 from azurelinuxagent.common.utils import restutil
 from tests.protocol.mockwiredata import WireProtocolData, DATA_FILE
 from tests.protocol.test_wire import MockResponse
-from tests.tools import *
+from tests.tools import AgentTestCase, PY_VERSION_MAJOR, Mock, patch
 
 if sys.version_info[0] == 3:
     import http.client as httpclient
diff --git a/tests/protocol/test_image_info_matcher.py b/tests/protocol/test_image_info_matcher.py
index 936e94ff..bd538b39 100644
--- a/tests/protocol/test_image_info_matcher.py
+++ b/tests/protocol/test_image_info_matcher.py
@@ -16,9 +16,8 @@
 #
 # Requires Python 2.6+ and Openssl 1.0+
 
-from azurelinuxagent.common.datacontract import set_properties
 from azurelinuxagent.common.protocol.imds import ImageInfoMatcher
-from tests.tools import *
+import unittest
 
 
 class TestImageInfoMatcher(unittest.TestCase):
diff --git a/tests/protocol/test_imds.py b/tests/protocol/test_imds.py
index 2ac172d6..68c3d436 100644
--- a/tests/protocol/test_imds.py
+++ b/tests/protocol/test_imds.py
@@ -17,6 +17,8 @@
 # Requires Python 2.6+ and Openssl 1.0+
 
 import json
+import os
+import unittest
 
 import azurelinuxagent.common.protocol.imds as imds
 
@@ -25,7 +27,7 @@ from azurelinuxagent.common.exception import HttpError, ResourceGoneError
 from azurelinuxagent.common.future import ustr, httpclient
 from azurelinuxagent.common.utils import restutil
 from tests.ga.test_update import ResponseMock
-from tests.tools import *
+from tests.tools import AgentTestCase, data_dir, MagicMock, Mock, patch
 
 
 class TestImds(AgentTestCase):
diff --git a/tests/protocol/test_metadata.py b/tests/protocol/test_metadata.py
index 3f1793ae..d5ec36de 100644
--- a/tests/protocol/test_metadata.py
+++ b/tests/protocol/test_metadata.py
@@ -15,15 +15,13 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
-from azurelinuxagent.common.datacontract import get_properties, set_properties
-from azurelinuxagent.common.exception import ProtocolError
 from azurelinuxagent.common.protocol.metadata import *
 from azurelinuxagent.common.protocol.restapi import *
 from azurelinuxagent.common.telemetryevent import TelemetryEventList, TelemetryEvent
 from azurelinuxagent.common.utils import restutil
 
 from tests.protocol.mockmetadata import *
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
 
 
 class TestMetadataProtocolGetters(AgentTestCase):
diff --git a/tests/protocol/test_protocol_util.py b/tests/protocol/test_protocol_util.py
index 4a117899..6f341f10 100644
--- a/tests/protocol/test_protocol_util.py
+++ b/tests/protocol/test_protocol_util.py
@@ -15,10 +15,17 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
-from tests.tools import *
+import os
+import unittest
+
+from tests.tools import AgentTestCase, MagicMock, Mock, patch
 from azurelinuxagent.common.exception import *
 from azurelinuxagent.common.protocol import get_protocol_util, \
                                             TAG_FILE_NAME
+from azurelinuxagent.common.utils.restutil import KNOWN_WIRESERVER_IP
+from azurelinuxagent.common.protocol.util import ENDPOINT_FILE_NAME
+from errno import ENOENT
+
 
 @patch("time.sleep")
 class TestProtocolUtil(AgentTestCase):
@@ -34,22 +41,22 @@ class TestProtocolUtil(AgentTestCase):
         protocol_util.dhcp_handler = MagicMock()
         protocol_util.dhcp_handler.endpoint = "foo.bar"
 
-        #Test wire protocol is available
+        # Test wire protocol is available
         protocol = protocol_util.get_protocol()
         self.assertEquals(WireProtocol.return_value, protocol)
 
-        #Test wire protocol is not available
+        # Test wire protocol is not available
         protocol_util.clear_protocol()
         WireProtocol.return_value.detect.side_effect = ProtocolError()
 
         protocol = protocol_util.get_protocol()
         self.assertEquals(MetadataProtocol.return_value, protocol)
 
-        #Test no protocol is available
+        # Test no protocol is available
         protocol_util.clear_protocol()
         WireProtocol.return_value.detect.side_effect = ProtocolError()
-
         MetadataProtocol.return_value.detect.side_effect = ProtocolError()
+
         self.assertRaises(ProtocolError, protocol_util.get_protocol)
 
     def test_detect_protocol_by_file(self, _):
@@ -59,12 +66,12 @@ class TestProtocolUtil(AgentTestCase):
 
         tag_file = os.path.join(self.tmp_dir, TAG_FILE_NAME)
 
-        #Test tag file doesn't exist
+        # Test tag file doesn't exist
         protocol_util.get_protocol(by_file=True)
         protocol_util._detect_wire_protocol.assert_any_call()
         protocol_util._detect_metadata_protocol.assert_not_called()
 
-        #Test tag file exists
+        # Test tag file exists
         protocol_util.clear_protocol()
         protocol_util._detect_wire_protocol.reset_mock()
         protocol_util._detect_metadata_protocol.reset_mock()
@@ -75,6 +82,156 @@ class TestProtocolUtil(AgentTestCase):
         protocol_util._detect_metadata_protocol.assert_any_call()
         protocol_util._detect_wire_protocol.assert_not_called()
 
+    @patch("azurelinuxagent.common.conf.get_lib_dir")
+    @patch("azurelinuxagent.common.protocol.util.WireProtocol")
+    def test_detect_wire_protocol_no_dhcp(self, WireProtocol, mock_get_lib_dir, _):
+        WireProtocol.return_value.detect = Mock()
+        mock_get_lib_dir.return_value = self.tmp_dir
+
+        protocol_util = get_protocol_util()
+
+        protocol_util.osutil = MagicMock()
+        protocol_util.osutil.is_dhcp_available.return_value = False
+
+        protocol_util.dhcp_handler = MagicMock()
+        protocol_util.dhcp_handler.endpoint = None
+        protocol_util.dhcp_handler.run = Mock()
+
+        endpoint_file = protocol_util._get_wireserver_endpoint_file_path()
+
+        # Test wire protocol when no endpoint file has been written
+        protocol_util._detect_wire_protocol()
+        self.assertEqual(KNOWN_WIRESERVER_IP, protocol_util.get_wireserver_endpoint())
+
+        # Test wire protocol when endpoint was previously detected
+        protocol_util.clear_protocol()
+        with open(endpoint_file, "w+") as endpoint_fd:
+            endpoint_fd.write("baz.qux")
+
+        protocol_util._detect_wire_protocol()
+        self.assertEqual("baz.qux", protocol_util.get_wireserver_endpoint())
+
+        # Test wire protocol on dhcp failure
+        protocol_util.clear_protocol()
+        protocol_util.osutil.is_dhcp_available.return_value = True
+        protocol_util.dhcp_handler.run.side_effect = DhcpError()
+
+        self.assertRaises(ProtocolError, protocol_util._detect_wire_protocol)
+
+    @patch("azurelinuxagent.common.protocol.util.MetadataProtocol")
+    @patch("azurelinuxagent.common.protocol.util.WireProtocol")
+    def test_get_protocol(self, WireProtocol, MetadataProtocol, _):
+        WireProtocol.return_value = MagicMock()
+        MetadataProtocol.return_value = MagicMock()
+
+        protocol_util = get_protocol_util()
+        protocol_util.get_wireserver_endpoint = Mock()
+        protocol_util._detect_protocol = MagicMock()
+
+        # Test for wire protocol
+        protocol_util._save_protocol("WireProtocol")
+
+        protocol = protocol_util.get_protocol()
+        self.assertEquals(WireProtocol.return_value, protocol)
+        protocol_util.get_wireserver_endpoint.assert_any_call()
+
+        # Test to ensure protocol persists
+        protocol_util.get_wireserver_endpoint.reset_mock()
+        protocol_util._save_protocol("MetadataProtocol")
+
+        protocol = protocol_util.get_protocol()
+        self.assertEquals(WireProtocol.return_value, protocol)
+        protocol_util.get_wireserver_endpoint.assert_not_called()
+
+        # Test for metadata protocol
+        protocol_util.clear_protocol()
+        protocol_util._save_protocol("MetadataProtocol")
+
+        protocol = protocol_util.get_protocol()
+        self.assertEquals(MetadataProtocol.return_value, protocol)
+        protocol_util.get_wireserver_endpoint.assert_not_called()
+
+        # Test for unknown protocol
+        protocol_util.clear_protocol()
+        protocol_util._save_protocol("Not_a_Protocol")
+        protocol_util._detect_protocol.side_effect = NotImplementedError()
+
+        self.assertRaises(NotImplementedError, protocol_util.get_protocol)
+        protocol_util.get_wireserver_endpoint.assert_not_called()
+
+    @patch("azurelinuxagent.common.utils.fileutil")
+    @patch("azurelinuxagent.common.conf.get_lib_dir")
+    def test_endpoint_file_states(self, mock_get_lib_dir, mock_fileutil, _):
+        mock_get_lib_dir.return_value = self.tmp_dir
+        mock_fileutil = MagicMock()
+
+        protocol_util = get_protocol_util()
+        endpoint_file = protocol_util._get_wireserver_endpoint_file_path()
+
+        # Test get endpoint for io error
+        mock_fileutil.read_file.side_effect = IOError()
+
+        ep = protocol_util.get_wireserver_endpoint()
+        self.assertEquals(ep, KNOWN_WIRESERVER_IP)
+
+        # Test get endpoint when file not found
+        mock_fileutil.read_file.side_effect = IOError(ENOENT, 'File not found')
+
+        ep = protocol_util.get_wireserver_endpoint()
+        self.assertEquals(ep, KNOWN_WIRESERVER_IP)
+
+        # Test get endpoint for empty file
+        mock_fileutil.read_file.return_value = ""
+
+        ep = protocol_util.get_wireserver_endpoint()
+        self.assertEquals(ep, KNOWN_WIRESERVER_IP)
+
+        # Test set endpoint for io error
+        mock_fileutil.write_file.side_effect = IOError()
+
+        ep = protocol_util.get_wireserver_endpoint()
+        self.assertRaises(OSUtilError, protocol_util._set_wireserver_endpoint('abc'))
+
+        # Test clear endpoint for io error
+        with open(endpoint_file, "w+") as ep_fd:
+            ep_fd.write("")
+
+        with patch('os.remove') as mock_remove:
+            protocol_util._clear_wireserver_endpoint()
+            self.assertEqual(1, mock_remove.call_count)
+            self.assertEqual(endpoint_file, mock_remove.call_args_list[0][0][0])
+
+        # Test clear endpoint when file not found
+        with patch('os.remove') as mock_remove:
+            mock_remove = Mock(side_effect=IOError(ENOENT, 'File not found'))
+            protocol_util._clear_wireserver_endpoint()
+            mock_remove.assert_not_called()
+
+    def test_protocol_file_states(self, _):
+        protocol_util = get_protocol_util()
+        protocol_util._clear_wireserver_endpoint = Mock()
+
+        protocol_file = protocol_util._get_protocol_file_path()
+
+        # Test clear protocol for io error
+        with open(protocol_file, "w+") as proto_fd:
+            proto_fd.write("")
+
+        with patch('os.remove') as mock_remove:
+            protocol_util.clear_protocol()
+            self.assertEqual(1, protocol_util._clear_wireserver_endpoint.call_count)
+            self.assertEqual(1, mock_remove.call_count)
+            self.assertEqual(protocol_file, mock_remove.call_args_list[0][0][0])
+
+        # Test clear protocol when file not found
+        protocol_util._clear_wireserver_endpoint.reset_mock()
+
+        with patch('os.remove') as mock_remove:
+            protocol_util.clear_protocol()
+            self.assertEqual(1, protocol_util._clear_wireserver_endpoint.call_count)
+            self.assertEqual(1, mock_remove.call_count)
+            self.assertEqual(protocol_file, mock_remove.call_args_list[0][0][0])
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/protocol/test_wire.py b/tests/protocol/test_wire.py
index b7a324a7..ca162ba4 100644
--- a/tests/protocol/test_wire.py
+++ b/tests/protocol/test_wire.py
@@ -16,18 +16,34 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
+import json
+import os
+import stat
+import tempfile
+import time
+import unittest
 import zipfile
 
-from azurelinuxagent.common.telemetryevent import TelemetryEvent, TelemetryEventParam
-from azurelinuxagent.common.protocol.wire import *
+from azurelinuxagent.common import conf
+from azurelinuxagent.common.exception import InvalidContainerError, ResourceGoneError, ProtocolError, \
+    ExtensionDownloadError
+from azurelinuxagent.common.future import httpclient
+from azurelinuxagent.common.protocol.hostplugin import HostPluginProtocol
+from azurelinuxagent.common.protocol.wire import WireProtocol, WireClient, GoalState, ExtensionsConfig, \
+    InVMArtifactsProfile, VMAgentManifestUri, StatusBlob, VMStatus, INCARNATION_FILE_NAME, ExtHandlerVersionUri, \
+    DataContractList, socket
+from azurelinuxagent.common.telemetryevent import TelemetryEvent, TelemetryEventParam, TelemetryEventList
+from azurelinuxagent.common.utils import fileutil, restutil
 from azurelinuxagent.common.utils.shellutil import run_get_output
+from azurelinuxagent.common.version import CURRENT_VERSION, DISTRO_NAME, DISTRO_VERSION
 from tests.ga.test_monitor import random_generator
-from tests.protocol.mockwiredata import *
+from tests.protocol import mockwiredata
+from tests.tools import ANY, MagicMock, Mock, patch, AgentTestCase, skip_if_predicate_true, running_under_travis
 
 data_with_bom = b'\xef\xbb\xbfhehe'
 testurl = 'http://foo'
 testtype = 'BlockBlob'
-wireserver_url = '168.63.129.16'
+WIRESERVER_URL = '168.63.129.16'
 
 
 def get_event(message, duration=30000, evt_type="", is_internal=False, is_success=True,
@@ -57,7 +73,7 @@ class TestWireProtocol(AgentTestCase):
         MockCryptUtil.side_effect = test_data.mock_crypt_util
 
         with patch.object(restutil, 'http_get', test_data.mock_http_get):
-            protocol = WireProtocol(wireserver_url)
+            protocol = WireProtocol(WIRESERVER_URL)
             protocol.detect()
             protocol.get_vminfo()
             protocol.get_certs()
@@ -83,37 +99,37 @@ class TestWireProtocol(AgentTestCase):
 
     def test_getters(self, *args):
         """Normal case"""
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         self._test_getters(test_data, True, *args)
 
     def test_getters_no_ext(self, *args):
         """Provision with agent is not checked"""
-        test_data = WireProtocolData(DATA_FILE_NO_EXT)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_NO_EXT)
         self._test_getters(test_data, True, *args)
 
     def test_getters_ext_no_settings(self, *args):
         """Extensions without any settings"""
-        test_data = WireProtocolData(DATA_FILE_EXT_NO_SETTINGS)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_NO_SETTINGS)
         self._test_getters(test_data, True, *args)
 
     def test_getters_ext_no_public(self, *args):
         """Extensions without any public settings"""
-        test_data = WireProtocolData(DATA_FILE_EXT_NO_PUBLIC)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_EXT_NO_PUBLIC)
         self._test_getters(test_data, True, *args)
 
     def test_getters_ext_no_cert_format(self, *args):
         """Certificate format not specified"""
-        test_data = WireProtocolData(DATA_FILE_NO_CERT_FORMAT)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_NO_CERT_FORMAT)
         self._test_getters(test_data, True, *args)
 
     def test_getters_ext_cert_format_not_pfx(self, *args):
         """Certificate format is not Pkcs7BlobWithPfxContents specified"""
-        test_data = WireProtocolData(DATA_FILE_CERT_FORMAT_NOT_PFX)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE_CERT_FORMAT_NOT_PFX)
         self._test_getters(test_data, False, *args)
 
     @patch("azurelinuxagent.common.protocol.healthservice.HealthService.report_host_plugin_extension_artifact")
     def test_getters_with_stale_goal_state(self, patch_report, *args):
-        test_data = WireProtocolData(DATA_FILE)
+        test_data = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE)
         test_data.emulate_stale_goal_state = True
 
         self._test_getters(test_data, True, *args)
@@ -166,20 +182,19 @@ class TestWireProtocol(AgentTestCase):
                 self.assertTrue(c == (True if i != 3 else False))
 
     def test_status_blob_parsing(self, *args):
-        wire_protocol_client = WireProtocol(wireserver_url).client
-        wire_protocol_client.ext_conf = ExtensionsConfig(WireProtocolData(DATA_FILE).ext_conf)
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
+        wire_protocol_client.ext_conf = ExtensionsConfig(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).ext_conf)
         self.assertEqual(wire_protocol_client.ext_conf.status_upload_blob,
-                         u'https://yuezhatest.blob.core.windows.net/vhds/test'
-                         u'-cs12.test-cs12.test-cs12.status?sr=b&sp=rw&se'
-                         u'=9999-01-01&sk=key1&sv=2014-02-14&sig'
-                         u'=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D')
+                         'https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?'
+                         'sr=b&sp=rw&se=9999-01-01&sk=key1&sv=2014-02-14&'
+                         'sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo')
         self.assertEqual(wire_protocol_client.ext_conf.status_upload_blob_type,
                          u'BlockBlob')
         pass
 
     def test_get_host_ga_plugin(self, *args):
-        wire_protocol_client = WireProtocol(wireserver_url).client
-        goal_state = GoalState(WireProtocolData(DATA_FILE).goal_state)
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
+        goal_state = GoalState(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state)
 
         with patch.object(WireClient, "get_goal_state", return_value=goal_state) as patch_get_goal_state:
             host_plugin = wire_protocol_client.get_host_plugin()
@@ -197,7 +212,7 @@ class TestWireProtocol(AgentTestCase):
         patch_get_host.return_value = HostPluginProtocol(host_uri, 'container_id', 'role_config')
         patch_request.return_value = [host_uri, {}]
 
-        WireProtocol(wireserver_url).download_ext_handler_pkg(ext_uri, destination)
+        WireProtocol(WIRESERVER_URL).download_ext_handler_pkg(ext_uri, destination)
 
         self.assertEqual(patch_http.call_count, 2)
         self.assertEqual(patch_request.call_count, 1)
@@ -210,7 +225,7 @@ class TestWireProtocol(AgentTestCase):
         tmp = tempfile.mkdtemp()
         destination = os.path.join(tmp, 'test_download_ext_handler_pkg_stream.zip')
 
-        success = WireProtocol(wireserver_url).download_ext_handler_pkg(ext_uri, destination)
+        success = WireProtocol(WIRESERVER_URL).download_ext_handler_pkg(ext_uri, destination)
         self.assertTrue(success)
         self.assertTrue(os.path.exists(destination))
 
@@ -238,7 +253,7 @@ class TestWireProtocol(AgentTestCase):
         Default status blob method is HostPlugin.
         """
         vmstatus = VMStatus(message="Ready", status="Ready")
-        wire_protocol_client = WireProtocol(wireserver_url).client
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
         wire_protocol_client.ext_conf = ExtensionsConfig(None)
         wire_protocol_client.ext_conf.status_upload_blob = testurl
         wire_protocol_client.ext_conf.status_upload_blob_type = testtype
@@ -260,12 +275,12 @@ class TestWireProtocol(AgentTestCase):
     @patch("azurelinuxagent.common.protocol.wire.WireClient.update_goal_state")
     def test_upload_status_blob_host_ga_plugin(self, *args):
         vmstatus = VMStatus(message="Ready", status="Ready")
-        wire_protocol_client = WireProtocol(wireserver_url).client
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
         wire_protocol_client.ext_conf = ExtensionsConfig(None)
         wire_protocol_client.ext_conf.status_upload_blob = testurl
         wire_protocol_client.ext_conf.status_upload_blob_type = testtype
         wire_protocol_client.status_blob.vm_status = vmstatus
-        goal_state = GoalState(WireProtocolData(DATA_FILE).goal_state)
+        goal_state = GoalState(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state)
 
         with patch.object(HostPluginProtocol,
                           "ensure_initialized",
@@ -287,7 +302,7 @@ class TestWireProtocol(AgentTestCase):
     @patch("azurelinuxagent.common.protocol.hostplugin.HostPluginProtocol.ensure_initialized")
     def test_upload_status_blob_unknown_type_assumes_block(self, _, __, *args):
         vmstatus = VMStatus(message="Ready", status="Ready")
-        wire_protocol_client = WireProtocol(wireserver_url).client
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
         wire_protocol_client.ext_conf = ExtensionsConfig(None)
         wire_protocol_client.ext_conf.status_upload_blob = testurl
         wire_protocol_client.ext_conf.status_upload_blob_type = "NotALegalType"
@@ -306,19 +321,19 @@ class TestWireProtocol(AgentTestCase):
     @patch("azurelinuxagent.common.protocol.wire.WireClient.update_goal_state")
     def test_upload_status_blob_reports_prepare_error(self, *args):
         vmstatus = VMStatus(message="Ready", status="Ready")
-        wire_protocol_client = WireProtocol(wireserver_url).client
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
         wire_protocol_client.ext_conf = ExtensionsConfig(None)
         wire_protocol_client.ext_conf.status_upload_blob = testurl
         wire_protocol_client.ext_conf.status_upload_blob_type = testtype
         wire_protocol_client.status_blob.vm_status = vmstatus
-        goal_state = GoalState(WireProtocolData(DATA_FILE).goal_state)
+        goal_state = GoalState(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state)
 
         with patch.object(StatusBlob, "prepare", side_effect=Exception) as mock_prepare:
             self.assertRaises(ProtocolError, wire_protocol_client.upload_status_blob)
             self.assertEqual(1, mock_prepare.call_count)
 
     def test_get_in_vm_artifacts_profile_blob_not_available(self, *args):
-        wire_protocol_client = WireProtocol(wireserver_url).client
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
         wire_protocol_client.ext_conf = ExtensionsConfig(None)
 
         # Test when artifacts_profile_blob is null/None
@@ -329,10 +344,10 @@ class TestWireProtocol(AgentTestCase):
         self.assertEqual(None, wire_protocol_client.get_artifacts_profile())
 
     def test_get_in_vm_artifacts_profile_response_body_not_valid(self, *args):
-        wire_protocol_client = WireProtocol(wireserver_url).client
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
         wire_protocol_client.ext_conf = ExtensionsConfig(None)
         wire_protocol_client.ext_conf.artifacts_profile_blob = testurl
-        goal_state = GoalState(WireProtocolData(DATA_FILE).goal_state)
+        goal_state = GoalState(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state)
         wire_protocol_client.get_goal_state = Mock(return_value=goal_state)
 
         with patch.object(HostPluginProtocol, "get_artifact_request",
@@ -358,10 +373,10 @@ class TestWireProtocol(AgentTestCase):
 
     @patch("azurelinuxagent.common.event.add_event")
     def test_artifacts_profile_json_parsing(self, patch_event, *args):
-        wire_protocol_client = WireProtocol(wireserver_url).client
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
         wire_protocol_client.ext_conf = ExtensionsConfig(None)
         wire_protocol_client.ext_conf.artifacts_profile_blob = testurl
-        goal_state = GoalState(WireProtocolData(DATA_FILE).goal_state)
+        goal_state = GoalState(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state)
         wire_protocol_client.get_goal_state = Mock(return_value=goal_state)
 
         # response is invalid json
@@ -378,10 +393,10 @@ class TestWireProtocol(AgentTestCase):
         self.assertEqual('ArtifactsProfileBlob', patch_event.call_args[1]['op'])
 
     def test_get_in_vm_artifacts_profile_default(self, *args):
-        wire_protocol_client = WireProtocol(wireserver_url).client
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
         wire_protocol_client.ext_conf = ExtensionsConfig(None)
         wire_protocol_client.ext_conf.artifacts_profile_blob = testurl
-        goal_state = GoalState(WireProtocolData(DATA_FILE).goal_state)
+        goal_state = GoalState(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state)
         wire_protocol_client.get_goal_state = Mock(return_value=goal_state)
 
         wire_protocol_client.call_storage_service = Mock(
@@ -399,7 +414,7 @@ class TestWireProtocol(AgentTestCase):
         mock_host = HostPluginProtocol(host_uri,
                                        'container_id',
                                        'role_config')
-        client = WireProtocol(wireserver_url).client
+        client = WireProtocol(WIRESERVER_URL).client
 
         with patch.object(WireClient, "fetch", return_value=None) as patch_fetch:
             with patch.object(WireClient, "get_host_plugin", return_value=mock_host):
@@ -419,7 +434,7 @@ class TestWireProtocol(AgentTestCase):
         uris.append(uri1)
         host_uri = 'host_uri'
         mock_host = HostPluginProtocol(host_uri, 'container_id', 'role_config')
-        client = WireProtocol(wireserver_url).client
+        client = WireProtocol(WIRESERVER_URL).client
         manifest_return = "manifest.xml"
 
         with patch.object(WireClient, "get_host_plugin", return_value=mock_host):
@@ -443,10 +458,10 @@ class TestWireProtocol(AgentTestCase):
                 self.assertTrue(HostPluginProtocol.is_default_channel())
 
     def test_get_in_vm_artifacts_profile_host_ga_plugin(self, *args):
-        wire_protocol_client = WireProtocol(wireserver_url).client
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
         wire_protocol_client.ext_conf = ExtensionsConfig(None)
         wire_protocol_client.ext_conf.artifacts_profile_blob = testurl
-        goal_state = GoalState(WireProtocolData(DATA_FILE).goal_state)
+        goal_state = GoalState(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state)
         wire_protocol_client.get_goal_state = Mock(return_value=goal_state)
         wire_protocol_client.fetch = Mock(side_effect=[None, '{"onHold": "true"}'])
         with patch.object(HostPluginProtocol,
@@ -464,7 +479,7 @@ class TestWireProtocol(AgentTestCase):
         status = 'status'
         message = 'message'
 
-        client = WireProtocol(wireserver_url).client
+        client = WireProtocol(WIRESERVER_URL).client
         actual = StatusBlob(client=client)
         actual.set_vm_status(VMStatus(status=status, message=message))
         timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
@@ -501,7 +516,7 @@ class TestWireProtocol(AgentTestCase):
         mock_http_request.return_value = MockResponse("", 200)
 
         event_str = u'a test string'
-        client = WireProtocol(wireserver_url).client
+        client = WireProtocol(WIRESERVER_URL).client
         client.send_event("foo", event_str)
 
         first_call = mock_http_request.call_args_list[0]
@@ -517,7 +532,7 @@ class TestWireProtocol(AgentTestCase):
     @patch("azurelinuxagent.common.protocol.wire.WireClient.send_event")
     def test_report_event_small_event(self, patch_send_event, *args):
         event_list = TelemetryEventList()
-        client = WireProtocol(wireserver_url).client
+        client = WireProtocol(WIRESERVER_URL).client
 
         event_str = random_generator(10)
         event_list.events.append(get_event(message=event_str))
@@ -539,7 +554,7 @@ class TestWireProtocol(AgentTestCase):
     @patch("azurelinuxagent.common.protocol.wire.WireClient.send_event")
     def test_report_event_multiple_events_to_fill_buffer(self, patch_send_event, *args):
         event_list = TelemetryEventList()
-        client = WireProtocol(wireserver_url).client
+        client = WireProtocol(WIRESERVER_URL).client
 
         event_str = random_generator(2 ** 15)
         event_list.events.append(get_event(message=event_str))
@@ -555,7 +570,7 @@ class TestWireProtocol(AgentTestCase):
         event_list = TelemetryEventList()
         event_str = random_generator(2 ** 18)
         event_list.events.append(get_event(message=event_str))
-        client = WireProtocol(wireserver_url).client
+        client = WireProtocol(WIRESERVER_URL).client
         client.report_event(event_list)
 
         self.assertEqual(patch_send_event.call_count, 0)
@@ -563,14 +578,46 @@ class TestWireProtocol(AgentTestCase):
 
 class TestWireClient(AgentTestCase):
 
+    def test_get_ext_conf_without_uri(self, *args):
+        test_goal_state = GoalState(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state)
+        test_goal_state.ext_uri = None
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
+        wire_protocol_client.get_goal_state = Mock(return_value=test_goal_state)
+
+        with patch("azurelinuxagent.common.protocol.wire.WireClient.fetch_cache",
+                   return_value=mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).ext_conf):
+            ext_conf = wire_protocol_client.get_ext_conf()
+
+        self.assertEqual(0, len(ext_conf.ext_handlers.extHandlers))
+        self.assertEqual(0, len(ext_conf.vmagent_manifests.vmAgentManifests))
+        self.assertIsNone(ext_conf.status_upload_blob)
+        self.assertIsNone(ext_conf.status_upload_blob_type)
+        self.assertIsNone(ext_conf.artifacts_profile_blob)
+
+    def test_get_ext_conf_with_uri(self, *args):
+        test_goal_state = GoalState(mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state)
+        wire_protocol_client = WireProtocol(WIRESERVER_URL).client
+        wire_protocol_client.get_goal_state = Mock(return_value=test_goal_state)
+
+        with patch("azurelinuxagent.common.protocol.wire.WireClient.fetch_cache",
+                   return_value=mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).ext_conf):
+            ext_conf = wire_protocol_client.get_ext_conf()
+
+        self.assertEqual(1, len(ext_conf.ext_handlers.extHandlers))
+        self.assertEqual(2, len(ext_conf.vmagent_manifests.vmAgentManifests))
+        self.assertEqual("https://test.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?"
+                         "sr=b&sp=rw&se=9999-01-01&sk=key1&sv=2014-02-14&sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo", ext_conf.status_upload_blob)
+        self.assertEqual("BlockBlob", ext_conf.status_upload_blob_type)
+        self.assertEqual(None, ext_conf.artifacts_profile_blob)
+
     def test_save_or_update_goal_state_should_save_new_goal_state_file(self):
         # Assert the file didn't exist before
         incarnation = 42
         goal_state_file = os.path.join(conf.get_lib_dir(), "GoalState.{0}.xml".format(incarnation))
         self.assertFalse(os.path.exists(goal_state_file))
 
-        xml_text = WireProtocolData(DATA_FILE).goal_state
-        client = WireClient(wireserver_url)
+        xml_text = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state
+        client = WireClient(WIRESERVER_URL)
         client.save_or_update_goal_state_file(incarnation, xml_text)
 
         # Assert the file exists and its contents
@@ -582,7 +629,7 @@ class TestWireClient(AgentTestCase):
     def test_save_or_update_goal_state_should_update_existing_goal_state_file(self):
         incarnation = 42
         goal_state_file = os.path.join(conf.get_lib_dir(), "GoalState.{0}.xml".format(incarnation))
-        xml_text = WireProtocolData(DATA_FILE).goal_state
+        xml_text = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state
 
         with open(goal_state_file, "w") as f:
             f.write(xml_text)
@@ -594,9 +641,9 @@ class TestWireClient(AgentTestCase):
             self.assertEquals("".join(contents), xml_text)
 
         # Update the container id
-        new_goal_state = WireProtocolData(DATA_FILE).goal_state.replace("c6d5526c-5ac2-4200-b6e2-56f2b70c5ab2",
+        new_goal_state = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state.replace("c6d5526c-5ac2-4200-b6e2-56f2b70c5ab2",
                                                                         "z6d5526c-5ac2-4200-b6e2-56f2b70c5ab2")
-        client = WireClient(wireserver_url)
+        client = WireClient(WIRESERVER_URL)
         client.save_or_update_goal_state_file(incarnation, new_goal_state)
 
         # Assert the file exists and its contents
@@ -611,18 +658,18 @@ class TestWireClient(AgentTestCase):
         with open(incarnation_file, "w") as f:
             f.write(incarnation)
 
-        xml_text = WireProtocolData(DATA_FILE).goal_state
+        xml_text = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state
         goal_state_file = os.path.join(conf.get_lib_dir(), "GoalState.{0}.xml".format(incarnation))
 
         with open(goal_state_file, "w") as f:
             f.write(xml_text)
 
-        client = WireClient(wireserver_url)
+        client = WireClient(WIRESERVER_URL)
         host = client.get_host_plugin()
         old_container_id = host.container_id
 
         # Update the container id
-        new_goal_state = WireProtocolData(DATA_FILE).goal_state.replace("c6d5526c-5ac2-4200-b6e2-56f2b70c5ab2",
+        new_goal_state = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state.replace("c6d5526c-5ac2-4200-b6e2-56f2b70c5ab2",
                                                                         "z6d5526c-5ac2-4200-b6e2-56f2b70c5ab2")
         with patch("azurelinuxagent.common.protocol.wire.WireClient.fetch_config", return_value=new_goal_state):
             client.update_goal_state(forced=False)
@@ -975,8 +1022,8 @@ class TestWireClient(AgentTestCase):
                         self.assertEquals(HostPluginProtocol.is_default_channel(), False)
 
     def test_send_request_using_appropriate_channel_should_not_invoke_host_channel_when_direct_channel_succeeds(self, *args):
-        xml_text = WireProtocolData(DATA_FILE).goal_state
-        client = WireClient(wireserver_url)
+        xml_text = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state
+        client = WireClient(WIRESERVER_URL)
         client.goal_state = GoalState(xml_text)
         client.get_host_plugin().set_default_channel(False)
 
@@ -998,8 +1045,8 @@ class TestWireClient(AgentTestCase):
         self.assertEquals(0, host_func.counter)
 
     def test_send_request_using_appropriate_channel_should_not_use_direct_channel_when_host_channel_is_default(self, *args):
-        xml_text = WireProtocolData(DATA_FILE).goal_state
-        client = WireClient(wireserver_url)
+        xml_text = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state
+        client = WireClient(WIRESERVER_URL)
         client.goal_state = GoalState(xml_text)
         client.get_host_plugin().set_default_channel(True)
 
@@ -1021,8 +1068,8 @@ class TestWireClient(AgentTestCase):
         self.assertEquals(1, host_func.counter)
 
     def test_send_request_using_appropriate_channel_should_use_host_channel_when_direct_channel_fails(self, *args):
-        xml_text = WireProtocolData(DATA_FILE).goal_state
-        client = WireClient(wireserver_url)
+        xml_text = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state
+        client = WireClient(WIRESERVER_URL)
         client.goal_state = GoalState(xml_text)
         host = client.get_host_plugin()
         host.set_default_channel(False)
@@ -1047,8 +1094,8 @@ class TestWireClient(AgentTestCase):
         self.assertEquals(True, host.is_default_channel())
 
     def test_send_request_using_appropriate_channel_should_retry_the_host_channel_after_reloading_goal_state(self, *args):
-        xml_text = WireProtocolData(DATA_FILE).goal_state
-        client = WireClient(wireserver_url)
+        xml_text = mockwiredata.WireProtocolData(mockwiredata.DATA_FILE).goal_state
+        client = WireClient(WIRESERVER_URL)
         client.goal_state = GoalState(xml_text)
         client.get_host_plugin().set_default_channel(False)
 
diff --git a/tests/test_agent.py b/tests/test_agent.py
index d0122641..dedc9905 100644
--- a/tests/test_agent.py
+++ b/tests/test_agent.py
@@ -20,7 +20,7 @@ import os.path
 from azurelinuxagent.agent import *
 from azurelinuxagent.common.conf import *
 
-from tests.tools import *
+from tests.tools import AgentTestCase, data_dir, Mock, patch
 
 EXPECTED_CONFIGURATION = \
 """AutoUpdate.Enabled = True
@@ -70,6 +70,7 @@ ResourceDisk.MountOptions = None
 ResourceDisk.MountPoint = /mnt/resource
 ResourceDisk.SwapSizeMB = 0""".split('\n')
 
+
 class TestAgent(AgentTestCase):
 
     def test_accepts_configuration_path(self):
diff --git a/tests/test_import.py b/tests/test_import.py
index c792c241..5d77d37c 100644
--- a/tests/test_import.py
+++ b/tests/test_import.py
@@ -1,4 +1,4 @@
-from tests.tools import *
+from tests.tools import AgentTestCase
 import azurelinuxagent.common.osutil as osutil
 import azurelinuxagent.common.dhcp as dhcp
 import azurelinuxagent.common.protocol as protocol
diff --git a/tests/utils/test_archive.py b/tests/utils/test_archive.py
index 1016c9aa..22949e48 100644
--- a/tests/utils/test_archive.py
+++ b/tests/utils/test_archive.py
@@ -3,9 +3,14 @@
 from datetime import datetime, timedelta
 
 import zipfile
+import os
+import shutil
+import tempfile
 
+import azurelinuxagent.common.logger as logger
+from azurelinuxagent.common.utils import fileutil
 from azurelinuxagent.common.utils.archive import StateFlusher, StateArchiver, MAX_ARCHIVED_STATES
-from tests.tools import *
+from tests.tools import AgentTestCase
 
 debug = False
 if os.environ.get('DEBUG') == '1':
diff --git a/tests/utils/test_crypt_util.py b/tests/utils/test_crypt_util.py
index c9ae9bc0..c923c176 100644
--- a/tests/utils/test_crypt_util.py
+++ b/tests/utils/test_crypt_util.py
@@ -15,9 +15,14 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
+import os
+import sys
+import unittest
+
+import azurelinuxagent.common.conf as conf
 from azurelinuxagent.common.exception import CryptError
 from azurelinuxagent.common.utils.cryptutil import CryptUtil
-from tests.tools import *
+from tests.tools import AgentTestCase, data_dir, load_data, skip_if_predicate_true
 
 
 def is_python_version_26():
diff --git a/tests/utils/test_extension_process_util.py b/tests/utils/test_extension_process_util.py
index 2e036e74..c51f78af 100644
--- a/tests/utils/test_extension_process_util.py
+++ b/tests/utils/test_extension_process_util.py
@@ -18,8 +18,11 @@ from azurelinuxagent.common.exception import ExtensionError, ExtensionErrorCodes
 from azurelinuxagent.common.future import ustr
 from azurelinuxagent.common.utils.extensionprocessutil import format_stdout_stderr, read_output, \
     wait_for_process_completion_or_timeout, handle_process_completion
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
+import os
+import shutil
 import subprocess
+import tempfile
 
 
 class TestProcessUtils(AgentTestCase):
diff --git a/tests/utils/test_file_util.py b/tests/utils/test_file_util.py
index a3aadf2a..c3d4fdb9 100644
--- a/tests/utils/test_file_util.py
+++ b/tests/utils/test_file_util.py
@@ -21,11 +21,14 @@ import random
 import string
 import tempfile
 import uuid
+import os
+import shutil
+import unittest
 
 import azurelinuxagent.common.utils.fileutil as fileutil
 
 from azurelinuxagent.common.future import ustr
-from tests.tools import *
+from tests.tools import AgentTestCase, patch
 
 
 class TestFileOperations(AgentTestCase):
@@ -324,5 +327,6 @@ DHCP_HOSTNAME=test\n"
             self.assertFalse(os.path.isdir(d))
             self.assertFalse(os.path.isfile(d))
 
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/utils/test_network_util.py b/tests/utils/test_network_util.py
index 8dfefa22..ba5c630c 100644
--- a/tests/utils/test_network_util.py
+++ b/tests/utils/test_network_util.py
@@ -17,7 +17,7 @@
 
 import azurelinuxagent.common.utils.networkutil as networkutil
 
-from tests.tools import *
+from tests.tools import AgentTestCase
 
 
 class TestNetworkOperations(AgentTestCase):
diff --git a/tests/utils/test_rest_util.py b/tests/utils/test_rest_util.py
index f097f10f..97d1903b 100644
--- a/tests/utils/test_rest_util.py
+++ b/tests/utils/test_rest_util.py
@@ -15,11 +15,14 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
+import os
+import unittest
+
 from azurelinuxagent.common.exception import HttpError, ResourceGoneError, InvalidContainerError
 import azurelinuxagent.common.utils.restutil as restutil
 from azurelinuxagent.common.utils.restutil import HTTP_USER_AGENT
 from azurelinuxagent.common.future import httpclient, ustr
-from tests.tools import *
+from tests.tools import AgentTestCase, call, Mock, MagicMock, patch
 
 
 class TestIOErrorCounter(AgentTestCase):
@@ -28,7 +31,7 @@ class TestIOErrorCounter(AgentTestCase):
         restutil.IOErrorCounter.set_protocol_endpoint()
 
         restutil.IOErrorCounter.increment(
-            restutil.DEFAULT_PROTOCOL_ENDPOINT, restutil.HOST_PLUGIN_PORT)
+            restutil.KNOWN_WIRESERVER_IP, restutil.HOST_PLUGIN_PORT)
 
         counts = restutil.IOErrorCounter.get_and_reset()
         self.assertEqual(1, counts["hostplugin"])
@@ -40,7 +43,7 @@ class TestIOErrorCounter(AgentTestCase):
         restutil.IOErrorCounter.set_protocol_endpoint()
 
         restutil.IOErrorCounter.increment(
-            restutil.DEFAULT_PROTOCOL_ENDPOINT, 80)
+            restutil.KNOWN_WIRESERVER_IP, 80)
 
         counts = restutil.IOErrorCounter.get_and_reset()
         self.assertEqual(0, counts["hostplugin"])
@@ -64,11 +67,11 @@ class TestIOErrorCounter(AgentTestCase):
         restutil.IOErrorCounter.set_protocol_endpoint()
 
         restutil.IOErrorCounter.increment(
-            restutil.DEFAULT_PROTOCOL_ENDPOINT, restutil.HOST_PLUGIN_PORT)
+            restutil.KNOWN_WIRESERVER_IP, restutil.HOST_PLUGIN_PORT)
         restutil.IOErrorCounter.increment(
-            restutil.DEFAULT_PROTOCOL_ENDPOINT, restutil.HOST_PLUGIN_PORT)
+            restutil.KNOWN_WIRESERVER_IP, restutil.HOST_PLUGIN_PORT)
         restutil.IOErrorCounter.increment(
-            restutil.DEFAULT_PROTOCOL_ENDPOINT, 80)
+            restutil.KNOWN_WIRESERVER_IP, 80)
         restutil.IOErrorCounter.increment(
             '169.254.169.254', 80)
         restutil.IOErrorCounter.increment(
diff --git a/tests/utils/test_shell_util.py b/tests/utils/test_shell_util.py
index 145fb2d0..a8f545b5 100644
--- a/tests/utils/test_shell_util.py
+++ b/tests/utils/test_shell_util.py
@@ -16,8 +16,7 @@
 # Requires Python 2.6+ and Openssl 1.0+
 #
 
-from tests.tools import *
-from azurelinuxagent.common.logger import LogLevel
+from tests.tools import AgentTestCase, patch
 import unittest
 import azurelinuxagent.common.utils.shellutil as shellutil
 
@@ -155,7 +154,8 @@ class RunCommandTestCase(AgentTestCase):
         exception = context_manager.exception
         self.assertIn("No such file or directory", str(exception))
 
-    def test_run_command_it_should_not_log_by_default(self):
+    @patch("azurelinuxagent.common.utils.shellutil.logger", autospec=True)
+    def test_run_command_it_should_not_log_by_default(self, mock_logger):
 
         def assert_no_message_logged(command):
             try:
diff --git a/tests/utils/test_text_util.py b/tests/utils/test_text_util.py
index a32058e8..0701704a 100644
--- a/tests/utils/test_text_util.py
+++ b/tests/utils/test_text_util.py
@@ -16,9 +16,11 @@
 #
 
 from distutils.version import LooseVersion as Version
-from tests.tools import *
+from tests.tools import AgentTestCase
 
 import hashlib
+import os
+import unittest
 
 import azurelinuxagent.common.utils.textutil as textutil