From efff9d6e0e9dba470518ffcb063f6d4ec7e857d1 Mon Sep 17 00:00:00 2001 From: Yue Zhang Date: Sat, 5 Mar 2016 05:16:15 +0800 Subject: [PATCH] Separate provision agent and guest agent --- azurelinuxagent/agent.py | 101 +++++-- .../{distro => common}/__init__.py | 2 - azurelinuxagent/{ => common}/conf.py | 10 +- .../{distro/default => common}/dhcp.py | 62 ++-- azurelinuxagent/{ => common}/event.py | 10 +- azurelinuxagent/{ => common}/exception.py | 8 + azurelinuxagent/{ => common}/future.py | 0 azurelinuxagent/{ => common}/logger.py | 5 +- azurelinuxagent/common/osutil/__init__.py | 18 ++ .../osutil.py => common/osutil/coreos.py} | 10 +- .../osutil.py => common/osutil/debian.py} | 10 +- .../osutil.py => common/osutil/default.py} | 16 +- .../loader.py => common/osutil/factory.py} | 51 ++-- .../osutil.py => common/osutil/freebsd.py} | 10 +- .../osutil.py => common/osutil/redhat.py} | 18 +- .../suse/osutil.py => common/osutil/suse.py} | 12 +- .../osutil.py => common/osutil/ubuntu.py} | 10 +- .../loader.py => common/protocol/__init__.py} | 9 +- .../{ => common}/protocol/metadata.py | 43 ++- .../{ => common}/protocol/ovfenv.py | 10 +- .../{ => common}/protocol/restapi.py | 28 +- .../protocol/util.py} | 149 ++++++---- azurelinuxagent/{ => common}/protocol/wire.py | 56 +++- .../freebsd => common/utils}/__init__.py | 2 - .../{ => common}/utils/cryptutil.py | 6 +- .../{ => common}/utils/fileutil.py | 6 +- .../{ => common}/utils/restutil.py | 8 +- .../{ => common}/utils/shellutil.py | 4 +- .../{ => common}/utils/textutil.py | 0 .../{metadata.py => common/version.py} | 6 +- azurelinuxagent/daemon/__init__.py | 18 ++ .../{distro/default => daemon}/env.py | 34 ++- .../default/daemon.py => daemon/main.py} | 70 +++-- .../{distro/default => daemon}/monitor.py | 35 ++- .../daemon/resourcedisk/__init__.py | 20 ++ .../resourcedisk/default.py} | 25 +- .../daemon/resourcedisk/factory.py | 33 +++ .../resourcedisk/freebsd.py} | 17 +- .../{distro/default => daemon}/scvmm.py | 31 +- azurelinuxagent/distro/coreos/distro.py | 29 -- azurelinuxagent/distro/debian/distro.py | 27 -- azurelinuxagent/distro/default/distro.py | 51 ---- azurelinuxagent/distro/default/init.py | 53 ---- azurelinuxagent/distro/freebsd/distro.py | 29 -- azurelinuxagent/distro/redhat/__init__.py | 19 -- azurelinuxagent/distro/redhat/distro.py | 31 -- azurelinuxagent/distro/suse/__init__.py | 19 -- azurelinuxagent/distro/ubuntu/__init__.py | 19 -- azurelinuxagent/distro/ubuntu/distro.py | 55 ---- .../{distro/debian => ga}/__init__.py | 2 - .../extension.py => ga/exthandlers.py} | 41 +-- azurelinuxagent/ga/update.py | 278 ++++++++++++++++++ .../{distro/default => pa}/__init__.py | 2 - azurelinuxagent/pa/deprovision/__init__.py | 20 ++ .../deprovision/coreos.py} | 9 +- .../deprovision/default.py} | 29 +- azurelinuxagent/pa/deprovision/factory.py | 36 +++ .../deprovision/ubuntu.py} | 11 +- azurelinuxagent/pa/provision/__init__.py | 18 ++ .../provision.py => pa/provision/default.py} | 61 ++-- .../distro.py => pa/provision/factory.py} | 24 +- .../provision.py => pa/provision/ubuntu.py} | 26 +- azurelinuxagent/utils/__init__.py | 19 -- setup.py | 6 +- tests/__init__.py | 3 - .../protocol => tests/daemon}/__init__.py | 2 - tests/{distro => daemon}/test_daemon.py | 34 +-- tests/{distro => daemon}/test_monitor.py | 7 +- tests/data/ga/WALinuxAgent-2.1.5.rc0.zip | Bin 0 -> 243684 bytes tests/data/wire/ext_conf.xml | 30 +- tests/data/wire/ga_manifest.xml | 48 +++ tests/distro/__init__.py | 19 -- tests/distro/test_loader.py | 36 --- .../distro/coreos => tests/ga}/__init__.py | 2 - tests/{distro => ga}/test_extension.py | 72 +++-- tests/ga/test_update.py | 136 +++++++++ tests/pa/__init__.py | 16 + tests/{distro => pa}/test_provision.py | 32 +- tests/protocol/__init__.py | 3 - tests/protocol/mockmetadata.py | 7 +- tests/protocol/mockwiredata.py | 11 +- tests/protocol/test_metadata.py | 9 +- .../test_protocol_util.py | 54 ++-- tests/protocol/test_restapi.py | 5 +- tests/protocol/test_wire.py | 15 +- tests/test_import.py | 26 ++ tests/tools.py | 9 +- tests/utils/__init__.py | 3 - tests/utils/test_file_util.py | 7 +- tests/utils/test_rest_util.py | 15 +- tests/utils/test_shell_util.py | 5 +- tests/utils/test_text_util.py | 9 +- 92 files changed, 1461 insertions(+), 1031 deletions(-) rename azurelinuxagent/{distro => common}/__init__.py (95%) rename azurelinuxagent/{ => common}/conf.py (94%) rename azurelinuxagent/{distro/default => common}/dhcp.py (87%) rename azurelinuxagent/{ => common}/event.py (93%) rename azurelinuxagent/{ => common}/exception.py (94%) rename azurelinuxagent/{ => common}/future.py (100%) rename azurelinuxagent/{ => common}/logger.py (95%) create mode 100644 azurelinuxagent/common/osutil/__init__.py rename azurelinuxagent/{distro/coreos/osutil.py => common/osutil/coreos.py} (90%) rename azurelinuxagent/{distro/debian/osutil.py => common/osutil/debian.py} (80%) rename azurelinuxagent/{distro/default/osutil.py => common/osutil/default.py} (98%) rename azurelinuxagent/{distro/loader.py => common/osutil/factory.py} (57%) rename azurelinuxagent/{distro/freebsd/osutil.py => common/osutil/freebsd.py} (96%) rename azurelinuxagent/{distro/redhat/osutil.py => common/osutil/redhat.py} (87%) rename azurelinuxagent/{distro/suse/osutil.py => common/osutil/suse.py} (89%) rename azurelinuxagent/{distro/ubuntu/osutil.py => common/osutil/ubuntu.py} (88%) rename azurelinuxagent/{distro/debian/loader.py => common/protocol/__init__.py} (76%) rename azurelinuxagent/{ => common}/protocol/metadata.py (81%) rename azurelinuxagent/{ => common}/protocol/ovfenv.py (93%) rename azurelinuxagent/{ => common}/protocol/restapi.py (90%) rename azurelinuxagent/{distro/default/protocolUtil.py => common/protocol/util.py} (67%) rename azurelinuxagent/{ => common}/protocol/wire.py (95%) rename azurelinuxagent/{distro/freebsd => common/utils}/__init__.py (95%) rename azurelinuxagent/{ => common}/utils/cryptutil.py (96%) rename azurelinuxagent/{ => common}/utils/fileutil.py (96%) rename azurelinuxagent/{ => common}/utils/restutil.py (96%) rename azurelinuxagent/{ => common}/utils/shellutil.py (97%) rename azurelinuxagent/{ => common}/utils/textutil.py (100%) rename azurelinuxagent/{metadata.py => common/version.py} (95%) create mode 100644 azurelinuxagent/daemon/__init__.py rename azurelinuxagent/{distro/default => daemon}/env.py (77%) rename azurelinuxagent/{distro/default/daemon.py => daemon/main.py} (57%) rename azurelinuxagent/{distro/default => daemon}/monitor.py (84%) create mode 100644 azurelinuxagent/daemon/resourcedisk/__init__.py rename azurelinuxagent/{distro/default/resourceDisk.py => daemon/resourcedisk/default.py} (91%) create mode 100644 azurelinuxagent/daemon/resourcedisk/factory.py rename azurelinuxagent/{distro/freebsd/resourceDisk.py => daemon/resourcedisk/freebsd.py} (90%) rename azurelinuxagent/{distro/default => daemon}/scvmm.py (64%) delete mode 100644 azurelinuxagent/distro/coreos/distro.py delete mode 100644 azurelinuxagent/distro/debian/distro.py delete mode 100644 azurelinuxagent/distro/default/distro.py delete mode 100644 azurelinuxagent/distro/default/init.py delete mode 100644 azurelinuxagent/distro/freebsd/distro.py delete mode 100644 azurelinuxagent/distro/redhat/__init__.py delete mode 100644 azurelinuxagent/distro/redhat/distro.py delete mode 100644 azurelinuxagent/distro/suse/__init__.py delete mode 100644 azurelinuxagent/distro/ubuntu/__init__.py delete mode 100644 azurelinuxagent/distro/ubuntu/distro.py rename azurelinuxagent/{distro/debian => ga}/__init__.py (95%) rename azurelinuxagent/{distro/default/extension.py => ga/exthandlers.py} (95%) create mode 100644 azurelinuxagent/ga/update.py rename azurelinuxagent/{distro/default => pa}/__init__.py (95%) create mode 100644 azurelinuxagent/pa/deprovision/__init__.py rename azurelinuxagent/{distro/coreos/deprovision.py => pa/deprovision/coreos.py} (78%) rename azurelinuxagent/{distro/default/deprovision.py => pa/deprovision/default.py} (81%) create mode 100644 azurelinuxagent/pa/deprovision/factory.py rename azurelinuxagent/{distro/ubuntu/deprovision.py => pa/deprovision/ubuntu.py} (82%) create mode 100644 azurelinuxagent/pa/provision/__init__.py rename azurelinuxagent/{distro/default/provision.py => pa/provision/default.py} (75%) rename azurelinuxagent/{distro/suse/distro.py => pa/provision/factory.py} (51%) rename azurelinuxagent/{distro/ubuntu/provision.py => pa/provision/ubuntu.py} (81%) delete mode 100644 azurelinuxagent/utils/__init__.py rename {azurelinuxagent/protocol => tests/daemon}/__init__.py (95%) rename tests/{distro => daemon}/test_daemon.py (63%) rename tests/{distro => daemon}/test_monitor.py (77%) create mode 100644 tests/data/ga/WALinuxAgent-2.1.5.rc0.zip create mode 100644 tests/data/wire/ga_manifest.xml delete mode 100644 tests/distro/__init__.py delete mode 100644 tests/distro/test_loader.py rename {azurelinuxagent/distro/coreos => tests/ga}/__init__.py (95%) rename tests/{distro => ga}/test_extension.py (86%) create mode 100644 tests/ga/test_update.py create mode 100644 tests/pa/__init__.py rename tests/{distro => pa}/test_provision.py (58%) rename tests/{distro => protocol}/test_protocol_util.py (52%) create mode 100644 tests/test_import.py diff --git a/azurelinuxagent/agent.py b/azurelinuxagent/agent.py index 93e9c16..8b5c8f2 100644 --- a/azurelinuxagent/agent.py +++ b/azurelinuxagent/agent.py @@ -25,41 +25,90 @@ import os import sys import re import subprocess -from azurelinuxagent.metadata import AGENT_NAME, AGENT_LONG_VERSION, \ +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.event as event +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.version import AGENT_NAME, AGENT_LONG_VERSION, \ DISTRO_NAME, DISTRO_VERSION, \ PY_VERSION_MAJOR, PY_VERSION_MINOR, \ PY_VERSION_MICRO - -from azurelinuxagent.distro.loader import get_distro +from azurelinuxagent.common.osutil import get_osutil class Agent(object): def __init__(self, verbose): """ Initialize agent running environment. """ - self.distro = get_distro(); - self.distro.init_handler.run(verbose) + self.osutil = get_osutil() + #Init stdout log + level = logger.LogLevel.VERBOSE if verbose else logger.LogLevel.INFO + logger.add_logger_appender(logger.AppenderType.STDOUT, level) + + #Init config + conf_file_path = self.osutil.get_agent_conf_file_path() + conf.load_conf_from_file(conf_file_path) + + #Init log + verbose = verbose or conf.get_logs_verbose() + level = logger.LogLevel.VERBOSE if verbose else logger.LogLevel.INFO + logger.add_logger_appender(logger.AppenderType.FILE, level, + path="/var/log/waagent.log") + logger.add_logger_appender(logger.AppenderType.CONSOLE, level, + path="/dev/console") + + #Init event reporter + event_dir = os.path.join(conf.get_lib_dir(), "events") + event.init_event_logger(event_dir) + event.enable_unhandled_err_dump("WALA") def daemon(self): """ Run agent daemon """ - self.distro.daemon_handler.run() + from azurelinuxagent.daemon import get_daemon_handler + daemon_handler = get_daemon_handler() + daemon_handler.run() + + def provision(self): + """ + Run provision command + """ + from azurelinuxagent.pa.provision import get_provision_handler + provision_handler = get_provision_handler() + provision_handler.run() def deprovision(self, force=False, deluser=False): """ Run deprovision command """ - self.distro.deprovision_handler.run(force=force, deluser=deluser) + from azurelinuxagent.pa.deprovision import get_deprovision_handler + deprovision_handler = get_deprovision_handler() + deprovision_handler.run(force=force, deluser=deluser) def register_service(self): """ Register agent as a service """ print("Register {0} service".format(AGENT_NAME)) - self.distro.osutil.register_agent_service() + self.osutil.register_agent_service() print("Start {0} service".format(AGENT_NAME)) - self.distro.osutil.start_agent_service() + self.osutil.start_agent_service() + + def update(self): + """ + Run extension handlers handler + """ + from azurelinuxagent.ga.update import get_update_handler + update_handler = get_update_handler() + update_handler.run() + + def run_exthandlers(self): + """ + Run extension handlers handler + """ + from azurelinuxagent.ga.exthandlers import get_exthandlers_handler + exthandlers_handler = get_exthandlers_handler() + exthandlers_handler.run() def main(): """ @@ -74,15 +123,24 @@ def main(): elif command == "start": start() else: - agent = Agent(verbose) - if command == "deprovision+user": - agent.deprovision(force, deluser=True) - elif command == "deprovision": - agent.deprovision(force, deluser=False) - elif command == "register-service": - agent.register_service() - elif command == "daemon": - agent.daemon() + try: + agent = Agent(verbose) + if command == "deprovision+user": + agent.deprovision(force, deluser=True) + elif command == "provision": + agent.provision() + elif command == "deprovision": + agent.deprovision(force, deluser=False) + elif command == "register-service": + agent.register_service() + elif command == "daemon": + agent.daemon() + elif command == "update": + agent.update() + elif command == "run-exthandlers": + agent.run_exthandlers() + except Exception as e: + logger.error(u"Failed to run '{0}': {1}", command, e) def parse_args(sys_args): """ @@ -102,6 +160,10 @@ def parse_args(sys_args): cmd = "start" elif re.match("^([-/]*)register-service", a): cmd = "register-service" + elif re.match("^([-/]*)update", a): + cmd = "update" + elif re.match("^([-/]*)run-exthandlers", a): + cmd = "run-exthandlers" elif re.match("^([-/]*)version", a): cmd = "version" elif re.match("^([-/]*)verbose", a): @@ -129,7 +191,8 @@ def usage(): """ print("") print((("usage: {0} [-verbose] [-force] [-help]" - "-deprovision[+user]|-register-service|-version|-daemon|-start]" + "-deprovision[+user]|-register-service|-version|-daemon|-start|" + "-update|-run-exthandlers]" "").format(sys.argv[0]))) print("") diff --git a/azurelinuxagent/distro/__init__.py b/azurelinuxagent/common/__init__.py similarity index 95% rename from azurelinuxagent/distro/__init__.py rename to azurelinuxagent/common/__init__.py index d9b82f5..1ea2f38 100644 --- a/azurelinuxagent/distro/__init__.py +++ b/azurelinuxagent/common/__init__.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/azurelinuxagent/conf.py b/azurelinuxagent/common/conf.py similarity index 94% rename from azurelinuxagent/conf.py rename to azurelinuxagent/common/conf.py index 1ac65cb..22b5d74 100644 --- a/azurelinuxagent/conf.py +++ b/azurelinuxagent/common/conf.py @@ -21,8 +21,8 @@ Module conf loads and parses configuration file """ import os -import azurelinuxagent.utils.fileutil as fileutil -from azurelinuxagent.exception import AgentConfigError +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.common.exception import AgentConfigError class ConfigurationProvider(object): """ @@ -167,3 +167,9 @@ def get_resourcedisk_filesystem(conf=__conf__): def get_resourcedisk_swap_size_mb(conf=__conf__): return conf.get_int("ResourceDisk.SwapSizeMB", 0) +def get_autoupdate_gafamily(conf=__conf__): + return conf.get("AutoUpdate.GAFamily", "Prod") + +def get_autoupdate_enabled(conf=__conf__): + return conf.get_switch("AutoUpdate.Enabled", True) + diff --git a/azurelinuxagent/distro/default/dhcp.py b/azurelinuxagent/common/dhcp.py similarity index 87% rename from azurelinuxagent/distro/default/dhcp.py rename to azurelinuxagent/common/dhcp.py index 1c20960..9b4da90 100644 --- a/azurelinuxagent/distro/default/dhcp.py +++ b/azurelinuxagent/common/dhcp.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,29 +13,34 @@ # limitations under the License. # # Requires Python 2.4+ and Openssl 1.0+ + import os import socket import array import time import threading -import azurelinuxagent.logger as logger -import azurelinuxagent.conf as conf -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil -from azurelinuxagent.utils.textutil import hex_dump, hex_dump2, hex_dump3, \ - compare_bytes, str_to_ord, \ - unpack_big_endian, \ - unpack_little_endian, \ - int_to_ip4_addr -from azurelinuxagent.exception import DhcpError +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +from azurelinuxagent.common.utils.textutil import hex_dump, hex_dump2, \ + hex_dump3, \ + compare_bytes, str_to_ord, \ + unpack_big_endian, \ + unpack_little_endian, \ + int_to_ip4_addr +from azurelinuxagent.common.exception import DhcpError +from azurelinuxagent.common.osutil import get_osutil +def get_dhcp_handler(): + return DhcpHandler() class DhcpHandler(object): """ Azure use DHCP option 245 to pass endpoint ip to VMs. """ - def __init__(self, distro): - self.distro = distro + def __init__(self): + self.osutil = get_osutil() self.endpoint = None self.gateway = None self.routes = None @@ -56,13 +59,13 @@ class DhcpHandler(object): """ Wait for network stack to be initialized. """ - ipv4 = self.distro.osutil.get_ip4_addr() + ipv4 = self.osutil.get_ip4_addr() while ipv4 == '' or ipv4 == '0.0.0.0': logger.info("Waiting for network.") time.sleep(10) logger.info("Try to start network interface.") - self.distro.osutil.start_network() - ipv4 = self.distro.osutil.get_ip4_addr() + self.osutil.start_network() + ipv4 = self.osutil.get_ip4_addr() def conf_routes(self): logger.info("Configure routes") @@ -70,16 +73,16 @@ class DhcpHandler(object): logger.info("Routes:{0}", self.routes) #Add default gateway if self.gateway is not None: - self.distro.osutil.route_add(0 , 0, self.gateway) + self.osutil.route_add(0 , 0, self.gateway) if self.routes is not None: for route in self.routes: - self.distro.osutil.route_add(route[0], route[1], route[2]) + self.osutil.route_add(route[0], route[1], route[2]) def _send_dhcp_req(self, request): __waiting_duration__ = [0, 10, 30, 60, 60] for duration in __waiting_duration__: try: - self.distro.osutil.allow_dhcp_broadcast() + self.osutil.allow_dhcp_broadcast() response = socket_send(request) validate_dhcp_resp(request, response) return response @@ -95,7 +98,8 @@ class DhcpHandler(object): Stop dhcp service if necessary """ logger.info("Send dhcp request") - mac_addr = self.distro.osutil.get_mac_addr() + mac_addr = self.osutil.get_mac_addr() + req = build_dhcp_request(mac_addr) # Do unicast first, then fallback to broadcast if fails. req = build_dhcp_request(mac_addr, self._request_broadcast) @@ -103,23 +107,23 @@ class DhcpHandler(object): self._request_broadcast = True # Temporary allow broadcast for dhcp. Remove the route when done. - missing_default_route = self.distro.osutil.is_missing_default_route() - ifname = self.distro.osutil.get_if_name() + missing_default_route = self.osutil.is_missing_default_route() + ifname = self.osutil.get_if_name() if missing_default_route: - self.distro.osutil.set_route_for_dhcp_broadcast(ifname) + self.osutil.set_route_for_dhcp_broadcast(ifname) # In some distros, dhcp service needs to be shutdown before agent probe # endpoint through dhcp. - if self.distro.osutil.is_dhcp_enabled(): - self.distro.osutil.stop_dhcp_service() + if self.osutil.is_dhcp_enabled(): + self.osutil.stop_dhcp_service() resp = self._send_dhcp_req(req) - if self.distro.osutil.is_dhcp_enabled(): - self.distro.osutil.start_dhcp_service() + if self.osutil.is_dhcp_enabled(): + self.osutil.start_dhcp_service() if missing_default_route: - self.distro.osutil.remove_route_for_dhcp_broadcast(ifname) + self.osutil.remove_route_for_dhcp_broadcast(ifname) if resp is None: raise DhcpError("Failed to receive dhcp response.") diff --git a/azurelinuxagent/event.py b/azurelinuxagent/common/event.py similarity index 93% rename from azurelinuxagent/event.py rename to azurelinuxagent/common/event.py index f38b242..2ab2ef2 100644 --- a/azurelinuxagent/event.py +++ b/azurelinuxagent/common/event.py @@ -24,14 +24,14 @@ import time import datetime import threading import platform -import azurelinuxagent.logger as logger -from azurelinuxagent.exception import EventError, ProtocolError -from azurelinuxagent.future import ustr -from azurelinuxagent.protocol.restapi import TelemetryEventParam, \ +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.exception import EventError, ProtocolError +from azurelinuxagent.common.future import ustr +from azurelinuxagent.common.protocol.restapi import TelemetryEventParam, \ TelemetryEventList, \ TelemetryEvent, \ set_properties, get_properties -from azurelinuxagent.metadata import DISTRO_NAME, DISTRO_VERSION, \ +from azurelinuxagent.common.version import DISTRO_NAME, DISTRO_VERSION, \ DISTRO_CODE_NAME, AGENT_VERSION diff --git a/azurelinuxagent/exception.py b/azurelinuxagent/common/exception.py similarity index 94% rename from azurelinuxagent/exception.py rename to azurelinuxagent/common/exception.py index 7fa5cff..457490c 100644 --- a/azurelinuxagent/exception.py +++ b/azurelinuxagent/common/exception.py @@ -113,3 +113,11 @@ class CryptError(AgentError): """ def __init__(self, msg=None, inner=None): super(CryptError, self).__init__('000011', msg, inner) + +class UpdateError(AgentError): + """ + Update Guest Agent error + """ + def __init__(self, msg=None, inner=None): + super(UpdateError, self).__init__('000012', msg, inner) + diff --git a/azurelinuxagent/future.py b/azurelinuxagent/common/future.py similarity index 100% rename from azurelinuxagent/future.py rename to azurelinuxagent/common/future.py diff --git a/azurelinuxagent/logger.py b/azurelinuxagent/common/logger.py similarity index 95% rename from azurelinuxagent/logger.py rename to azurelinuxagent/common/logger.py index 52cb55f..bd4916b 100644 --- a/azurelinuxagent/logger.py +++ b/azurelinuxagent/common/logger.py @@ -14,15 +14,12 @@ # # Requires Python 2.4+ and openssl_bin 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx """ Log utils """ import os import sys -from azurelinuxagent.future import ustr +from azurelinuxagent.common.future import ustr from datetime import datetime class Logger(object): diff --git a/azurelinuxagent/common/osutil/__init__.py b/azurelinuxagent/common/osutil/__init__.py new file mode 100644 index 0000000..3b5ba3b --- /dev/null +++ b/azurelinuxagent/common/osutil/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +from azurelinuxagent.common.osutil.factory import get_osutil diff --git a/azurelinuxagent/distro/coreos/osutil.py b/azurelinuxagent/common/osutil/coreos.py similarity index 90% rename from azurelinuxagent/distro/coreos/osutil.py rename to azurelinuxagent/common/osutil/coreos.py index b174d04..e26fd97 100644 --- a/azurelinuxagent/distro/coreos/osutil.py +++ b/azurelinuxagent/common/osutil/coreos.py @@ -26,11 +26,11 @@ import struct import fcntl import time import base64 -import azurelinuxagent.logger as logger -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil -import azurelinuxagent.utils.textutil as textutil -from azurelinuxagent.distro.default.osutil import DefaultOSUtil +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +import azurelinuxagent.common.utils.textutil as textutil +from azurelinuxagent.common.osutil.default import DefaultOSUtil class CoreOSUtil(DefaultOSUtil): def __init__(self): diff --git a/azurelinuxagent/distro/debian/osutil.py b/azurelinuxagent/common/osutil/debian.py similarity index 80% rename from azurelinuxagent/distro/debian/osutil.py rename to azurelinuxagent/common/osutil/debian.py index a40c1de..f455572 100644 --- a/azurelinuxagent/distro/debian/osutil.py +++ b/azurelinuxagent/common/osutil/debian.py @@ -26,11 +26,11 @@ import struct import fcntl import time import base64 -import azurelinuxagent.logger as logger -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil -import azurelinuxagent.utils.textutil as textutil -from azurelinuxagent.distro.default.osutil import DefaultOSUtil +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +import azurelinuxagent.common.utils.textutil as textutil +from azurelinuxagent.common.osutil.default import DefaultOSUtil class DebianOSUtil(DefaultOSUtil): def __init__(self): diff --git a/azurelinuxagent/distro/default/osutil.py b/azurelinuxagent/common/osutil/default.py similarity index 98% rename from azurelinuxagent/distro/default/osutil.py rename to azurelinuxagent/common/osutil/default.py index 523202b..796d92d 100644 --- a/azurelinuxagent/distro/default/osutil.py +++ b/azurelinuxagent/common/osutil/default.py @@ -26,14 +26,14 @@ import time import pwd import fcntl import base64 -import azurelinuxagent.logger as logger -import azurelinuxagent.conf as conf -from azurelinuxagent.exception import OSUtilError -from azurelinuxagent.future import ustr -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil -import azurelinuxagent.utils.textutil as textutil -from azurelinuxagent.utils.cryptutil import CryptUtil +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.exception import OSUtilError +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +import azurelinuxagent.common.utils.textutil as textutil +from azurelinuxagent.common.utils.cryptutil import CryptUtil __RULES_FILES__ = [ "/lib/udev/rules.d/75-persistent-net-generator.rules", "/etc/udev/rules.d/70-persistent-net.rules" ] diff --git a/azurelinuxagent/distro/loader.py b/azurelinuxagent/common/osutil/factory.py similarity index 57% rename from azurelinuxagent/distro/loader.py rename to azurelinuxagent/common/osutil/factory.py index f6800b3..5e8ae6e 100644 --- a/azurelinuxagent/distro/loader.py +++ b/azurelinuxagent/common/osutil/factory.py @@ -15,56 +15,55 @@ # Requires Python 2.4+ and Openssl 1.0+ # -import azurelinuxagent.logger as logger -from azurelinuxagent.utils.textutil import Version -from azurelinuxagent.metadata import DISTRO_NAME, DISTRO_VERSION, \ +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.utils.textutil import Version +from azurelinuxagent.common.version import DISTRO_NAME, DISTRO_VERSION, \ DISTRO_FULL_NAME -from azurelinuxagent.distro.default.distro import DefaultDistro -from azurelinuxagent.distro.ubuntu.distro import UbuntuDistro, \ - Ubuntu14Distro, \ - Ubuntu12Distro, \ - UbuntuSnappyDistro -from azurelinuxagent.distro.redhat.distro import RedhatDistro, Redhat6xDistro -from azurelinuxagent.distro.coreos.distro import CoreOSDistro -from azurelinuxagent.distro.suse.distro import SUSE11Distro, SUSEDistro -from azurelinuxagent.distro.debian.distro import DebianDistro -from azurelinuxagent.distro.freebsd.distro import FreeBSDDistro -def get_distro(distro_name=DISTRO_NAME, distro_version=DISTRO_VERSION, +from .default import DefaultOSUtil +from .coreos import CoreOSUtil +from .debian import DebianOSUtil +from .freebsd import FreeBSDOSUtil +from .redhat import RedhatOSUtil, Redhat6xOSUtil +from .suse import SUSEOSUtil, SUSE11OSUtil +from .ubuntu import UbuntuOSUtil, Ubuntu12OSUtil, Ubuntu14OSUtil, \ + UbuntuSnappyOSUtil + +def get_osutil(distro_name=DISTRO_NAME, distro_version=DISTRO_VERSION, distro_full_name=DISTRO_FULL_NAME): if distro_name == "ubuntu": if Version(distro_version) == Version("12.04") or \ Version(distro_version) == Version("12.10"): - return Ubuntu12Distro() + return Ubuntu12OSUtil() elif Version(distro_version) == Version("14.04") or \ Version(distro_version) == Version("14.10"): - return Ubuntu14Distro() + return Ubuntu14OSUtil() elif distro_full_name == "Snappy Ubuntu Core": - return UbuntuSnappyDistro() + return UbuntuSnappyOSUtil() else: - return UbuntuDistro() + return UbuntuOSUtil() if distro_name == "coreos": - return CoreOSDistro() + return CoreOSUtil() if distro_name == "suse": if distro_full_name=='SUSE Linux Enterprise Server' and \ Version(distro_version) < Version('12') or \ distro_full_name == 'openSUSE' and \ Version(distro_version) < Version('13.2'): - return SUSE11Distro() + return SUSE11OSUtil() else: - return SUSEDistro() + return SUSEOSUtil() elif distro_name == "debian": - return DebianDistro() + return DebianOSUtil() elif distro_name == "redhat" or distro_name == "centos" or \ distro_name == "oracle": if Version(distro_version) < Version("7"): - return Redhat6xDistro() + return Redhat6xOSUtil() else: - return RedhatDistro() + return RedhatOSUtil() elif distro_name == "freebsd": - return FreeBSDDistro() + return FreeBSDOSUtil() else: logger.warn("Unable to load distro implemetation for {0}.", distro_name) logger.warn("Use default distro implemetation instead.") - return DefaultDistro() + return DefaultOSUtil() diff --git a/azurelinuxagent/distro/freebsd/osutil.py b/azurelinuxagent/common/osutil/freebsd.py similarity index 96% rename from azurelinuxagent/distro/freebsd/osutil.py rename to azurelinuxagent/common/osutil/freebsd.py index 3dfb6fc..3d2febd 100644 --- a/azurelinuxagent/distro/freebsd/osutil.py +++ b/azurelinuxagent/common/osutil/freebsd.py @@ -16,11 +16,11 @@ # # Requires Python 2.4+ and Openssl 1.0+ -import azurelinuxagent.utils.shellutil as shellutil -import azurelinuxagent.utils.textutil as textutil -import azurelinuxagent.logger as logger -from azurelinuxagent.distro.default.osutil import DefaultOSUtil -from azurelinuxagent.exception import OSUtilError +import azurelinuxagent.common.utils.shellutil as shellutil +import azurelinuxagent.common.utils.textutil as textutil +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.exception import OSUtilError +from azurelinuxagent.common.osutil.default import DefaultOSUtil class FreeBSDOSUtil(DefaultOSUtil): diff --git a/azurelinuxagent/distro/redhat/osutil.py b/azurelinuxagent/common/osutil/redhat.py similarity index 87% rename from azurelinuxagent/distro/redhat/osutil.py rename to azurelinuxagent/common/osutil/redhat.py index 7f769a5..1001e7e 100644 --- a/azurelinuxagent/distro/redhat/osutil.py +++ b/azurelinuxagent/common/osutil/redhat.py @@ -26,15 +26,15 @@ import struct import fcntl import time import base64 -import azurelinuxagent.conf as conf -import azurelinuxagent.logger as logger -from azurelinuxagent.future import ustr, bytebuffer -from azurelinuxagent.exception import OSUtilError, CryptError -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil -import azurelinuxagent.utils.textutil as textutil -from azurelinuxagent.utils.cryptutil import CryptUtil -from azurelinuxagent.distro.default.osutil import DefaultOSUtil +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.future import ustr, bytebuffer +from azurelinuxagent.common.exception import OSUtilError, CryptError +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +import azurelinuxagent.common.utils.textutil as textutil +from azurelinuxagent.common.utils.cryptutil import CryptUtil +from azurelinuxagent.common.osutil.default import DefaultOSUtil class Redhat6xOSUtil(DefaultOSUtil): def __init__(self): diff --git a/azurelinuxagent/distro/suse/osutil.py b/azurelinuxagent/common/osutil/suse.py similarity index 89% rename from azurelinuxagent/distro/suse/osutil.py rename to azurelinuxagent/common/osutil/suse.py index 8d6f5bf..f0ed0c0 100644 --- a/azurelinuxagent/distro/suse/osutil.py +++ b/azurelinuxagent/common/osutil/suse.py @@ -25,12 +25,12 @@ import array import struct import fcntl import time -import azurelinuxagent.logger as logger -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil -import azurelinuxagent.utils.textutil as textutil -from azurelinuxagent.metadata import DISTRO_NAME, DISTRO_VERSION, DISTRO_FULL_NAME -from azurelinuxagent.distro.default.osutil import DefaultOSUtil +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +import azurelinuxagent.common.utils.textutil as textutil +from azurelinuxagent.common.version import DISTRO_NAME, DISTRO_VERSION, DISTRO_FULL_NAME +from azurelinuxagent.common.osutil.default import DefaultOSUtil class SUSE11OSUtil(DefaultOSUtil): def __init__(self): diff --git a/azurelinuxagent/distro/ubuntu/osutil.py b/azurelinuxagent/common/osutil/ubuntu.py similarity index 88% rename from azurelinuxagent/distro/ubuntu/osutil.py rename to azurelinuxagent/common/osutil/ubuntu.py index cc4b8ef..3cf669a 100644 --- a/azurelinuxagent/distro/ubuntu/osutil.py +++ b/azurelinuxagent/common/osutil/ubuntu.py @@ -25,11 +25,11 @@ import array import struct import fcntl import time -import azurelinuxagent.logger as logger -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil -import azurelinuxagent.utils.textutil as textutil -from azurelinuxagent.distro.default.osutil import DefaultOSUtil +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +import azurelinuxagent.common.utils.textutil as textutil +from azurelinuxagent.common.osutil.default import DefaultOSUtil class Ubuntu14OSUtil(DefaultOSUtil): def __init__(self): diff --git a/azurelinuxagent/distro/debian/loader.py b/azurelinuxagent/common/protocol/__init__.py similarity index 76% rename from azurelinuxagent/distro/debian/loader.py rename to azurelinuxagent/common/protocol/__init__.py index cc0c06f..fb7c273 100644 --- a/azurelinuxagent/distro/debian/loader.py +++ b/azurelinuxagent/common/protocol/__init__.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,8 +15,7 @@ # Requires Python 2.4+ and Openssl 1.0+ # - -def get_osutil(): - from azurelinuxagent.distro.debian.osutil import DebianOSUtil - return DebianOSUtil() +from azurelinuxagent.common.protocol.util import get_protocol_util, \ + OVF_FILE_NAME, \ + TAG_FILE_NAME diff --git a/azurelinuxagent/protocol/metadata.py b/azurelinuxagent/common/protocol/metadata.py similarity index 81% rename from azurelinuxagent/protocol/metadata.py rename to azurelinuxagent/common/protocol/metadata.py index 8a1656f..38d7645 100644 --- a/azurelinuxagent/protocol/metadata.py +++ b/azurelinuxagent/common/protocol/metadata.py @@ -20,15 +20,15 @@ import json import shutil import os import time -from azurelinuxagent.exception import ProtocolError, HttpError -from azurelinuxagent.future import httpclient, ustr -import azurelinuxagent.conf as conf -import azurelinuxagent.logger as logger -import azurelinuxagent.utils.restutil as restutil -import azurelinuxagent.utils.textutil as textutil -import azurelinuxagent.utils.fileutil as fileutil -from azurelinuxagent.utils.cryptutil import CryptUtil -from azurelinuxagent.protocol.restapi import * +from azurelinuxagent.common.exception import ProtocolError, HttpError +from azurelinuxagent.common.future import httpclient, ustr +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.utils.restutil as restutil +import azurelinuxagent.common.utils.textutil as textutil +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.common.utils.cryptutil import CryptUtil +from azurelinuxagent.common.protocol.restapi import * METADATA_ENDPOINT='169.254.169.254' APIVERSION='2015-05-01-preview' @@ -58,6 +58,8 @@ class MetadataProtocol(Protocol): self.apiversion, "&$expand=*") self.ext_uri = BASE_URI.format(self.endpoint, "extensionHandlers", self.apiversion, "&$expand=*") + self.vmagent_uri = BASE_URI.format(self.endpoint, "vmAgentVersions", + self.apiversion, "&$expand=*") self.provision_status_uri = BASE_URI.format(self.endpoint, "provisioningStatus", self.apiversion, "") @@ -140,6 +142,29 @@ class MetadataProtocol(Protocol): #TODO download and save certs return CertList() + def get_vmagent_manifests(self): + manifests = VMAgentManifestList() + data = self._get_data(self.vmagent_uri) + set_properties("vmAgentManifests", manifests.vmAgentManifests, data) + return manifests + + def get_vmagent_pkgs(self, vmagent_manifest): + #Agent package is the same with extension handler + vmagent_pkgs = ExtHandlerPackageList() + data = None + for manifest_uri in vmagent_manifest.versionsManifestUris: + try: + data = self._get_data(manifest_uri.uri) + break + except ProtocolError as e: + logger.warn("Failed to get vmagent versions: {0}", e) + logger.info("Retry getting vmagent versions") + if data is None: + raise ProtocolError(("Failed to get versions for vm agent: {0}" + "").format(vmagent_manifest.family)) + set_properties("vmAgentVersions", vmagent_pkgs, data) + return vmagent_pkgs + def get_ext_handlers(self): headers = { "x-ms-vmagent-public-x509-cert": self._get_trans_cert() diff --git a/azurelinuxagent/protocol/ovfenv.py b/azurelinuxagent/common/protocol/ovfenv.py similarity index 93% rename from azurelinuxagent/protocol/ovfenv.py rename to azurelinuxagent/common/protocol/ovfenv.py index de6791c..47571b2 100644 --- a/azurelinuxagent/protocol/ovfenv.py +++ b/azurelinuxagent/common/protocol/ovfenv.py @@ -23,11 +23,11 @@ import os import re import shutil import xml.dom.minidom as minidom -import azurelinuxagent.logger as logger -from azurelinuxagent.exception import ProtocolError -from azurelinuxagent.future import ustr -import azurelinuxagent.utils.fileutil as fileutil -from azurelinuxagent.utils.textutil import parse_doc, findall, find, findtext +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.exception import ProtocolError +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.common.utils.textutil import parse_doc, findall, find, findtext OVF_VERSION = "1.0" OVF_NAME_SPACE = "http://schemas.dmtf.org/ovf/environment/1" diff --git a/azurelinuxagent/protocol/restapi.py b/azurelinuxagent/common/protocol/restapi.py similarity index 90% rename from azurelinuxagent/protocol/restapi.py rename to azurelinuxagent/common/protocol/restapi.py index 2778dc4..c1ca64e 100644 --- a/azurelinuxagent/protocol/restapi.py +++ b/azurelinuxagent/common/protocol/restapi.py @@ -21,10 +21,10 @@ import copy import re import json import xml.dom.minidom -import azurelinuxagent.logger as logger -from azurelinuxagent.exception import ProtocolError, HttpError -from azurelinuxagent.future import ustr -import azurelinuxagent.utils.restutil as restutil +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.exception import ProtocolError, HttpError +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.utils.restutil as restutil def validata_param(name, val, expected_type): if val is None: @@ -102,6 +102,20 @@ class CertList(DataContract): def __init__(self): self.certificates = DataContractList(Cert) +#TODO: confirm vmagent manifest schema +class VMAgentManifestUri(DataContract): + def __init__(self, uri=None): + self.uri = uri + +class VMAgentManifest(DataContract): + def __init__(self, family=None): + self.family = family + self.versionsManifestUris = DataContractList(VMAgentManifestUri) + +class VMAgentManifestList(DataContract): + def __init__(self): + self.vmAgentManifests = DataContractList(VMAgentManifest) + class Extension(DataContract): def __init__(self, name=None, sequenceNumber=None, publicSettings=None, protectedSettings=None, certificateThumbprint=None): @@ -224,6 +238,12 @@ class Protocol(DataContract): def get_certs(self): raise NotImplementedError() + def get_vmagent_manifests(self): + raise NotImplementedError() + + def get_vmagent_pkgs(self): + raise NotImplementedError() + def get_ext_handlers(self): raise NotImplementedError() diff --git a/azurelinuxagent/distro/default/protocolUtil.py b/azurelinuxagent/common/protocol/util.py similarity index 67% rename from azurelinuxagent/distro/default/protocolUtil.py rename to azurelinuxagent/common/protocol/util.py index 34466cf..98adeed 100644 --- a/azurelinuxagent/distro/default/protocolUtil.py +++ b/azurelinuxagent/common/protocol/util.py @@ -21,16 +21,19 @@ import re import shutil import time import threading -import azurelinuxagent.conf as conf -import azurelinuxagent.logger as logger -from azurelinuxagent.exception import ProtocolError, OSUtilError, \ +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.exception import ProtocolError, OSUtilError, \ ProtocolNotFoundError, DhcpError -from azurelinuxagent.future import ustr -import azurelinuxagent.utils.fileutil as fileutil -from azurelinuxagent.protocol.ovfenv import OvfEnv -from azurelinuxagent.protocol.wire import WireProtocol -from azurelinuxagent.protocol.metadata import MetadataProtocol, METADATA_ENDPOINT -import azurelinuxagent.utils.shellutil as shellutil +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.utils.fileutil as fileutil +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 +import azurelinuxagent.common.utils.shellutil as shellutil OVF_FILE_NAME = "ovf-env.xml" @@ -46,15 +49,19 @@ PROBE_INTERVAL = 10 ENDPOINT_FILE_NAME = "WireServerEndpoint" +def get_protocol_util(): + return ProtocolUtil() + class ProtocolUtil(object): """ ProtocolUtil handles initialization for protocol instance. 2 protocol types are invoked, wire protocol and metadata protocols. """ - def __init__(self, distro): - self.distro = distro - self.protocol = None + def __init__(self): self.lock = threading.Lock() + self.protocol = None + self.osutil = get_osutil() + self.dhcp_handler = get_dhcp_handler() def copy_ovf_env(self): """ @@ -65,7 +72,7 @@ class ProtocolUtil(object): ovf_file_path_on_dvd = os.path.join(dvd_mount_point, OVF_FILE_NAME) tag_file_path_on_dvd = os.path.join(dvd_mount_point, TAG_FILE_NAME) try: - self.distro.osutil.mount_dvd() + self.osutil.mount_dvd() ovfxml = fileutil.read_file(ovf_file_path_on_dvd, remove_bom=True) ovfenv = OvfEnv(ovfxml) ovfxml = re.sub(".*?<", "*<", ovfxml) @@ -81,8 +88,8 @@ class ProtocolUtil(object): raise ProtocolError(ustr(e)) try: - self.distro.osutil.umount_dvd() - self.distro.osutil.eject_dvd() + self.osutil.umount_dvd() + self.osutil.eject_dvd() except OSUtilError as e: logger.warn(ustr(e)) @@ -114,23 +121,24 @@ class ProtocolUtil(object): raise OSUtilError(ustr(e)) def _detect_wire_protocol(self): - endpoint = self.distro.dhcp_handler.endpoint + endpoint = self.dhcp_handler.endpoint if endpoint is None: logger.info("WireServer endpoint is not found. Rerun dhcp handler") try: - self.distro.dhcp_handler.run() + self.dhcp_handler.run() except DhcpError as e: raise ProtocolError(ustr(e)) - endpoint = self.distro.dhcp_handler.endpoint + endpoint = self.dhcp_handler.endpoint try: protocol = WireProtocol(endpoint) protocol.detect() self._set_wireserver_endpoint(endpoint) + self.save_protocol("WireProtocol") return protocol except ProtocolError as e: logger.info("WireServer is not responding. Reset endpoint") - self.distro.dhcp_handler.endpoint = None + self.dhcp_handler.endpoint = None raise e def _detect_metadata_protocol(self): @@ -138,7 +146,9 @@ class ProtocolUtil(object): protocol.detect() #Only allow root access METADATA_ENDPOINT - self.distro.osutil.set_admin_access_to_ip(METADATA_ENDPOINT) + self.osutil.set_admin_access_to_ip(METADATA_ENDPOINT) + + self.save_protocol("MetadataProtocol") return protocol @@ -146,9 +156,8 @@ class ProtocolUtil(object): """ Probe protocol endpoints in turn. """ - protocol_file_path = os.path.join(conf.get_lib_dir(), PROTOCOL_FILE_NAME) - if os.path.isfile(protocol_file_path): - os.remove(protocol_file_path) + self.clear_protocol() + for retry in range(0, MAX_RETRY): for protocol in protocols: try: @@ -174,7 +183,7 @@ class ProtocolUtil(object): protocol_file_path = os.path.join(conf.get_lib_dir(), PROTOCOL_FILE_NAME) if not os.path.isfile(protocol_file_path): - raise ProtocolError("No protocl found") + raise ProtocolNotFoundError("No protocol found") protocol_name = fileutil.read_file(protocol_file_path) if protocol_name == "WireProtocol": @@ -186,23 +195,61 @@ class ProtocolUtil(object): raise ProtocolNotFoundError(("Unknown protocol: {0}" "").format(protocol_name)) - def detect_protocol(self): + def save_protocol(self, protocol_name): + """ + Save protocol endpoint + """ + protocol_file_path = os.path.join(conf.get_lib_dir(), PROTOCOL_FILE_NAME) + try: + fileutil.write_file(protocol_file_path, protocol_name) + except IOError as e: + logger.error("Failed to save protocol endpoint: {0}", e) + + + def clear_protocol(self): + """ + Cleanup previous saved endpoint. + """ + logger.info("Clean protocol") + self.protocol = None + protocol_file_path = os.path.join(conf.get_lib_dir(), PROTOCOL_FILE_NAME) + if not os.path.isfile(protocol_file_path): + return + + try: + os.remove(protocol_file_path) + except IOError as e: + logger.error("Failed to clear protocol endpoint: {0}", e) + + def get_protocol(self): """ Detect protocol by endpoints :returns: protocol instance """ - logger.info("Detect protocol endpoints") - protocols = ["WireProtocol", "MetadataProtocol"] self.lock.acquire() + try: - if self.protocol is None: - self.protocol = self._detect_protocol(protocols) + if self.protocol is not None: + return self.protocol + + try: + self.protocol = self._get_protocol() + return self.protocol + except ProtocolNotFoundError: + pass + + logger.info("Detect protocol endpoints") + protocols = ["WireProtocol", "MetadataProtocol"] + self.protocol = self._detect_protocol(protocols) + return self.protocol + finally: self.lock.release() - def detect_protocol_by_file(self): + + def get_protocol_by_file(self): """ Detect protocol by tag file. @@ -211,33 +258,27 @@ class ProtocolUtil(object): :returns: protocol instance """ - logger.info("Detect protocol by file") self.lock.acquire() + try: + if self.protocol is not None: + return self.protocol + + try: + self.protocol = self._get_protocol() + return self.protocol + except ProtocolNotFoundError: + pass + + logger.info("Detect protocol by file") tag_file_path = os.path.join(conf.get_lib_dir(), TAG_FILE_NAME) - if self.protocol is None: - protocols = [] - if os.path.isfile(tag_file_path): - protocols.append("MetadataProtocol") - else: - protocols.append("WireProtocol") - self.protocol = self._detect_protocol(protocols) - finally: - self.lock.release() - return self.protocol - - def get_protocol(self): - """ - Get protocol instance based on previous detecting result. - - :returns protocol instance - """ - self.lock.acquire() - try: - if self.protocol is None: - self.protocol = self._get_protocol() + protocols = [] + if os.path.isfile(tag_file_path): + protocols.append("MetadataProtocol") + else: + protocols.append("WireProtocol") + self.protocol = self._detect_protocol(protocols) return self.protocol + finally: self.lock.release() - return self.protocol - diff --git a/azurelinuxagent/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py similarity index 95% rename from azurelinuxagent/protocol/wire.py rename to azurelinuxagent/common/protocol/wire.py index b9c93cf..815fb6b 100644 --- a/azurelinuxagent/protocol/wire.py +++ b/azurelinuxagent/common/protocol/wire.py @@ -22,19 +22,19 @@ import re import time import traceback import xml.sax.saxutils as saxutils -import azurelinuxagent.conf as conf -import azurelinuxagent.logger as logger -from azurelinuxagent.exception import ProtocolError, HttpError, \ +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.exception import ProtocolError, HttpError, \ ProtocolNotFoundError -from azurelinuxagent.future import ustr, httpclient, bytebuffer -import azurelinuxagent.utils.restutil as restutil -from azurelinuxagent.utils.textutil import parse_doc, findall, find, findtext, \ +from azurelinuxagent.common.future import ustr, httpclient, bytebuffer +import azurelinuxagent.common.utils.restutil as restutil +from azurelinuxagent.common.utils.textutil import parse_doc, findall, find, findtext, \ getattrib, gettext, remove_bom, \ get_bytes_from_pem -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil -from azurelinuxagent.utils.cryptutil import CryptUtil -from azurelinuxagent.protocol.restapi import * +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +from azurelinuxagent.common.utils.cryptutil import CryptUtil +from azurelinuxagent.common.protocol.restapi import * VERSION_INFO_URI = "http://{0}/?comp=versions" GOAL_STATE_URI = "http://{0}/machine/?comp=goalstate" @@ -102,6 +102,18 @@ class WireProtocol(Protocol): certificates = self.client.get_certs() return certificates.cert_list + def get_vmagent_manifests(self): + #Update goal state to get latest extensions config + self.client.update_goal_state() + goal_state = self.client.get_goal_state() + ext_conf = self.client.get_ext_conf() + return ext_conf.vmagent_manifests, goal_state.incarnation + + def get_vmagent_pkgs(self, vmagent_manifest): + goal_state = self.client.get_goal_state() + man = self.client.get_gafamily_manifest(vmagent_manifest, goal_state) + return man.pkg_list + def get_ext_handlers(self): logger.verb("Get extension handler config") #Update goal state to get latest extensions config @@ -711,6 +723,14 @@ class WireClient(object): self.save_cache(local_file, xml_text) return ExtensionManifest(xml_text) + def get_gafamily_manifest(self, vmagent_manifest, goal_state): + local_file = MANIFEST_FILE_NAME.format(vmagent_manifest.family, + goal_state.incarnation) + local_file = os.path.join(conf.get_lib_dir(), local_file) + xml_text = self.fetch_manifest(vmagent_manifest.versionsManifestUris) + fileutil.write_file(local_file, xml_text) + return ExtensionManifest(xml_text) + def check_wire_protocol_version(self): uri = VERSION_INFO_URI.format(self.endpoint) version_info_xml = self.fetch_config(uri, None) @@ -1052,6 +1072,7 @@ class ExtensionsConfig(object): def __init__(self, xml_text): logger.verb("Load ExtensionsConfig.xml") self.ext_handlers = ExtHandlerList() + self.vmagent_manifests = VMAgentManifestList() self.status_upload_blob = None if xml_text is not None: self.parse(xml_text) @@ -1061,6 +1082,21 @@ class ExtensionsConfig(object): Write configuration to file ExtensionsConfig.xml. """ xml_doc = parse_doc(xml_text) + + ga_families_list = find(xml_doc, "GAFamilies") + ga_families = findall(ga_families_list, "GAFamily") + + for ga_family in ga_families: + family = findtext(ga_family, "Name") + uris_list = find(ga_family, "Uris") + uris = findall(uris_list, "Uri") + manifest = VMAgentManifest() + manifest.family = family + for uri in uris: + manifestUri = VMAgentManifestUri(uri=gettext(uri)) + manifest.versionsManifestUris.append(manifestUri) + self.vmagent_manifests.vmAgentManifests.append(manifest) + plugins_list = find(xml_doc, "Plugins") plugins = findall(plugins_list, "Plugin") plugin_settings_list = find(xml_doc, "PluginSettings") diff --git a/azurelinuxagent/distro/freebsd/__init__.py b/azurelinuxagent/common/utils/__init__.py similarity index 95% rename from azurelinuxagent/distro/freebsd/__init__.py rename to azurelinuxagent/common/utils/__init__.py index d9b82f5..1ea2f38 100644 --- a/azurelinuxagent/distro/freebsd/__init__.py +++ b/azurelinuxagent/common/utils/__init__.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/azurelinuxagent/utils/cryptutil.py b/azurelinuxagent/common/utils/cryptutil.py similarity index 96% rename from azurelinuxagent/utils/cryptutil.py rename to azurelinuxagent/common/utils/cryptutil.py index 5ee5637..b35bda0 100644 --- a/azurelinuxagent/utils/cryptutil.py +++ b/azurelinuxagent/common/utils/cryptutil.py @@ -19,9 +19,9 @@ import base64 import struct -from azurelinuxagent.future import ustr, bytebuffer -from azurelinuxagent.exception import CryptError -import azurelinuxagent.utils.shellutil as shellutil +from azurelinuxagent.common.future import ustr, bytebuffer +from azurelinuxagent.common.exception import CryptError +import azurelinuxagent.common.utils.shellutil as shellutil class CryptUtil(object): def __init__(self, openssl_cmd): diff --git a/azurelinuxagent/utils/fileutil.py b/azurelinuxagent/common/utils/fileutil.py similarity index 96% rename from azurelinuxagent/utils/fileutil.py rename to azurelinuxagent/common/utils/fileutil.py index 82fd973..24842d0 100644 --- a/azurelinuxagent/utils/fileutil.py +++ b/azurelinuxagent/common/utils/fileutil.py @@ -26,9 +26,9 @@ import re import shutil import pwd import tempfile -import azurelinuxagent.logger as logger -from azurelinuxagent.future import ustr -import azurelinuxagent.utils.textutil as textutil +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.utils.textutil as textutil def read_file(filepath, asbin=False, remove_bom=False, encoding='utf-8'): """ diff --git a/azurelinuxagent/utils/restutil.py b/azurelinuxagent/common/utils/restutil.py similarity index 96% rename from azurelinuxagent/utils/restutil.py rename to azurelinuxagent/common/utils/restutil.py index 2e8b0be..71c88c1 100644 --- a/azurelinuxagent/utils/restutil.py +++ b/azurelinuxagent/common/utils/restutil.py @@ -21,10 +21,10 @@ import time import platform import os import subprocess -import azurelinuxagent.conf as conf -import azurelinuxagent.logger as logger -from azurelinuxagent.exception import HttpError -from azurelinuxagent.future import httpclient, urlparse +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.exception import HttpError +from azurelinuxagent.common.future import httpclient, urlparse """ REST api util functions diff --git a/azurelinuxagent/utils/shellutil.py b/azurelinuxagent/common/utils/shellutil.py similarity index 97% rename from azurelinuxagent/utils/shellutil.py rename to azurelinuxagent/common/utils/shellutil.py index 98871a1..8632758 100644 --- a/azurelinuxagent/utils/shellutil.py +++ b/azurelinuxagent/common/utils/shellutil.py @@ -20,8 +20,8 @@ import platform import os import subprocess -from azurelinuxagent.future import ustr -import azurelinuxagent.logger as logger +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.logger as logger if not hasattr(subprocess,'check_output'): def check_output(*popenargs, **kwargs): diff --git a/azurelinuxagent/utils/textutil.py b/azurelinuxagent/common/utils/textutil.py similarity index 100% rename from azurelinuxagent/utils/textutil.py rename to azurelinuxagent/common/utils/textutil.py diff --git a/azurelinuxagent/metadata.py b/azurelinuxagent/common/version.py similarity index 95% rename from azurelinuxagent/metadata.py rename to azurelinuxagent/common/version.py index 42ccc68..5d49655 100644 --- a/azurelinuxagent/metadata.py +++ b/azurelinuxagent/common/version.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,8 +19,8 @@ import os import re import platform import sys -import azurelinuxagent.utils.fileutil as fileutil -from azurelinuxagent.future import ustr +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.common.future import ustr def get_distro(): if 'FreeBSD' in platform.system(): diff --git a/azurelinuxagent/daemon/__init__.py b/azurelinuxagent/daemon/__init__.py new file mode 100644 index 0000000..979e01b --- /dev/null +++ b/azurelinuxagent/daemon/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +from azurelinuxagent.daemon.main import get_daemon_handler diff --git a/azurelinuxagent/distro/default/env.py b/azurelinuxagent/daemon/env.py similarity index 77% rename from azurelinuxagent/distro/default/env.py rename to azurelinuxagent/daemon/env.py index be47eaf..9d18026 100644 --- a/azurelinuxagent/distro/default/env.py +++ b/azurelinuxagent/daemon/env.py @@ -21,8 +21,13 @@ import os import socket import threading import time -import azurelinuxagent.logger as logger -import azurelinuxagent.conf as conf +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.osutil import get_osutil +from azurelinuxagent.common.dhcp import get_dhcp_handler + +def get_env_handler(): + return EnvHandler() class EnvHandler(object): """ @@ -32,8 +37,9 @@ class EnvHandler(object): Monitor scsi disk. If new scsi disk found, set timeout """ - def __init__(self, distro): - self.distro = distro + def __init__(self): + self.osutil = get_osutil() + self.dhcp_handler = get_dhcp_handler() self.stopped = True self.hostname = None self.dhcpid = None @@ -46,9 +52,9 @@ class EnvHandler(object): self.stopped = False logger.info("Start env monitor service.") - self.distro.dhcp_handler.conf_routes() + self.dhcp_handler.conf_routes() self.hostname = socket.gethostname() - self.dhcpid = self.distro.osutil.get_dhcp_pid() + self.dhcpid = self.osutil.get_dhcp_pid() self.server_thread = threading.Thread(target = self.monitor) self.server_thread.setDaemon(True) self.server_thread.start() @@ -59,10 +65,10 @@ class EnvHandler(object): If dhcp clinet process re-start has occurred, reset routes. """ while not self.stopped: - self.distro.osutil.remove_rules_files() + self.osutil.remove_rules_files() timeout = conf.get_root_device_scsi_timeout() if timeout is not None: - self.distro.osutil.set_scsi_disks_timeout(timeout) + self.osutil.set_scsi_disks_timeout(timeout) if conf.get_monitor_hostname(): self.handle_hostname_update() self.handle_dhclient_restart() @@ -73,25 +79,25 @@ class EnvHandler(object): if curr_hostname != self.hostname: logger.info("EnvMonitor: Detected host name change: {0} -> {1}", self.hostname, curr_hostname) - self.distro.osutil.set_hostname(curr_hostname) - self.distro.osutil.publish_hostname(curr_hostname) + self.osutil.set_hostname(curr_hostname) + self.osutil.publish_hostname(curr_hostname) self.hostname = curr_hostname def handle_dhclient_restart(self): if self.dhcpid is None: logger.warn("Dhcp client is not running. ") - self.dhcpid = self.distro.osutil.get_dhcp_pid() + self.dhcpid = self.osutil.get_dhcp_pid() return #The dhcp process hasn't changed since last check - if self.distro.osutil.check_pid_alive(self.dhcpid.strip()): + if self.osutil.check_pid_alive(self.dhcpid.strip()): return - newpid = self.distro.osutil.get_dhcp_pid() + newpid = self.osutil.get_dhcp_pid() if newpid is not None and newpid != self.dhcpid: logger.info("EnvMonitor: Detected dhcp client restart. " "Restoring routing table.") - self.distro.dhcp_handler.conf_routes() + self.dhcp_handler.conf_routes() self.dhcpid = newpid def stop(self): diff --git a/azurelinuxagent/distro/default/daemon.py b/azurelinuxagent/daemon/main.py similarity index 57% rename from azurelinuxagent/distro/default/daemon.py rename to azurelinuxagent/daemon/main.py index aa7f4e6..3539732 100644 --- a/azurelinuxagent/distro/default/daemon.py +++ b/azurelinuxagent/daemon/main.py @@ -21,24 +21,43 @@ import os import time import sys import traceback -import azurelinuxagent.conf as conf -import azurelinuxagent.logger as logger -from azurelinuxagent.future import ustr -from azurelinuxagent.event import add_event, WALAEventOperation -from azurelinuxagent.exception import ProtocolError -from azurelinuxagent.metadata import AGENT_LONG_NAME, AGENT_VERSION, \ +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.future import ustr +from azurelinuxagent.common.event import add_event, WALAEventOperation +from azurelinuxagent.common.exception import ProtocolError +from azurelinuxagent.common.version import AGENT_LONG_NAME, AGENT_VERSION, \ DISTRO_NAME, DISTRO_VERSION, \ DISTRO_FULL_NAME, PY_VERSION_MAJOR, \ PY_VERSION_MINOR, PY_VERSION_MICRO -import azurelinuxagent.event as event -import azurelinuxagent.utils.fileutil as fileutil +import azurelinuxagent.common.event as event +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.common.osutil import get_osutil +from azurelinuxagent.common.protocol import get_protocol_util +from azurelinuxagent.daemon.scvmm import get_scvmm_handler +from azurelinuxagent.daemon.resourcedisk import get_resourcedisk_handler +from azurelinuxagent.daemon.monitor import get_monitor_handler +from azurelinuxagent.daemon.env import get_env_handler +from azurelinuxagent.pa.provision import get_provision_handler +from azurelinuxagent.ga.update import get_update_handler +def get_daemon_handler(): + return DaemonHandler() class DaemonHandler(object): - def __init__(self, distro): - self.distro = distro + """ + Main thread of daemon. It will invoke other threads to do actual work + """ + def __init__(self): self.running = True - + self.osutil = get_osutil() + self.protocol_util = get_protocol_util() + self.scvmm_handler = get_scvmm_handler() + self.resourcedisk_handler = get_resourcedisk_handler() + self.monitor_handler = get_monitor_handler() + self.env_handler = get_env_handler() + self.provision_handler = get_provision_handler() + self.update_handler = get_update_handler() def run(self): logger.info("{0} Version:{1}", AGENT_LONG_NAME, AGENT_VERSION) @@ -58,6 +77,7 @@ class DaemonHandler(object): logger.info("Sleep 15 seconds and restart daemon") time.sleep(15) + def check_pid(self): """Check whether daemon is already running""" pid = None @@ -65,7 +85,7 @@ class DaemonHandler(object): if os.path.isfile(pid_file): pid = fileutil.read_file(pid_file) - if self.distro.osutil.check_pid_alive(pid): + if self.osutil.check_pid_alive(pid): logger.info("Daemon is already running: {0}", pid) sys.exit(0) @@ -79,25 +99,19 @@ class DaemonHandler(object): os.chdir(conf.get_lib_dir()) if conf.get_detect_scvmm_env(): - if self.distro.scvmm_handler.run(): - return - - self.distro.provision_handler.run() + self.scvmm_handler.run() if conf.get_resourcedisk_format(): - self.distro.resource_disk_handler.run() - - try: - protocol = self.distro.protocol_util.detect_protocol() - except ProtocolError as e: - logger.error("Failed to detect protocol, exit", e) - return + self.resourcedisk_handler.run() - self.distro.event_handler.run() - self.distro.env_handler.run() + self.protocol_util.clear_protocol() + + self.provision_handler.run() + + self.monitor_handler.run() + + self.env_handler.run() while self.running: - #Handle extensions - self.distro.ext_handlers_handler.run() + self.update_handler.run() time.sleep(25) - diff --git a/azurelinuxagent/distro/default/monitor.py b/azurelinuxagent/daemon/monitor.py similarity index 84% rename from azurelinuxagent/distro/default/monitor.py rename to azurelinuxagent/daemon/monitor.py index 3b26c9a..40782fe 100644 --- a/azurelinuxagent/distro/default/monitor.py +++ b/azurelinuxagent/daemon/monitor.py @@ -24,19 +24,23 @@ import time import datetime import threading import platform -import azurelinuxagent.logger as logger -import azurelinuxagent.conf as conf -from azurelinuxagent.event import WALAEventOperation, add_event -from azurelinuxagent.exception import EventError, ProtocolError, OSUtilError -from azurelinuxagent.future import ustr -from azurelinuxagent.utils.textutil import parse_doc, findall, find, getattrib -from azurelinuxagent.protocol.restapi import TelemetryEventParam, \ +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.event import WALAEventOperation, add_event +from azurelinuxagent.common.exception import EventError, ProtocolError, \ + OSUtilError +from azurelinuxagent.common.future import ustr +from azurelinuxagent.common.utils.textutil import parse_doc, findall, find, \ + getattrib +from azurelinuxagent.common.protocol.restapi import TelemetryEventParam, \ TelemetryEventList, \ TelemetryEvent, \ set_properties, get_properties -from azurelinuxagent.metadata import DISTRO_NAME, DISTRO_VERSION, \ +from azurelinuxagent.common.version import DISTRO_NAME, DISTRO_VERSION, \ DISTRO_CODE_NAME, AGENT_LONG_VERSION +from azurelinuxagent.common.osutil import get_osutil +from azurelinuxagent.common.protocol import get_protocol_util def parse_event(data_str): try: @@ -76,10 +80,13 @@ def parse_json_event(data_str): set_properties("TelemetryEvent", event, data) return event +def get_monitor_handler(): + return MonitorHandler() class MonitorHandler(object): - def __init__(self, distro): - self.distro = distro + def __init__(self): + self.osutil = get_osutil() + self.protocol_util = get_protocol_util() self.sysinfo = [] def run(self): @@ -99,15 +106,15 @@ class MonitorHandler(object): self.sysinfo.append(TelemetryEventParam("GAVersion", AGENT_LONG_VERSION)) try: - ram = self.distro.osutil.get_total_mem() - processors = self.distro.osutil.get_processor_cores() + ram = self.osutil.get_total_mem() + processors = self.osutil.get_processor_cores() self.sysinfo.append(TelemetryEventParam("RAM", ram)) self.sysinfo.append(TelemetryEventParam("Processors", processors)) except OSUtilError as e: logger.warn("Failed to get system info: {0}", e) try: - protocol = self.distro.protocol_util.get_protocol() + protocol = self.protocol_util.get_protocol() vminfo = protocol.get_vminfo() self.sysinfo.append(TelemetryEventParam("VMName", vminfo.vmName)) @@ -161,7 +168,7 @@ class MonitorHandler(object): return try: - protocol = self.distro.protocol_util.get_protocol() + protocol = self.protocol_util.get_protocol() protocol.report_event(event_list) except ProtocolError as e: logger.error("{0}", e) diff --git a/azurelinuxagent/daemon/resourcedisk/__init__.py b/azurelinuxagent/daemon/resourcedisk/__init__.py new file mode 100644 index 0000000..021cecd --- /dev/null +++ b/azurelinuxagent/daemon/resourcedisk/__init__.py @@ -0,0 +1,20 @@ +# Microsoft Azure Linux Agent +# +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +from azurelinuxagent.daemon.resourcedisk.factory import get_resourcedisk_handler diff --git a/azurelinuxagent/distro/default/resourceDisk.py b/azurelinuxagent/daemon/resourcedisk/default.py similarity index 91% rename from azurelinuxagent/distro/default/resourceDisk.py rename to azurelinuxagent/daemon/resourcedisk/default.py index a6c5232..d435e30 100644 --- a/azurelinuxagent/distro/default/resourceDisk.py +++ b/azurelinuxagent/daemon/resourcedisk/default.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,13 +18,14 @@ import os import re import threading -import azurelinuxagent.logger as logger -from azurelinuxagent.future import ustr -import azurelinuxagent.conf as conf -from azurelinuxagent.event import add_event, WALAEventOperation -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil -from azurelinuxagent.exception import ResourceDiskError +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.event import add_event, WALAEventOperation +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +from azurelinuxagent.common.exception import ResourceDiskError +from azurelinuxagent.common.osutil import get_osutil DATALOSS_WARNING_FILE_NAME="DATALOSS_WARNING_README.txt" DATA_LOSS_WARNING="""\ @@ -40,8 +39,8 @@ For additional details to please refer to the MSDN documentation at : http://msd """ class ResourceDiskHandler(object): - def __init__(self, distro): - self.distro = distro + def __init__(self): + self.osutil = get_osutil() def start_activate_resource_disk(self): disk_thread = threading.Thread(target = self.run) @@ -81,13 +80,13 @@ class ResourceDiskHandler(object): logger.error("Failed to enable swap {0}", e) def mount_resource_disk(self, mount_point, fs): - device = self.distro.osutil.device_for_ide_port(1) + device = self.osutil.device_for_ide_port(1) if device is None: raise ResourceDiskError("unable to detect disk topology") device = "/dev/" + device mountlist = shellutil.run_get_output("mount")[1] - existing = self.distro.osutil.get_mount_point(mountlist, device) + existing = self.osutil.get_mount_point(mountlist, device) if(existing): logger.info("Resource disk {0}1 is already mounted", device) diff --git a/azurelinuxagent/daemon/resourcedisk/factory.py b/azurelinuxagent/daemon/resourcedisk/factory.py new file mode 100644 index 0000000..76e5a23 --- /dev/null +++ b/azurelinuxagent/daemon/resourcedisk/factory.py @@ -0,0 +1,33 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.utils.textutil import Version +from azurelinuxagent.common.version import DISTRO_NAME, \ + DISTRO_VERSION, \ + DISTRO_FULL_NAME +from .default import ResourceDiskHandler +from .freebsd import FreeBSDResourceDiskHandler + +def get_resourcedisk_handler(distro_name=DISTRO_NAME, + distro_version=DISTRO_VERSION, + distro_full_name=DISTRO_FULL_NAME): + if distro_name == "freebsd": + return FreeBSDResourceDiskHandler() + + return ResourceDiskHandler() + diff --git a/azurelinuxagent/distro/freebsd/resourceDisk.py b/azurelinuxagent/daemon/resourcedisk/freebsd.py similarity index 90% rename from azurelinuxagent/distro/freebsd/resourceDisk.py rename to azurelinuxagent/daemon/resourcedisk/freebsd.py index aefdff1..36a3ac9 100644 --- a/azurelinuxagent/distro/freebsd/resourceDisk.py +++ b/azurelinuxagent/daemon/resourcedisk/freebsd.py @@ -16,12 +16,11 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -import azurelinuxagent.logger as logger -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil -from azurelinuxagent.distro.default.resourceDisk import ResourceDiskHandler -from azurelinuxagent.exception import ResourceDiskError - +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +from azurelinuxagent.common.exception import ResourceDiskError +from azurelinuxagent.daemon.resourcedisk.default import ResourceDiskHandler class FreeBSDResourceDiskHandler(ResourceDiskHandler): """ @@ -35,8 +34,8 @@ class FreeBSDResourceDiskHandler(ResourceDiskHandler): 1. MBR: The resource disk partition is /dev/da1s1 2. GPT: The resource disk partition is /dev/da1p2, /dev/da1p1 is for reserved usage. """ - def __init__(self, distro): - super(FreeBSDResourceDiskHandler, self).__init__(distro) + def __init__(self): + super(FreeBSDResourceDiskHandler, self).__init__() @staticmethod def parse_gpart_list(data): @@ -95,7 +94,7 @@ class FreeBSDResourceDiskHandler(ResourceDiskHandler): # 3. Mount partition mount_list = shellutil.run_get_output("mount")[1] - existing = self.distro.osutil.get_mount_point(mount_list, partition) + existing = self.osutil.get_mount_point(mount_list, partition) if existing: logger.info("Resource disk {0} is already mounted", partition) diff --git a/azurelinuxagent/distro/default/scvmm.py b/azurelinuxagent/daemon/scvmm.py similarity index 64% rename from azurelinuxagent/distro/default/scvmm.py rename to azurelinuxagent/daemon/scvmm.py index 4d083b4..0df1845 100644 --- a/azurelinuxagent/distro/default/scvmm.py +++ b/azurelinuxagent/daemon/scvmm.py @@ -18,31 +18,44 @@ # import os +import sys import subprocess -import azurelinuxagent.logger as logger +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.osutil import get_osutil VMM_CONF_FILE_NAME = "linuxosconfiguration.xml" VMM_STARTUP_SCRIPT_NAME= "install" +def get_scvmm_handler(): + return ScvmmHandler() + class ScvmmHandler(object): - def __init__(self, distro): - self.distro = distro + def __init__(self): + self.osutil = get_osutil() def detect_scvmm_env(self): logger.info("Detecting Microsoft System Center VMM Environment") - self.distro.osutil.mount_dvd(max_retry=1, chk_err=False) - mount_point = self.distro.osutil.get_dvd_mount_point() + self.osutil.mount_dvd(max_retry=1, chk_err=False) + mount_point = conf.get_dvd_mount_point() found = os.path.isfile(os.path.join(mount_point, VMM_CONF_FILE_NAME)) if found: self.start_scvmm_agent() else: - self.distro.osutil.umount_dvd(chk_err=False) + self.osutil.umount_dvd(chk_err=False) return found def start_scvmm_agent(self): logger.info("Starting Microsoft System Center VMM Initialization " "Process") - mount_point = self.distro.osutil.get_dvd_mount_point() + mount_point = conf.get_dvd_mount_point() startup_script = os.path.join(mount_point, VMM_STARTUP_SCRIPT_NAME) - subprocess.Popen(["/bin/bash", startup_script, "-p " + mount_point]) - + devnull = open(os.devnull, 'w') + subprocess.Popen(["/bin/bash", startup_script, "-p " + mount_point], + stdout=devnull, stderr=devnull) + + def run(self): + if self.detect_scvmm_env(): + self.start_scvmm_agent() + logger.info("Exiting") + sys.exit(0) diff --git a/azurelinuxagent/distro/coreos/distro.py b/azurelinuxagent/distro/coreos/distro.py deleted file mode 100644 index 04c7bff..0000000 --- a/azurelinuxagent/distro/coreos/distro.py +++ /dev/null @@ -1,29 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - -from azurelinuxagent.distro.default.distro import DefaultDistro -from azurelinuxagent.distro.coreos.osutil import CoreOSUtil -from azurelinuxagent.distro.coreos.deprovision import CoreOSDeprovisionHandler - -class CoreOSDistro(DefaultDistro): - def __init__(self): - super(CoreOSDistro, self).__init__() - self.osutil = CoreOSUtil() - self.deprovision_handler = CoreOSDeprovisionHandler(self) - diff --git a/azurelinuxagent/distro/debian/distro.py b/azurelinuxagent/distro/debian/distro.py deleted file mode 100644 index 01f4e3e..0000000 --- a/azurelinuxagent/distro/debian/distro.py +++ /dev/null @@ -1,27 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - -from azurelinuxagent.distro.default.distro import DefaultDistro -from azurelinuxagent.distro.debian.osutil import DebianOSUtil - -class DebianDistro(DefaultDistro): - def __init__(self): - super(DebianDistro, self).__init__() - self.osutil = DebianOSUtil() - diff --git a/azurelinuxagent/distro/default/distro.py b/azurelinuxagent/distro/default/distro.py deleted file mode 100644 index ca0d77e..0000000 --- a/azurelinuxagent/distro/default/distro.py +++ /dev/null @@ -1,51 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - -from azurelinuxagent.conf import ConfigurationProvider -from azurelinuxagent.distro.default.osutil import DefaultOSUtil -from azurelinuxagent.distro.default.daemon import DaemonHandler -from azurelinuxagent.distro.default.init import InitHandler -from azurelinuxagent.distro.default.monitor import MonitorHandler -from azurelinuxagent.distro.default.dhcp import DhcpHandler -from azurelinuxagent.distro.default.protocolUtil import ProtocolUtil -from azurelinuxagent.distro.default.scvmm import ScvmmHandler -from azurelinuxagent.distro.default.env import EnvHandler -from azurelinuxagent.distro.default.provision import ProvisionHandler -from azurelinuxagent.distro.default.resourceDisk import ResourceDiskHandler -from azurelinuxagent.distro.default.extension import ExtHandlersHandler -from azurelinuxagent.distro.default.deprovision import DeprovisionHandler - -class DefaultDistro(object): - """ - """ - def __init__(self): - self.osutil = DefaultOSUtil() - self.protocol_util = ProtocolUtil(self) - - self.init_handler = InitHandler(self) - self.daemon_handler = DaemonHandler(self) - self.event_handler = MonitorHandler(self) - self.dhcp_handler = DhcpHandler(self) - self.scvmm_handler = ScvmmHandler(self) - self.env_handler = EnvHandler(self) - self.provision_handler = ProvisionHandler(self) - self.resource_disk_handler = ResourceDiskHandler(self) - self.ext_handlers_handler = ExtHandlersHandler(self) - self.deprovision_handler = DeprovisionHandler(self) - diff --git a/azurelinuxagent/distro/default/init.py b/azurelinuxagent/distro/default/init.py deleted file mode 100644 index c703e87..0000000 --- a/azurelinuxagent/distro/default/init.py +++ /dev/null @@ -1,53 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - -import os -import azurelinuxagent.conf as conf -import azurelinuxagent.logger as logger -import azurelinuxagent.event as event - - -class InitHandler(object): - def __init__(self, distro): - self.distro = distro - - def run(self, verbose): - #Init stdout log - level = logger.LogLevel.VERBOSE if verbose else logger.LogLevel.INFO - logger.add_logger_appender(logger.AppenderType.STDOUT, level) - - #Init config - conf_file_path = self.distro.osutil.get_agent_conf_file_path() - conf.load_conf_from_file(conf_file_path) - - #Init log - verbose = verbose or conf.get_logs_verbose() - level = logger.LogLevel.VERBOSE if verbose else logger.LogLevel.INFO - logger.add_logger_appender(logger.AppenderType.FILE, level, - path="/var/log/waagent.log") - logger.add_logger_appender(logger.AppenderType.CONSOLE, level, - path="/dev/console") - - #Init event reporter - event_dir = os.path.join(conf.get_lib_dir(), "events") - event.init_event_logger(event_dir) - event.enable_unhandled_err_dump("WALA") - - - diff --git a/azurelinuxagent/distro/freebsd/distro.py b/azurelinuxagent/distro/freebsd/distro.py deleted file mode 100644 index a889b53..0000000 --- a/azurelinuxagent/distro/freebsd/distro.py +++ /dev/null @@ -1,29 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - -from azurelinuxagent.distro.default.distro import DefaultDistro -from azurelinuxagent.distro.freebsd.resourceDisk import FreeBSDResourceDiskHandler -from azurelinuxagent.distro.freebsd.osutil import FreeBSDOSUtil - - -class FreeBSDDistro(DefaultDistro): - def __init__(self): - super(FreeBSDDistro, self).__init__() - self.osutil = FreeBSDOSUtil() - self.resource_disk_handler = FreeBSDResourceDiskHandler(self) diff --git a/azurelinuxagent/distro/redhat/__init__.py b/azurelinuxagent/distro/redhat/__init__.py deleted file mode 100644 index d9b82f5..0000000 --- a/azurelinuxagent/distro/redhat/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - diff --git a/azurelinuxagent/distro/redhat/distro.py b/azurelinuxagent/distro/redhat/distro.py deleted file mode 100644 index c9278b8..0000000 --- a/azurelinuxagent/distro/redhat/distro.py +++ /dev/null @@ -1,31 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - -from azurelinuxagent.distro.default.distro import DefaultDistro -from azurelinuxagent.distro.redhat.osutil import RedhatOSUtil, Redhat6xOSUtil - -class Redhat6xDistro(DefaultDistro): - def __init__(self): - super(Redhat6xDistro, self).__init__() - self.osutil = Redhat6xOSUtil() - -class RedhatDistro(DefaultDistro): - def __init__(self): - super(RedhatDistro, self).__init__() - self.osutil = RedhatOSUtil() diff --git a/azurelinuxagent/distro/suse/__init__.py b/azurelinuxagent/distro/suse/__init__.py deleted file mode 100644 index d9b82f5..0000000 --- a/azurelinuxagent/distro/suse/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - diff --git a/azurelinuxagent/distro/ubuntu/__init__.py b/azurelinuxagent/distro/ubuntu/__init__.py deleted file mode 100644 index d9b82f5..0000000 --- a/azurelinuxagent/distro/ubuntu/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - diff --git a/azurelinuxagent/distro/ubuntu/distro.py b/azurelinuxagent/distro/ubuntu/distro.py deleted file mode 100644 index f380f6c..0000000 --- a/azurelinuxagent/distro/ubuntu/distro.py +++ /dev/null @@ -1,55 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - -from azurelinuxagent.distro.default.distro import DefaultDistro -from azurelinuxagent.distro.ubuntu.osutil import Ubuntu14OSUtil, \ - Ubuntu12OSUtil, \ - UbuntuOSUtil, \ - UbuntuSnappyOSUtil - -from azurelinuxagent.distro.ubuntu.provision import UbuntuProvisionHandler -from azurelinuxagent.distro.ubuntu.deprovision import UbuntuDeprovisionHandler - -class UbuntuDistro(DefaultDistro): - def __init__(self): - super(UbuntuDistro, self).__init__() - self.osutil = UbuntuOSUtil() - self.provision_handler = UbuntuProvisionHandler(self) - self.deprovision_handler = UbuntuDeprovisionHandler(self) - -class Ubuntu12Distro(DefaultDistro): - def __init__(self): - super(Ubuntu12Distro, self).__init__() - self.osutil = Ubuntu12OSUtil() - self.provision_handler = UbuntuProvisionHandler(self) - self.deprovision_handler = UbuntuDeprovisionHandler(self) - -class Ubuntu14Distro(DefaultDistro): - def __init__(self): - super(Ubuntu14Distro, self).__init__() - self.osutil = Ubuntu14OSUtil() - self.provision_handler = UbuntuProvisionHandler(self) - self.deprovision_handler = UbuntuDeprovisionHandler(self) - -class UbuntuSnappyDistro(DefaultDistro): - def __init__(self): - super(UbuntuSnappyDistro, self).__init__() - self.osutil = UbuntuSnappyOSUtil() - self.provision_handler = UbuntuProvisionHandler(self) - self.deprovision_handler = UbuntuDeprovisionHandler(self) diff --git a/azurelinuxagent/distro/debian/__init__.py b/azurelinuxagent/ga/__init__.py similarity index 95% rename from azurelinuxagent/distro/debian/__init__.py rename to azurelinuxagent/ga/__init__.py index d9b82f5..1ea2f38 100644 --- a/azurelinuxagent/distro/debian/__init__.py +++ b/azurelinuxagent/ga/__init__.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/azurelinuxagent/distro/default/extension.py b/azurelinuxagent/ga/exthandlers.py similarity index 95% rename from azurelinuxagent/distro/default/extension.py rename to azurelinuxagent/ga/exthandlers.py index 262b01b..8f91253 100644 --- a/azurelinuxagent/distro/default/extension.py +++ b/azurelinuxagent/ga/exthandlers.py @@ -22,20 +22,24 @@ import time import json import subprocess import shutil -import azurelinuxagent.conf as conf -import azurelinuxagent.logger as logger -from azurelinuxagent.event import add_event, WALAEventOperation -from azurelinuxagent.exception import ExtensionError, ProtocolError, HttpError -from azurelinuxagent.future import ustr -from azurelinuxagent.metadata import AGENT_VERSION -from azurelinuxagent.protocol.restapi import ExtHandlerStatus, ExtensionStatus, \ - ExtensionSubStatus, Extension, \ - VMStatus, ExtHandler, \ - get_properties, set_properties -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.restutil as restutil -import azurelinuxagent.utils.shellutil as shellutil -from azurelinuxagent.utils.textutil import Version +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.event import add_event, WALAEventOperation +from azurelinuxagent.common.exception import ExtensionError, ProtocolError, HttpError +from azurelinuxagent.common.future import ustr +from azurelinuxagent.common.version import AGENT_VERSION +from azurelinuxagent.common.protocol.restapi import ExtHandlerStatus, \ + ExtensionStatus, \ + ExtensionSubStatus, \ + Extension, \ + VMStatus, ExtHandler, \ + get_properties, \ + set_properties +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.restutil as restutil +import azurelinuxagent.common.utils.shellutil as shellutil +from azurelinuxagent.common.utils.textutil import Version +from azurelinuxagent.common.protocol import get_protocol_util #HandlerEnvironment.json schema version HANDLER_ENVIRONMENT_VERSION = 1.0 @@ -103,9 +107,12 @@ class ExtHandlerState(object): Installed = "Installed" Enabled = "Enabled" +def get_exthandlers_handler(): + return ExtHandlersHandler() + class ExtHandlersHandler(object): - def __init__(self, distro): - self.distro = distro + def __init__(self): + self.protocol_util = get_protocol_util() self.ext_handlers = None self.last_etag = None self.log_report = False @@ -113,7 +120,7 @@ class ExtHandlersHandler(object): def run(self): ext_handlers, etag = None, None try: - self.protocol = self.distro.protocol_util.get_protocol() + self.protocol = self.protocol_util.get_protocol() ext_handlers, etag = self.protocol.get_ext_handlers() except ProtocolError as e: add_event(name="WALA", is_success=False, message=ustr(e)) diff --git a/azurelinuxagent/ga/update.py b/azurelinuxagent/ga/update.py new file mode 100644 index 0000000..4aa66c4 --- /dev/null +++ b/azurelinuxagent/ga/update.py @@ -0,0 +1,278 @@ +# Windows Azure Linux Agent +# +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# +import os +import json +import time +import subprocess +import signal +import sys +import zipfile +from azurelinuxagent.common.exception import UpdateError, ProtocolError +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.event import add_event +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.restutil as restutil +from azurelinuxagent.common.version import AGENT_VERSION +from azurelinuxagent.common.utils.textutil import Version +from azurelinuxagent.common.osutil import get_osutil +from azurelinuxagent.common.protocol import get_protocol_util + +def get_update_handler(): + return UpdateHandler() + +GA_DIR = 'GuestAgent' # Dir name for guest agent bin and data +GA_ERR = 'error' # File name for guest agent error record +MAX_FAILURE = 3 # Max failure allowed for guest agent before blacklisted +RETAIN_INTERVAL = 24 * 60 * 60 # Retain interval for black list + +""" +Handles self update logic +""" +class UpdateHandler(object): + + def __init__(self): + self.osutil = get_osutil() + self.protocol_util = get_protocol_util() + self.last_etag = None + self.agents = [] + self.error_record = {} + + def run(self): + """ + 1. If self-update is enabled, check for new versions. + otherwise, use current agent + 2. Invoke run-exthandlers task + """ + self.mk_ga_dir() + + self.load_error_record() + + updated = self.check_for_update() + if not updated: + return + + latest_agent = None + + if conf.get_autoupdate_enabled(): + logger.info("Auto update enabled") + latest_agent = self.get_latest_agent() + + try: + self.run_extensions(latest_agent) + except UpdateError as e: + add_event(u"WALA", is_success=False, message=ustr(e)) + if latest_agent is not None: + latest_agent.err.mark_failure() + + self.save_error_record() + + def mk_ga_dir(self): + dir_path = os.path.join(conf.get_lib_dir(), GA_DIR) + fileutil.mkdir(dir_path, mode=0o700) + + def get_latest_agent(self): + available_agent = [agent for agent in self.agents \ + if not agent.err.is_blacklisted()] + + return available_agent[0] if len(available_agent) >= 1 else None + + def run_extensions(self, latest_agent): + agent_bin = sys.argv[0] + + if latest_agent is not None: + logger.info(u"The latest guest agent version is : {0}", + latest_agent.version) + agent_bin = latest_agent.get_agent_bin() + + if not latest_agent.is_downloaded(): + try: + latest_agent.download() + except Exception as e: + raise UpdateError(u"Download failed", e) + + devnull = open(os.devnull, 'w') + try: + child = subprocess.Popen([agent_bin, 'run-exthandlers'], + stdout=devnull, stderr=devnull) + except Exception as e: + raise UpdateError(u"Failed to launch task 'run-exthandlers'", e) + + ret = child.wait() + if ret == None or ret != 0: + msg = u"Task 'run-exthandlers' returns none-zero code: {0}".format(1) + raise UpdateError(msg) + + def check_for_update(self): + """Get latest version not in black list""" + self.agents = [] + try: + protocol = self.protocol_util.get_protocol() + manifest_list, etag = protocol.get_vmagent_manifests() + except ProtocolError as e: + add_event(u"WALA", is_success=False, message=ustr(e)) + return False + + if self.last_etag is not None and self.last_etag == etag: + logger.verb("No change to ext handler config:{0}, skip", etag) + return False + + logger.info("Check for update") + + family = conf.get_autoupdate_gafamily() + manifests = [manifest for manifest in manifest_list.vmAgentManifests \ + if manifest.family == family] + if len(manifests) == 0: + message = u"No avaiable guest agent found for: {0}".format(family) + add_event(u"WALA", message=message) + + try: + pkg_list = protocol.get_vmagent_pkgs(manifests[0]) + except ProtocolError as e: + message= u"Failed to get GA package list: {0}".format(e) + add_event("WALA", is_success=False, message=message) + return + + #Only considering versions that is larger than current + pkgs = [pkg for pkg in pkg_list.versions \ + if Version(pkg.version) > Version(AGENT_VERSION)] + + pkgs = sorted(pkgs, key=lambda pkg : Version(pkg.version), reverse=True) + + for pkg in pkgs: + ga_err = self.error_record.get(pkg.version) + if ga_err is None: + ga_err = GuestAgentError(version=pkg.version) + agent = GuestAgent(pkg, ga_err) + self.agents.append(agent) + + #Update error record list. + #Only keep the records for available agent versions + self.error_record = {} + for agent in self.agents: + self.error_record[agent.version] = agent.err + return True + + def load_error_record(self): + self.error_record = {} + file_path = os.path.join(conf.get_lib_dir(), GA_DIR, GA_ERR) + if not os.path.isfile(file_path): + return + + try: + error_data_list = json.loads(fileutil.read_file(file_path)) + for error_data in error_data_list: + ga_err = GuestAgentError() + ga_err.from_dict(error_data) + ga_err.clear_old_failure() + self.error_record[ga_err.version] = ga_err + except (IOError, ValueError) as e: + message = u"Failed to load GA error record: {0}".format(e) + add_event(u"WALA", is_success=False, message=message) + + def save_error_record(self): + error_data_list = [] + for err in self.error_record.values(): + error_data = err.to_dict() + error_data_list.append(error_data) + + file_path = os.path.join(conf.get_lib_dir(), GA_DIR, GA_ERR) + try: + fileutil.write_file(file_path, json.dumps(error_data_list)) + except (IOError, ValueError) as e: + message = u"Failed to save GA error record: {0}".format(e) + add_event(u"WALA", is_success=False, message=message) + +class GuestAgent(object): + def __init__(self, pkg, err): + self.version = pkg.version + self.pkg = pkg + self.err = err + + def get_agent_bin(self): + file_name = "WALinuxAgent-{0}.egg".format(self.version) + return os.path.join(self.get_agent_dir(), file_name) + + def get_agent_dir(self): + dir_name = "WALinuxAgent-{0}".format(self.version) + return os.path.join(conf.get_lib_dir(), GA_DIR, dir_name) + + def get_agent_pkg_file(self): + pkg_file_name = "WALinuxAgent-{0}.zip".format(self.version) + return os.path.join(conf.get_lib_dir(), GA_DIR, pkg_file_name) + + def is_downloaded(self): + return os.path.isfile(self.get_agent_bin()) + + def download(self): + logger.info(u"Download guest agent: {0}", self.version) + add_event(u"WALA", message="Start downloading guest agent package") + package = None + + for uri in self.pkg.uris: + try: + resp = restutil.http_get(uri.uri, chk_proxy=True) + if resp.status == restutil.httpclient.OK: + package = resp.read() + break + except restutil.HttpError as e: + logger.warn("Failed download guest agent from: {0}", uri.uri) + + if package is None: + raise UpdateError("Failed to download guest agent package") + + logger.info("Unpack guest agent package") + pkg_file = self.get_agent_pkg_file() + fileutil.write_file(pkg_file, bytearray(package), asbin=True) + zipfile.ZipFile(pkg_file).extractall(self.get_agent_dir()) + + add_event(name="WALA", message="Download guest agent package succeeded") + +class GuestAgentError(object): + def __init__(self, version=None, last_failure=0, failure_count=0): + self.version = version + self.last_failure = last_failure + self.failure_count = failure_count + + def mark_failure(self): + self.last_failure = time.time() + self.failure_count += 1 + + def clear_old_failure(self): + """Clear failure recored""" + if self.last_failure < (time.time() - RETAIN_INTERVAL): + self.last_failure = 0 + self.failure_count = 0 + + def is_blacklisted(self): + return self.failure_count >= MAX_FAILURE + + def from_dict(self, data): + self.version = data.get(u"version") + self.last_failure = data.get(u"last_failure", 0) + self.failure_count = data.get(u"failure_count", 0) + + def to_dict(self): + data = { + u"version": self.version, + u"last_failure": self.last_failure, + u"failure_count": self.failure_count, + } + return data diff --git a/azurelinuxagent/distro/default/__init__.py b/azurelinuxagent/pa/__init__.py similarity index 95% rename from azurelinuxagent/distro/default/__init__.py rename to azurelinuxagent/pa/__init__.py index d9b82f5..1ea2f38 100644 --- a/azurelinuxagent/distro/default/__init__.py +++ b/azurelinuxagent/pa/__init__.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/azurelinuxagent/pa/deprovision/__init__.py b/azurelinuxagent/pa/deprovision/__init__.py new file mode 100644 index 0000000..de77168 --- /dev/null +++ b/azurelinuxagent/pa/deprovision/__init__.py @@ -0,0 +1,20 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +from azurelinuxagent.pa.deprovision.factory import get_deprovision_handler + +__all__ = ["get_deprovision_handler"] diff --git a/azurelinuxagent/distro/coreos/deprovision.py b/azurelinuxagent/pa/deprovision/coreos.py similarity index 78% rename from azurelinuxagent/distro/coreos/deprovision.py rename to azurelinuxagent/pa/deprovision/coreos.py index 9642579..079a913 100644 --- a/azurelinuxagent/distro/coreos/deprovision.py +++ b/azurelinuxagent/pa/deprovision/coreos.py @@ -17,12 +17,13 @@ # Requires Python 2.4+ and Openssl 1.0+ # -import azurelinuxagent.utils.fileutil as fileutil -from azurelinuxagent.distro.default.deprovision import DeprovisionHandler, DeprovisionAction +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.pa.deprovision.default import DeprovisionHandler, \ + DeprovisionAction class CoreOSDeprovisionHandler(DeprovisionHandler): - def __init__(self, distro): - self.distro = distro + def __init__(self): + super(CoreOSDeprovisionHandler, self).__init__() def setup(self, deluser): warnings, actions = super(CoreOSDeprovisionHandler, self).setup(deluser) diff --git a/azurelinuxagent/distro/default/deprovision.py b/azurelinuxagent/pa/deprovision/default.py similarity index 81% rename from azurelinuxagent/distro/default/deprovision.py rename to azurelinuxagent/pa/deprovision/default.py index e349272..b570c31 100644 --- a/azurelinuxagent/distro/default/deprovision.py +++ b/azurelinuxagent/pa/deprovision/default.py @@ -17,11 +17,13 @@ # Requires Python 2.4+ and Openssl 1.0+ # -import azurelinuxagent.conf as conf -from azurelinuxagent.exception import ProtocolError -from azurelinuxagent.future import read_input -import azurelinuxagent.utils.fileutil as fileutil -import azurelinuxagent.utils.shellutil as shellutil +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.exception import ProtocolError +from azurelinuxagent.common.future import read_input +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +from azurelinuxagent.common.osutil import get_osutil +from azurelinuxagent.common.protocol import get_protocol_util class DeprovisionAction(object): def __init__(self, func, args=[], kwargs={}): @@ -33,19 +35,20 @@ class DeprovisionAction(object): self.func(*self.args, **self.kwargs) class DeprovisionHandler(object): - def __init__(self, distro): - self.distro = distro + def __init__(self): + self.osutil = get_osutil() + self.protocol_util = get_protocol_util() def del_root_password(self, warnings, actions): warnings.append("WARNING! root password will be disabled. " "You will not be able to login as root.") - actions.append(DeprovisionAction(self.distro.osutil.del_root_password)) + actions.append(DeprovisionAction(self.osutil.del_root_password)) def del_user(self, warnings, actions): try: - ovfenv = self.distro.protocol_util.get_ovf_env() + ovfenv = self.protocol_util.get_ovf_env() except ProtocolError: warnings.append("WARNING! ovf-env.xml is not found.") warnings.append("WARNING! Skip delete user.") @@ -54,7 +57,7 @@ class DeprovisionHandler(object): username = ovfenv.username warnings.append(("WARNING! {0} account and entire home directory " "will be deleted.").format(username)) - actions.append(DeprovisionAction(self.distro.osutil.del_account, + actions.append(DeprovisionAction(self.osutil.del_account, [username])) @@ -65,7 +68,7 @@ class DeprovisionHandler(object): def stop_agent_service(self, warnings, actions): warnings.append("WARNING! The waagent service will be stopped.") - actions.append(DeprovisionAction(self.distro.osutil.stop_agent_service)) + actions.append(DeprovisionAction(self.osutil.stop_agent_service)) def del_files(self, warnings, actions): files_to_del = ['/root/.bash_history', '/var/log/waagent.log'] @@ -85,9 +88,9 @@ class DeprovisionHandler(object): def reset_hostname(self, warnings, actions): localhost = ["localhost.localdomain"] - actions.append(DeprovisionAction(self.distro.osutil.set_hostname, + actions.append(DeprovisionAction(self.osutil.set_hostname, localhost)) - actions.append(DeprovisionAction(self.distro.osutil.set_dhcp_hostname, + actions.append(DeprovisionAction(self.osutil.set_dhcp_hostname, localhost)) def setup(self, deluser): diff --git a/azurelinuxagent/pa/deprovision/factory.py b/azurelinuxagent/pa/deprovision/factory.py new file mode 100644 index 0000000..dd01633 --- /dev/null +++ b/azurelinuxagent/pa/deprovision/factory.py @@ -0,0 +1,36 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.utils.textutil import Version +from azurelinuxagent.common.version import DISTRO_NAME, DISTRO_VERSION, \ + DISTRO_FULL_NAME + +from .default import DeprovisionHandler +from .coreos import CoreOSDeprovisionHandler +from .ubuntu import UbuntuDeprovisionHandler + +def get_deprovision_handler(distro_name=DISTRO_NAME, + distro_version=DISTRO_VERSION, + distro_full_name=DISTRO_FULL_NAME): + if distro_name == "ubuntu": + return UbuntuDeprovisionHandler() + if distro_name == "coreos": + return CoreOSDeprovisionHandler() + + return DeprovisionHandler() + diff --git a/azurelinuxagent/distro/ubuntu/deprovision.py b/azurelinuxagent/pa/deprovision/ubuntu.py similarity index 82% rename from azurelinuxagent/distro/ubuntu/deprovision.py rename to azurelinuxagent/pa/deprovision/ubuntu.py index da6e834..14f90de 100644 --- a/azurelinuxagent/distro/ubuntu/deprovision.py +++ b/azurelinuxagent/pa/deprovision/ubuntu.py @@ -18,9 +18,10 @@ # import os -import azurelinuxagent.logger as logger -import azurelinuxagent.utils.fileutil as fileutil -from azurelinuxagent.distro.default.deprovision import DeprovisionHandler, DeprovisionAction +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.pa.deprovision.default import DeprovisionHandler, \ + DeprovisionAction def del_resolv(): if os.path.realpath('/etc/resolv.conf') != '/run/resolvconf/resolv.conf': @@ -33,8 +34,8 @@ def del_resolv(): class UbuntuDeprovisionHandler(DeprovisionHandler): - def __init__(self, distro): - super(UbuntuDeprovisionHandler, self).__init__(distro) + def __init__(self): + super(UbuntuDeprovisionHandler, self).__init__() def setup(self, deluser): warnings, actions = super(UbuntuDeprovisionHandler, self).setup(deluser) diff --git a/azurelinuxagent/pa/provision/__init__.py b/azurelinuxagent/pa/provision/__init__.py new file mode 100644 index 0000000..05f75ae --- /dev/null +++ b/azurelinuxagent/pa/provision/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +from azurelinuxagent.pa.provision.factory import get_provision_handler diff --git a/azurelinuxagent/distro/default/provision.py b/azurelinuxagent/pa/provision/default.py similarity index 75% rename from azurelinuxagent/distro/default/provision.py rename to azurelinuxagent/pa/provision/default.py index ae2951d..b07c147 100644 --- a/azurelinuxagent/distro/default/provision.py +++ b/azurelinuxagent/pa/provision/default.py @@ -20,21 +20,25 @@ Provision handler """ import os -import azurelinuxagent.logger as logger -from azurelinuxagent.future import ustr -import azurelinuxagent.conf as conf -from azurelinuxagent.event import add_event, WALAEventOperation -from azurelinuxagent.exception import ProvisionError, ProtocolError, OSUtilError -from azurelinuxagent.protocol.restapi import ProvisionStatus -import azurelinuxagent.utils.shellutil as shellutil -import azurelinuxagent.utils.fileutil as fileutil +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.event import add_event, WALAEventOperation +from azurelinuxagent.common.exception import ProvisionError, ProtocolError, \ + OSUtilError +from azurelinuxagent.common.protocol.restapi import ProvisionStatus +import azurelinuxagent.common.utils.shellutil as shellutil +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.common.osutil import get_osutil +from azurelinuxagent.common.protocol import get_protocol_util CUSTOM_DATA_FILE="CustomData" class ProvisionHandler(object): - def __init__(self, distro): - self.distro = distro + def __init__(self): + self.osutil = get_osutil() + self.protocol_util = get_protocol_util() def run(self): #If provision is not enabled, return @@ -49,12 +53,12 @@ class ProvisionHandler(object): logger.info("Run provision handler.") logger.info("Copy ovf-env.xml.") try: - ovfenv = self.distro.protocol_util.copy_ovf_env() + ovfenv = self.protocol_util.copy_ovf_env() except ProtocolError as e: self.report_event("Failed to copy ovf-env.xml: {0}".format(e)) return - self.distro.protocol_util.detect_protocol_by_file() + self.protocol_util.get_protocol_by_file() self.report_not_ready("Provisioning", "Starting") @@ -95,50 +99,50 @@ class ProvisionHandler(object): logger.info("Handle ovf-env.xml.") try: logger.info("Set host name.") - self.distro.osutil.set_hostname(ovfenv.hostname) + self.osutil.set_hostname(ovfenv.hostname) logger.info("Publish host name.") - self.distro.osutil.publish_hostname(ovfenv.hostname) + self.osutil.publish_hostname(ovfenv.hostname) self.config_user_account(ovfenv) self.save_customdata(ovfenv) if conf.get_delete_root_password(): - self.distro.osutil.del_root_password() + self.osutil.del_root_password() except OSUtilError as e: raise ProvisionError("Failed to handle ovf-env.xml: {0}".format(e)) def config_user_account(self, ovfenv): logger.info("Create user account if not exists") - self.distro.osutil.useradd(ovfenv.username) + self.osutil.useradd(ovfenv.username) if ovfenv.user_password is not None: logger.info("Set user password.") crypt_id = conf.get_password_cryptid() salt_len = conf.get_password_crypt_salt_len() - self.distro.osutil.chpasswd(ovfenv.username, ovfenv.user_password, + self.osutil.chpasswd(ovfenv.username, ovfenv.user_password, crypt_id=crypt_id, salt_len=salt_len) logger.info("Configure sudoer") - self.distro.osutil.conf_sudoer(ovfenv.username, nopasswd=ovfenv.user_password is None) + self.osutil.conf_sudoer(ovfenv.username, nopasswd=ovfenv.user_password is None) logger.info("Configure sshd") - self.distro.osutil.conf_sshd(ovfenv.disable_ssh_password_auth) + self.osutil.conf_sshd(ovfenv.disable_ssh_password_auth) #Disable selinux temporary - sel = self.distro.osutil.is_selinux_enforcing() + sel = self.osutil.is_selinux_enforcing() if sel: - self.distro.osutil.set_selinux_enforce(0) + self.osutil.set_selinux_enforce(0) self.deploy_ssh_pubkeys(ovfenv) self.deploy_ssh_keypairs(ovfenv) if sel: - self.distro.osutil.set_selinux_enforce(1) + self.osutil.set_selinux_enforce(1) - self.distro.osutil.restart_ssh_service() + self.osutil.restart_ssh_service() def save_customdata(self, ovfenv): customdata = ovfenv.customdata @@ -148,7 +152,8 @@ class ProvisionHandler(object): logger.info("Save custom data") lib_dir = conf.get_lib_dir() if conf.get_decode_customdata(): - customdata= self.distro.osutil.decode_customdata(customdata) + customdata= self.osutil.decode_customdata(customdata) + customdata_file = os.path.join(lib_dir, CUSTOM_DATA_FILE) fileutil.write_file(customdata_file, customdata) @@ -160,12 +165,12 @@ class ProvisionHandler(object): def deploy_ssh_pubkeys(self, ovfenv): for pubkey in ovfenv.ssh_pubkeys: logger.info("Deploy ssh public key.") - self.distro.osutil.deploy_ssh_pubkey(ovfenv.username, pubkey) + self.osutil.deploy_ssh_pubkey(ovfenv.username, pubkey) def deploy_ssh_keypairs(self, ovfenv): for keypair in ovfenv.ssh_keypairs: logger.info("Deploy ssh key pairs.") - self.distro.osutil.deploy_ssh_keypair(ovfenv.username, keypair) + self.osutil.deploy_ssh_keypair(ovfenv.username, keypair) def report_event(self, message, is_success=False): add_event(name="WALA", message=message, is_success=is_success, @@ -175,7 +180,7 @@ class ProvisionHandler(object): status = ProvisionStatus(status="NotReady", subStatus=sub_status, description=description) try: - protocol = self.distro.protocol_util.get_protocol() + protocol = self.protocol_util.get_protocol() protocol.report_provision_status(status) except ProtocolError as e: self.report_event(ustr(e)) @@ -184,7 +189,7 @@ class ProvisionHandler(object): status = ProvisionStatus(status="Ready") status.properties.certificateThumbprint = thumbprint try: - protocol = self.distro.protocol_util.get_protocol() + protocol = self.protocol_util.get_protocol() protocol.report_provision_status(status) except ProtocolError as e: self.report_event(ustr(e)) diff --git a/azurelinuxagent/distro/suse/distro.py b/azurelinuxagent/pa/provision/factory.py similarity index 51% rename from azurelinuxagent/distro/suse/distro.py rename to azurelinuxagent/pa/provision/factory.py index 5b39369..9bbe35c 100644 --- a/azurelinuxagent/distro/suse/distro.py +++ b/azurelinuxagent/pa/provision/factory.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,16 +15,18 @@ # Requires Python 2.4+ and Openssl 1.0+ # -from azurelinuxagent.distro.default.distro import DefaultDistro -from azurelinuxagent.distro.suse.osutil import SUSE11OSUtil, SUSEOSUtil +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.utils.textutil import Version +from azurelinuxagent.common.version import DISTRO_NAME, DISTRO_VERSION, \ + DISTRO_FULL_NAME +from .default import ProvisionHandler +from .ubuntu import UbuntuProvisionHandler -class SUSE11Distro(DefaultDistro): - def __init__(self): - super(SUSE11Distro, self).__init__() - self.osutil = SUSE11OSUtil() +def get_provision_handler(distro_name=DISTRO_NAME, + distro_version=DISTRO_VERSION, + distro_full_name=DISTRO_FULL_NAME): + if distro_name == "ubuntu": + return UbuntuProvisionHandler() -class SUSEDistro(DefaultDistro): - def __init__(self): - super(SUSEDistro, self).__init__() - self.osutil = SUSEOSUtil() + return ProvisionHandler() diff --git a/azurelinuxagent/distro/ubuntu/provision.py b/azurelinuxagent/pa/provision/ubuntu.py similarity index 81% rename from azurelinuxagent/distro/ubuntu/provision.py rename to azurelinuxagent/pa/provision/ubuntu.py index 330e057..b6098c4 100644 --- a/azurelinuxagent/distro/ubuntu/provision.py +++ b/azurelinuxagent/pa/provision/ubuntu.py @@ -19,22 +19,22 @@ import os import time -import azurelinuxagent.logger as logger -from azurelinuxagent.future import ustr -import azurelinuxagent.conf as conf -import azurelinuxagent.protocol.ovfenv as ovfenv -from azurelinuxagent.event import add_event, WALAEventOperation -from azurelinuxagent.exception import ProvisionError, ProtocolError -import azurelinuxagent.utils.shellutil as shellutil -import azurelinuxagent.utils.fileutil as fileutil -from azurelinuxagent.distro.default.provision import ProvisionHandler +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.protocol.ovfenv as ovfenv +from azurelinuxagent.common.event import add_event, WALAEventOperation +from azurelinuxagent.common.exception import ProvisionError, ProtocolError +import azurelinuxagent.common.utils.shellutil as shellutil +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.pa.provision.default import ProvisionHandler """ On ubuntu image, provision could be disabled. """ class UbuntuProvisionHandler(ProvisionHandler): - def __init__(self, distro): - self.distro = distro + def __init__(self): + super(UbuntuProvisionHandler, self).__init__() def run(self): #If provision is enabled, run default provision handler @@ -50,7 +50,7 @@ class UbuntuProvisionHandler(ProvisionHandler): logger.info("Waiting cloud-init to copy ovf-env.xml.") self.wait_for_ovfenv() - protocol = self.distro.protocol_util.detect_protocol() + protocol = self.protocol_util.get_protocol() self.report_not_ready("Provisioning", "Starting") logger.info("Sleep 15 seconds to prevent throttling") time.sleep(15) #Sleep to prevent throttling @@ -75,7 +75,7 @@ class UbuntuProvisionHandler(ProvisionHandler): """ for retry in range(0, max_retry): try: - self.distro.protocol_util.get_ovf_env() + self.protocol_util.get_ovf_env() return except ProtocolError: if retry < max_retry - 1: diff --git a/azurelinuxagent/utils/__init__.py b/azurelinuxagent/utils/__init__.py deleted file mode 100644 index d9b82f5..0000000 --- a/azurelinuxagent/utils/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Microsoft Azure Linux Agent -# -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# - diff --git a/setup.py b/setup.py index 0cfecff..0f42ba6 100755 --- a/setup.py +++ b/setup.py @@ -18,11 +18,11 @@ # import os -from azurelinuxagent.metadata import AGENT_NAME, AGENT_VERSION, \ +from azurelinuxagent.common.version import AGENT_NAME, AGENT_VERSION, \ AGENT_DESCRIPTION, \ DISTRO_NAME, DISTRO_VERSION, DISTRO_FULL_NAME -from azurelinuxagent.agent import Agent +from azurelinuxagent.common.osutil import get_osutil import setuptools from setuptools import find_packages from setuptools.command.install import install as _install @@ -158,7 +158,7 @@ class install(_install): def run(self): _install.run(self) if self.register_service: - Agent(False).register_service() + get_osutil().register_agent_service() setuptools.setup(name=AGENT_NAME, version=AGENT_VERSION, diff --git a/tests/__init__.py b/tests/__init__.py index 9bdb27e..2ef4c16 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -14,6 +14,3 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx diff --git a/azurelinuxagent/protocol/__init__.py b/tests/daemon/__init__.py similarity index 95% rename from azurelinuxagent/protocol/__init__.py rename to tests/daemon/__init__.py index 8c1bbdb..2ef4c16 100644 --- a/azurelinuxagent/protocol/__init__.py +++ b/tests/daemon/__init__.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/distro/test_daemon.py b/tests/daemon/test_daemon.py similarity index 63% rename from tests/distro/test_daemon.py rename to tests/daemon/test_daemon.py index 9d3c45b..263af49 100644 --- a/tests/distro/test_daemon.py +++ b/tests/daemon/test_daemon.py @@ -14,14 +14,10 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.exception import * -from azurelinuxagent.distro.default.daemon import * +from azurelinuxagent.common.exception import * +from azurelinuxagent.daemon import * class MockDaemonCall(object): def __init__(self, daemon_handler, count): @@ -38,26 +34,30 @@ class MockDaemonCall(object): @patch("time.sleep") class TestDaemon(AgentTestCase): def test_daemon_restart(self, mock_sleep): - distro = get_distro() - mock_daemon = Mock(side_effect=MockDaemonCall(distro.daemon_handler, 2)) - distro.daemon_handler.daemon = mock_daemon - distro.daemon_handler.check_pid = Mock() - distro.daemon_handler.run() + #Mock daemon function + daemon_handler = get_daemon_handler() + mock_daemon = Mock(side_effect=MockDaemonCall(daemon_handler, 2)) + daemon_handler.daemon = mock_daemon + + daemon_handler.check_pid = Mock() + + daemon_handler.run() mock_sleep.assert_any_call(15) - self.assertEquals(2, distro.daemon_handler.daemon.call_count) + self.assertEquals(2, daemon_handler.daemon.call_count) - @patch("azurelinuxagent.distro.default.daemon.conf") - @patch("azurelinuxagent.distro.default.daemon.sys.exit") + @patch("azurelinuxagent.daemon.main.conf") + @patch("azurelinuxagent.daemon.main.sys.exit") def test_check_pid(self, mock_exit, mock_conf, mock_sleep): - distro = get_distro() + daemon_handler = get_daemon_handler() + mock_pid_file = os.path.join(self.tmp_dir, "pid") mock_conf.get_agent_pid_file_path = Mock(return_value=mock_pid_file) - distro.daemon_handler.check_pid() + daemon_handler.check_pid() self.assertTrue(os.path.isfile(mock_pid_file)) - distro.daemon_handler.check_pid() + daemon_handler.check_pid() mock_exit.assert_any_call(0) if __name__ == '__main__': diff --git a/tests/distro/test_monitor.py b/tests/daemon/test_monitor.py similarity index 77% rename from tests/distro/test_monitor.py rename to tests/daemon/test_monitor.py index 1dd7740..e037dc0 100644 --- a/tests/distro/test_monitor.py +++ b/tests/daemon/test_monitor.py @@ -14,13 +14,10 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.exception import * -from azurelinuxagent.distro.default.monitor import * +from azurelinuxagent.common.exception import * +from azurelinuxagent.daemon.monitor import * class TestMonitor(AgentTestCase): def test_parse_xml_event(self): diff --git a/tests/data/ga/WALinuxAgent-2.1.5.rc0.zip b/tests/data/ga/WALinuxAgent-2.1.5.rc0.zip new file mode 100644 index 0000000000000000000000000000000000000000..fcf158d236eb22123c04a5ed520f6a30499f4bf7 GIT binary patch literal 243684 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%0DR$oh6$LYo9nIx_ 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 z z-KJg$YnS?}m>qGVR@1u>A7rb2Z$y z;>UcyrM!==Kx_jC=s;u>t!SAE`C6{YhCJ9|9*z({OuzrS91J994N&F?nB5%m32Q^Z z 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 literal 0 HcmV?d00001 diff --git a/tests/data/wire/ext_conf.xml b/tests/data/wire/ext_conf.xml index aded2dd..0b7c528 100644 --- a/tests/data/wire/ext_conf.xml +++ b/tests/data/wire/ext_conf.xml @@ -1,36 +1,16 @@ - Win8 + Prod - http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml - http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml - http://rdfepirv2hknprdstr05.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml - http://rdfepirv2hknprdstr06.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml - http://rdfepirv2hknprdstr07.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml - http://rdfepirv2hknprdstr08.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml - http://rdfepirv2hknprdstr09.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml - http://rdfepirv2hknprdstr10.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml - http://rdfepirv2hknprdstr11.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml - http://rdfepirv2hknprdstr12.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml - http://zrdfepirv2hk2prdstr01.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml + http://manifest_of_ga.xml - Win7 + Test - http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - http://rdfepirv2hknprdstr05.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - http://rdfepirv2hknprdstr06.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - http://rdfepirv2hknprdstr07.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - http://rdfepirv2hknprdstr08.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - http://rdfepirv2hknprdstr09.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - http://rdfepirv2hknprdstr10.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - http://rdfepirv2hknprdstr11.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - http://rdfepirv2hknprdstr12.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - http://zrdfepirv2hk2prdstr01.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml - + http://manifest_of_ga.xml + diff --git a/tests/data/wire/ga_manifest.xml b/tests/data/wire/ga_manifest.xml new file mode 100644 index 0000000..f43daf5 --- /dev/null +++ b/tests/data/wire/ga_manifest.xml @@ -0,0 +1,48 @@ + + + + + 1.0.0 + + http://foo.bar/zar/OSTCExtensions.WALinuxAgent__1.0.0 + + + + 1.1.0 + + http://foo.bar/zar/OSTCExtensions.WALinuxAgent__1.1.0 + + + + 2.0.0http://host/OSTCExtensions.WALinuxAgent__2.0.0 + + + 2.1.0http://host/OSTCExtensions.WALinuxAgent__2.1.0 + + + 2.1.1http://host/OSTCExtensions.WALinuxAgent__2.1.1 + + + 2.2.0http://host/OSTCExtensions.WALinuxAgent__2.2.0 + + + 3.0http://host/OSTCExtensions.WALinuxAgent__3.0 + + + 3.1http://host/OSTCExtensions.WALinuxAgent__3.1 + + + 4.0.0.0http://host/OSTCExtensions.WALinuxAgent__3.0 + + + 4.0.0.1http://host/OSTCExtensions.WALinuxAgent__3.1 + + + 4.1.0.0http://host/OSTCExtensions.WALinuxAgent__3.1 + + + 99999.0.0.0http://host/OSTCExtensions.WALinuxAgent__99999.0.0.0 + + + + diff --git a/tests/distro/__init__.py b/tests/distro/__init__.py deleted file mode 100644 index 9bdb27e..0000000 --- a/tests/distro/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx diff --git a/tests/distro/test_loader.py b/tests/distro/test_loader.py deleted file mode 100644 index 94ca913..0000000 --- a/tests/distro/test_loader.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2014 Microsoft Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Requires Python 2.4+ and Openssl 1.0+ -# -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx - -from tests.tools import * -from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.distro.default.distro import DefaultDistro - -class TestDistroLoader(AgentTestCase): - - @distros() - def test_distro_loader(self, *distro_args): - distro = get_distro(*distro_args) - self.assertNotEquals(None, distro) - self.assertNotEquals(DefaultDistro, type(distro)) - - -if __name__ == '__main__': - unittest.main() - diff --git a/azurelinuxagent/distro/coreos/__init__.py b/tests/ga/__init__.py similarity index 95% rename from azurelinuxagent/distro/coreos/__init__.py rename to tests/ga/__init__.py index 8c1bbdb..2ef4c16 100644 --- a/azurelinuxagent/distro/coreos/__init__.py +++ b/tests/ga/__init__.py @@ -1,5 +1,3 @@ -# Microsoft Azure Linux Agent -# # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/distro/test_extension.py b/tests/ga/test_extension.py similarity index 86% rename from tests/distro/test_extension.py rename to tests/ga/test_extension.py index e54cbf5..061c0ee 100644 --- a/tests/distro/test_extension.py +++ b/tests/ga/test_extension.py @@ -14,19 +14,16 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.protocol.mockwiredata import * -from azurelinuxagent.exception import * -from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.protocol.wire import WireProtocol -from azurelinuxagent.distro.default.extension import ExtHandlerInstance +from azurelinuxagent.common.exception import * +from azurelinuxagent.common.protocol import get_protocol_util +from azurelinuxagent.ga.exthandlers import * +from azurelinuxagent.common.protocol.wire import WireProtocol @patch("time.sleep") -@patch("azurelinuxagent.protocol.wire.CryptUtil") -@patch("azurelinuxagent.utils.restutil.http_get") +@patch("azurelinuxagent.common.protocol.wire.CryptUtil") +@patch("azurelinuxagent.common.utils.restutil.http_get") class TestExtension(AgentTestCase): def _assert_handler_status(self, report_vm_status, expected_status, @@ -50,31 +47,32 @@ class TestExtension(AgentTestCase): def _create_mock(self, test_data, mock_http_get, MockCryptUtil, _): """Test enable/disable/unistall of an extension""" - distro = get_distro() - + handler = get_exthandlers_handler() + #Mock protocol to return test data mock_http_get.side_effect = test_data.mock_http_get MockCryptUtil.side_effect = test_data.mock_crypt_util - + protocol = WireProtocol("foo.bar") protocol.detect() protocol.report_ext_status = MagicMock() protocol.report_vm_status = MagicMock() - distro.protocol_util.get_protocol = Mock(return_value=protocol) + + handler.protocol_util.get_protocol = Mock(return_value=protocol) - return distro, protocol + return handler, protocol def test_ext_handler(self, *args): test_data = WireProtocolData(DATA_FILE) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) #Test enable scenario. - distro.ext_handlers_handler.run() + 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) #Test goal state not changed - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") #Test goal state changed @@ -82,7 +80,7 @@ class TestExtension(AgentTestCase): "2<") test_data.ext_conf = test_data.ext_conf.replace("seqNo=\"0\"", "seqNo=\"1\"") - distro.ext_handlers_handler.run() + 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", 1) @@ -92,7 +90,7 @@ class TestExtension(AgentTestCase): test_data.ext_conf = test_data.ext_conf.replace("1.0.0", "1.1.0") test_data.ext_conf = test_data.ext_conf.replace("seqNo=\"1\"", "seqNo=\"2\"") - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.1.0") self._assert_ext_status(protocol.report_ext_status, "success", 2) @@ -100,7 +98,7 @@ class TestExtension(AgentTestCase): test_data.goal_state = test_data.goal_state.replace("3<", "4<") test_data.ext_conf = test_data.ext_conf.replace("enabled", "disabled") - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_handler_status(protocol.report_vm_status, "NotReady", 1, "1.1.0") @@ -108,56 +106,56 @@ class TestExtension(AgentTestCase): test_data.goal_state = test_data.goal_state.replace("4<", "5<") test_data.ext_conf = test_data.ext_conf.replace("disabled", "uninstall") - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_no_handler_status(protocol.report_vm_status) #Test uninstall again! test_data.goal_state = test_data.goal_state.replace("5<", "6<") - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_no_handler_status(protocol.report_vm_status) def test_ext_handler_no_settings(self, *args): test_data = WireProtocolData(DATA_FILE_EXT_NO_SETTINGS) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) - distro.ext_handlers_handler.run() + 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) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) - distro.ext_handlers_handler.run() + 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) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) #Assert no extension handler status - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_no_handler_status(protocol.report_vm_status) - @patch('azurelinuxagent.distro.default.extension.add_event') + @patch('azurelinuxagent.ga.exthandlers.add_event') def test_ext_handler_download_failure(self, mock_add_event, *args): test_data = WireProtocolData(DATA_FILE) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) protocol.download_ext_handler_pkg = Mock(side_effect=ProtocolError) - distro.ext_handlers_handler.run() + exthandlers_handler.run() args, kw = mock_add_event.call_args self.assertEquals(False, kw['is_success']) self.assertEquals("OSTCExtensions.ExampleHandlerLinux", kw['name']) self.assertEquals("Download", kw['op']) - @patch('azurelinuxagent.distro.default.extension.fileutil') + @patch('azurelinuxagent.ga.exthandlers.fileutil') def test_ext_handler_io_error(self, mock_fileutil, *args): test_data = WireProtocolData(DATA_FILE) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) mock_fileutil.write_file.return_value = IOError("Mock IO Error") - distro.ext_handlers_handler.run() + exthandlers_handler.run() def _assert_ext_status(self, report_ext_status, expected_status, expected_seq_no): @@ -169,8 +167,8 @@ class TestExtension(AgentTestCase): def test_ext_handler_no_reporting_status(self, *args): test_data = WireProtocolData(DATA_FILE) - distro, protocol = self._create_mock(test_data, *args) - distro.ext_handlers_handler.run() + 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") #Remove status file and re-run collecting extension status @@ -180,7 +178,7 @@ class TestExtension(AgentTestCase): self.assertTrue(os.path.isfile(status_file)) os.remove(status_file) - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") self._assert_ext_status(protocol.report_ext_status, "error", 0) diff --git a/tests/ga/test_update.py b/tests/ga/test_update.py new file mode 100644 index 0000000..b382b32 --- /dev/null +++ b/tests/ga/test_update.py @@ -0,0 +1,136 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +from tests.tools import * +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.common.protocol.wire import * +from azurelinuxagent.common.exception import UpdateError +from azurelinuxagent.ga.update import * +from tests.protocol.mockwiredata import * + +class TestUpdate(AgentTestCase): + def test_error_record(self): + update_handler = get_update_handler() + update_handler.mk_ga_dir() + + #Save error record + err = GuestAgentError(version="1.0") + update_handler.error_record[err.version] = err + update_handler.save_error_record() + + #Load error record + update_handler = get_update_handler() + update_handler.load_error_record() + self.assertNotEquals(None, update_handler.error_record.get("1.0")) + + #Mark failure and save again + err = update_handler.error_record.get("1.0") + err.mark_failure() + update_handler.save_error_record() + + #Re-load the error record and check + update_handler = get_update_handler() + update_handler.load_error_record() + self.assertNotEquals(None, update_handler.error_record.get("1.0")) + err = update_handler.error_record.get("1.0") + self.assertNotEquals(0, err.failure_count) + self.assertNotEquals(0, err.last_failure) + + @patch("time.sleep") + @patch("azurelinuxagent.common.protocol.wire.CryptUtil") + @patch("azurelinuxagent.common.utils.restutil.http_get") + def test_check_update(self, mock_http_get, MockCryptUtil, _): + update_handler = get_update_handler() + + test_data = WireProtocolData(DATA_FILE) + mock_http_get.side_effect = test_data.mock_http_get + MockCryptUtil.side_effect = test_data.mock_crypt_util + + protocol = WireProtocol("foo.bar") + protocol.detect() + update_handler.protocol_util.get_protocol = Mock(return_value=protocol) + + update_handler.check_for_update() + self.assertNotEquals(0, update_handler.agents) + + latest_agent = update_handler.get_latest_agent() + self.assertNotEquals(None, latest_agent) + self.assertEquals("99999.0.0.0", latest_agent.version) + #Only should consider versions >= current version + self.assertFalse("1.0.0" in update_handler.error_record) + + def test_run_extension(self): + update_handler = get_update_handler() + + #Create a mock guest agent instance + test_script = os.path.join(self.tmp_dir, "mock_success") + pkg = ExtHandlerPackage(version="1.0") + latest_agent = GuestAgent(pkg, GuestAgentError(version=pkg.version)) + latest_agent.get_agent_bin = Mock(return_value=test_script) + + #Create a test script to mock invoking run-extensions success + fileutil.write_file(test_script, "#!/bin/bash\nexit 0") + fileutil.chmod(test_script, 0o700) + update_handler.run_extensions(latest_agent) + + #Create a test script to mock invoking run-extensions failure + fileutil.write_file(test_script, "#!/bin/bash\nexit 1") + self.assertRaises(UpdateError, update_handler.run_extensions, + latest_agent) + +class TestGuestAgent(AgentTestCase): + @patch("azurelinuxagent.ga.update.restutil.http_get") + def test_download(self, mock_http_get): + update_handler = get_update_handler() + update_handler.mk_ga_dir() + + ga_pkg = load_bin_data("ga/WALinuxAgent-2.1.5.rc0.zip") + ga_pkg_resp = MagicMock() + ga_pkg_resp.status = restutil.httpclient.OK + ga_pkg_resp.read = Mock(return_value=ga_pkg) + mock_http_get.return_value= ga_pkg_resp + + pkg = ExtHandlerPackage(version="2.1.5.rc0") + pkg.uris.append(ExtHandlerPackageUri()) + agent = GuestAgent(pkg, GuestAgentError(version=pkg.version)) + agent.download() + self.assertTrue(agent.is_downloaded()) + +class TestGuestAgentError(AgentTestCase): + def test_mark_failure(self): + err = GuestAgentError() + + self.assertFalse(err.is_blacklisted()) + + for i in range(0, MAX_FAILURE): + err.mark_failure() + + #Assume agent failed >= MAX_FAILURE, it should be blacklisted + self.assertTrue(err.is_blacklisted()) + self.assertEqual(MAX_FAILURE, err.failure_count) + + #Clear old failure won't clear recent failure + err.clear_old_failure() + self.assertTrue(err.is_blacklisted()) + + #Unless we set the failure to earlier than (now - RETAIN_INTERVAL) + err.last_failure -= RETAIN_INTERVAL * 2 + err.clear_old_failure() + self.assertFalse(err.is_blacklisted()) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/pa/__init__.py b/tests/pa/__init__.py new file mode 100644 index 0000000..2ef4c16 --- /dev/null +++ b/tests/pa/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# diff --git a/tests/distro/test_provision.py b/tests/pa/test_provision.py similarity index 58% rename from tests/distro/test_provision.py rename to tests/pa/test_provision.py index 60249ce..6508017 100644 --- a/tests/distro/test_provision.py +++ b/tests/pa/test_provision.py @@ -14,33 +14,33 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.distro.default.protocolUtil import * -import azurelinuxagent.utils.fileutil as fileutil +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.protocol import OVF_FILE_NAME +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.pa.provision import get_provision_handler class TestProvision(AgentTestCase): - + @distros("redhat") def test_provision(self, distro_name, distro_version, distro_full_name): - distro = get_distro(distro_name, distro_version, distro_full_name) - distro.osutil = MagicMock() - distro.osutil.decode_customdata = Mock(return_value="") - - distro.protocol_util.detect_protocol_by_file = MagicMock() - distro.protocol_util.get_protocol = MagicMock() + provision_handler = get_provision_handler(distro_name, distro_version, + distro_full_name) + mock_osutil = MagicMock() + mock_osutil.decode_customdata = Mock(return_value="") + + provision_handler.osutil = mock_osutil + provision_handler.protocol_util.osutil = mock_osutil + provision_handler.protocol_util.get_protocol_by_file = MagicMock() + provision_handler.protocol_util.get_protocol = MagicMock() + conf.get_dvd_mount_point = Mock(return_value=self.tmp_dir) - ovfenv_file = os.path.join(self.tmp_dir, OVF_FILE_NAME) ovfenv_data = load_data("ovf-env.xml") fileutil.write_file(ovfenv_file, ovfenv_data) - handler = distro.provision_handler - handler.run() + provision_handler.run() if __name__ == '__main__': unittest.main() diff --git a/tests/protocol/__init__.py b/tests/protocol/__init__.py index 9bdb27e..2ef4c16 100644 --- a/tests/protocol/__init__.py +++ b/tests/protocol/__init__.py @@ -14,6 +14,3 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx diff --git a/tests/protocol/mockmetadata.py b/tests/protocol/mockmetadata.py index 0f7b568..dce3367 100644 --- a/tests/protocol/mockmetadata.py +++ b/tests/protocol/mockmetadata.py @@ -14,13 +14,10 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.future import httpclient -from azurelinuxagent.utils.cryptutil import CryptUtil +from azurelinuxagent.common.future import httpclient +from azurelinuxagent.common.utils.cryptutil import CryptUtil DATA_FILE = { "identity": "metadata/identity.json", diff --git a/tests/protocol/mockwiredata.py b/tests/protocol/mockwiredata.py index 2bfb0e9..c789de5 100644 --- a/tests/protocol/mockwiredata.py +++ b/tests/protocol/mockwiredata.py @@ -14,13 +14,10 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.future import httpclient -from azurelinuxagent.utils.cryptutil import CryptUtil +from azurelinuxagent.common.future import httpclient +from azurelinuxagent.common.utils.cryptutil import CryptUtil DATA_FILE = { "version_info": "wire/version_info.xml", @@ -30,6 +27,7 @@ DATA_FILE = { "certs": "wire/certs.xml", "ext_conf": "wire/ext_conf.xml", "manifest": "wire/manifest.xml", + "ga_manifest" : "wire/ga_manifest.xml", "trans_prv": "wire/trans_prv", "trans_cert": "wire/trans_cert", "test_ext": "ext/sample_ext.zip" @@ -62,6 +60,7 @@ class WireProtocolData(object): self.certs = load_data(data_files.get("certs")) self.ext_conf = load_data(data_files.get("ext_conf")) self.manifest = load_data(data_files.get("manifest")) + self.ga_manifest = load_data(data_files.get("ga_manifest")) self.trans_prv = load_data(data_files.get("trans_prv")) self.trans_cert = load_data(data_files.get("trans_cert")) self.ext = load_bin_data(data_files.get("test_ext")) @@ -82,6 +81,8 @@ class WireProtocolData(object): content = self.ext_conf elif "manifest.xml" in url: content = self.manifest + elif "manifest_of_ga.xml" in url: + content = self.ga_manifest elif "ExampleHandlerLinux" in url: content = self.ext resp = MagicMock() diff --git a/tests/protocol/test_metadata.py b/tests/protocol/test_metadata.py index fca1a82..3fcddbb 100644 --- a/tests/protocol/test_metadata.py +++ b/tests/protocol/test_metadata.py @@ -14,17 +14,14 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * from tests.protocol.mockmetadata import * -from azurelinuxagent.utils.restutil import httpclient -from azurelinuxagent.protocol.metadata import MetadataProtocol +from azurelinuxagent.common.utils.restutil import httpclient +from azurelinuxagent.common.protocol.metadata import MetadataProtocol @patch("time.sleep") -@patch("azurelinuxagent.protocol.metadata.restutil") +@patch("azurelinuxagent.common.protocol.metadata.restutil") class TestWireProtocolGetters(AgentTestCase): def _test_getters(self, test_data, mock_restutil ,_): mock_restutil.http_get.side_effect = test_data.mock_http_get diff --git a/tests/distro/test_protocol_util.py b/tests/protocol/test_protocol_util.py similarity index 52% rename from tests/distro/test_protocol_util.py rename to tests/protocol/test_protocol_util.py index 61339f3..cb9a06f 100644 --- a/tests/distro/test_protocol_util.py +++ b/tests/protocol/test_protocol_util.py @@ -14,72 +14,64 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.exception import * -from azurelinuxagent.distro.default.protocolUtil import * +from azurelinuxagent.common.exception import * +from azurelinuxagent.common.protocol import get_protocol_util, \ + TAG_FILE_NAME @patch("time.sleep") class TestProtocolUtil(AgentTestCase): - @distros() - @patch("azurelinuxagent.distro.default.protocolUtil.MetadataProtocol") - @patch("azurelinuxagent.distro.default.protocolUtil.WireProtocol") - def test_detect_protocol(self, distro_name, distro_version, distro_full_name, - WireProtocol, MetadataProtocol, _, *distro_args): - + @patch("azurelinuxagent.common.protocol.util.MetadataProtocol") + @patch("azurelinuxagent.common.protocol.util.WireProtocol") + def test_detect_protocol(self, WireProtocol, MetadataProtocol, _): WireProtocol.return_value = MagicMock() MetadataProtocol.return_value = MagicMock() + + protocol_util = get_protocol_util() - distro = get_distro(distro_name, distro_version, distro_full_name) - distro.dhcp_handler = MagicMock() - distro.dhcp_handler.endpoint = "foo.bar" + protocol_util.dhcp_handler = MagicMock() + protocol_util.dhcp_handler.endpoint = "foo.bar" #Test wire protocol is available - protocol = distro.protocol_util.detect_protocol() + protocol = protocol_util.get_protocol() self.assertEquals(WireProtocol.return_value, protocol) #Test wire protocol is not available - distro.protocol_util.protocol = None - WireProtocol.side_effect = ProtocolError() + protocol_util.clear_protocol() + WireProtocol.return_value.detect.side_effect = ProtocolError() - protocol = distro.protocol_util.detect_protocol() + protocol = protocol_util.get_protocol() self.assertEquals(MetadataProtocol.return_value, protocol) #Test no protocol is available - distro.protocol_util.protocol = None - WireProtocol.side_effect = ProtocolError() - MetadataProtocol.side_effect = ProtocolError() - self.assertRaises(ProtocolError, distro.protocol_util.detect_protocol) + protocol_util.clear_protocol() + WireProtocol.return_value.detect.side_effect = ProtocolError() - @distros() - def test_detect_protocol_by_file(self, distro_name, distro_version, - distro_full_name, _): - distro = get_distro(distro_name, distro_version, distro_full_name) - protocol_util = distro.protocol_util + MetadataProtocol.return_value.detect.side_effect = ProtocolError() + self.assertRaises(ProtocolError, protocol_util.get_protocol) + def test_detect_protocol_by_file(self, _): + protocol_util = get_protocol_util() protocol_util._detect_wire_protocol = Mock() protocol_util._detect_metadata_protocol = Mock() tag_file = os.path.join(self.tmp_dir, TAG_FILE_NAME) #Test tag file doesn't exist - protocol_util.detect_protocol_by_file() + protocol_util.get_protocol_by_file() protocol_util._detect_wire_protocol.assert_any_call() protocol_util._detect_metadata_protocol.assert_not_called() #Test tag file exists - protocol_util.protocol = None + protocol_util.clear_protocol() protocol_util._detect_wire_protocol.reset_mock() protocol_util._detect_metadata_protocol.reset_mock() with open(tag_file, "w+") as tag_fd: tag_fd.write("") - protocol_util.detect_protocol_by_file() + protocol_util.get_protocol_by_file() protocol_util._detect_metadata_protocol.assert_any_call() protocol_util._detect_wire_protocol.assert_not_called() diff --git a/tests/protocol/test_restapi.py b/tests/protocol/test_restapi.py index 656ecc6..e4b65c9 100644 --- a/tests/protocol/test_restapi.py +++ b/tests/protocol/test_restapi.py @@ -14,9 +14,6 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * import uuid @@ -24,7 +21,7 @@ import unittest import os import shutil import time -from azurelinuxagent.protocol.restapi import * +from azurelinuxagent.common.protocol.restapi import * class SampleDataContract(DataContract): def __init__(self): diff --git a/tests/protocol/test_wire.py b/tests/protocol/test_wire.py index 4c38c13..bd3acaf 100644 --- a/tests/protocol/test_wire.py +++ b/tests/protocol/test_wire.py @@ -14,9 +14,6 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * from tests.protocol.mockwiredata import * @@ -24,18 +21,18 @@ import uuid import unittest import os import time -from azurelinuxagent.utils.restutil import httpclient -from azurelinuxagent.utils.cryptutil import CryptUtil -from azurelinuxagent.protocol.restapi import * -from azurelinuxagent.protocol.wire import WireClient, WireProtocol, \ +from azurelinuxagent.common.utils.restutil import httpclient +from azurelinuxagent.common.utils.cryptutil import CryptUtil +from azurelinuxagent.common.protocol.restapi import * +from azurelinuxagent.common.protocol.wire import WireClient, WireProtocol, \ TRANSPORT_PRV_FILE_NAME, \ TRANSPORT_CERT_FILE_NAME data_with_bom = b'\xef\xbb\xbfhehe' @patch("time.sleep") -@patch("azurelinuxagent.protocol.wire.CryptUtil") -@patch("azurelinuxagent.protocol.wire.restutil") +@patch("azurelinuxagent.common.protocol.wire.CryptUtil") +@patch("azurelinuxagent.common.protocol.wire.restutil") class TestWireProtocolGetters(AgentTestCase): def _test_getters(self, test_data, mock_restutil, MockCryptUtil, _): diff --git a/tests/test_import.py b/tests/test_import.py new file mode 100644 index 0000000..0412411 --- /dev/null +++ b/tests/test_import.py @@ -0,0 +1,26 @@ +from tests.tools import * +import azurelinuxagent.common.osutil as osutil +import azurelinuxagent.common.dhcp as dhcp +import azurelinuxagent.common.protocol as protocol +import azurelinuxagent.pa.provision as provision +import azurelinuxagent.pa.deprovision as deprovision +import azurelinuxagent.daemon as daemon +import azurelinuxagent.daemon.resourcedisk as resourcedisk +import azurelinuxagent.daemon.scvmm as scvmm +import azurelinuxagent.daemon.monitor as monitor +import azurelinuxagent.ga.update as update +import azurelinuxagent.ga.exthandlers as exthandlers + +class TestImportHandler(AgentTestCase): + def test_get_handler(self): + osutil.get_osutil() + protocol.get_protocol_util() + dhcp.get_dhcp_handler() + provision.get_provision_handler() + deprovision.get_deprovision_handler() + daemon.get_daemon_handler() + resourcedisk.get_resourcedisk_handler() + scvmm.get_scvmm_handler() + monitor.get_monitor_handler() + update.get_update_handler() + exthandlers.get_exthandlers_handler() diff --git a/tests/tools.py b/tests/tools.py index 672c60b..aef641e 100644 --- a/tests/tools.py +++ b/tests/tools.py @@ -14,9 +14,6 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx """ Define util functions for unit test @@ -30,9 +27,9 @@ import shutil import json import tempfile from functools import wraps -import azurelinuxagent.conf as conf -import azurelinuxagent.logger as logger -import azurelinuxagent.event as event +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.event as event #Import mock module for Python2 and Python3 try: diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index 9bdb27e..2ef4c16 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -14,6 +14,3 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx diff --git a/tests/utils/test_file_util.py b/tests/utils/test_file_util.py index bf7c638..9a5479e 100644 --- a/tests/utils/test_file_util.py +++ b/tests/utils/test_file_util.py @@ -14,17 +14,14 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * import uuid import unittest import os import sys -from azurelinuxagent.future import ustr -import azurelinuxagent.utils.fileutil as fileutil +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.utils.fileutil as fileutil class TestFileOperations(AgentTestCase): def test_read_write_file(self): diff --git a/tests/utils/test_rest_util.py b/tests/utils/test_rest_util.py index bd22c55..874e527 100644 --- a/tests/utils/test_rest_util.py +++ b/tests/utils/test_rest_util.py @@ -14,17 +14,14 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import AgentTestCase, patch, Mock, MagicMock import uuid import unittest import os -import azurelinuxagent.utils.restutil as restutil -from azurelinuxagent.future import ustr, httpclient -import azurelinuxagent.logger as logger +import azurelinuxagent.common.utils.restutil as restutil +from azurelinuxagent.common.future import ustr, httpclient +import azurelinuxagent.common.logger as logger class TestHttpOperations(AgentTestCase): @@ -57,8 +54,8 @@ class TestHttpOperations(AgentTestCase): self.assertEquals(rel_uri, "None") - @patch("azurelinuxagent.future.httpclient.HTTPSConnection") - @patch("azurelinuxagent.future.httpclient.HTTPConnection") + @patch("azurelinuxagent.common.future.httpclient.HTTPSConnection") + @patch("azurelinuxagent.common.future.httpclient.HTTPConnection") def test_http_request(self, HTTPConnection, HTTPSConnection): mock_httpconn = MagicMock() mock_httpresp = MagicMock() @@ -98,7 +95,7 @@ class TestHttpOperations(AgentTestCase): self.assertEquals("_(:3| <)_", resp.read()) @patch("time.sleep") - @patch("azurelinuxagent.utils.restutil._http_request") + @patch("azurelinuxagent.common.utils.restutil._http_request") def test_http_request_with_retry(self, _http_request, sleep): mock_httpresp = MagicMock() mock_httpresp.read = Mock(return_value="hehe") diff --git a/tests/utils/test_shell_util.py b/tests/utils/test_shell_util.py index aa89121..156a50f 100644 --- a/tests/utils/test_shell_util.py +++ b/tests/utils/test_shell_util.py @@ -15,15 +15,12 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * import uuid import unittest import os -import azurelinuxagent.utils.shellutil as shellutil +import azurelinuxagent.common.utils.shellutil as shellutil import test class TestrunCmd(AgentTestCase): diff --git a/tests/utils/test_text_util.py b/tests/utils/test_text_util.py index 0e8cc7d..9ac0707 100644 --- a/tests/utils/test_text_util.py +++ b/tests/utils/test_text_util.py @@ -14,17 +14,14 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * import uuid import unittest import os -from azurelinuxagent.future import ustr -import azurelinuxagent.utils.textutil as textutil -from azurelinuxagent.utils.textutil import Version +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.utils.textutil as textutil +from azurelinuxagent.common.utils.textutil import Version class TestTextUtil(AgentTestCase): def test_get_password_hash(self):