diff options
Diffstat (limited to 'azurelinuxagent/distro')
38 files changed, 546 insertions, 318 deletions
diff --git a/azurelinuxagent/distro/__init__.py b/azurelinuxagent/distro/__init__.py index 4b2b9e1..d9b82f5 100644 --- a/azurelinuxagent/distro/__init__.py +++ b/azurelinuxagent/distro/__init__.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/centos/__init__.py b/azurelinuxagent/distro/centos/__init__.py index 4b2b9e1..d9b82f5 100644 --- a/azurelinuxagent/distro/centos/__init__.py +++ b/azurelinuxagent/distro/centos/__init__.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/centos/loader.py b/azurelinuxagent/distro/centos/loader.py index 379f027..9dc428f 100644 --- a/azurelinuxagent/distro/centos/loader.py +++ b/azurelinuxagent/distro/centos/loader.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/coreos/__init__.py b/azurelinuxagent/distro/coreos/__init__.py index 7a4980e..8c1bbdb 100644 --- a/azurelinuxagent/distro/coreos/__init__.py +++ b/azurelinuxagent/distro/coreos/__init__.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/coreos/deprovision.py b/azurelinuxagent/distro/coreos/deprovision.py index f0ff604..99d3a40 100644 --- a/azurelinuxagent/distro/coreos/deprovision.py +++ b/azurelinuxagent/distro/coreos/deprovision.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/coreos/handlerFactory.py b/azurelinuxagent/distro/coreos/handlerFactory.py index f0490e8..58f476c 100644 --- a/azurelinuxagent/distro/coreos/handlerFactory.py +++ b/azurelinuxagent/distro/coreos/handlerFactory.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/coreos/loader.py b/azurelinuxagent/distro/coreos/loader.py index ec009ef..802f276 100644 --- a/azurelinuxagent/distro/coreos/loader.py +++ b/azurelinuxagent/distro/coreos/loader.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/coreos/osutil.py b/azurelinuxagent/distro/coreos/osutil.py index 6dfba64..c244311 100644 --- a/azurelinuxagent/distro/coreos/osutil.py +++ b/azurelinuxagent/distro/coreos/osutil.py @@ -37,7 +37,7 @@ class CoreOSUtil(DefaultOSUtil): super(CoreOSUtil, self).__init__() self.waagent_path='/usr/share/oem/bin/waagent' self.python_path='/usr/share/oem/python/bin' - self.conf_path = '/usr/share/oem/waagent.conf' + self.conf_file_path = '/usr/share/oem/waagent.conf' if 'PATH' in os.environ: path = "{0}:{1}".format(os.environ['PATH'], self.python_path) else: @@ -55,7 +55,7 @@ class CoreOSUtil(DefaultOSUtil): #User 'core' is not a sysuser if username == 'core': return False - return super(CoreOSUtil, self).IsSysUser(username) + return super(CoreOSUtil, self).is_sys_user(username) def is_dhcp_enabled(self): return True @@ -88,3 +88,11 @@ class CoreOSUtil(DefaultOSUtil): def decode_customdata(self, data): return base64.b64decode(data) + def set_ssh_client_alive_interval(self): + #In CoreOS, /etc/sshd_config is mount readonly. Skip the setting + pass + + def conf_sshd(self, disable_password): + #In CoreOS, /etc/sshd_config is mount readonly. Skip the setting + pass + diff --git a/azurelinuxagent/distro/debian/__init__.py b/azurelinuxagent/distro/debian/__init__.py index 4b2b9e1..d9b82f5 100644 --- a/azurelinuxagent/distro/debian/__init__.py +++ b/azurelinuxagent/distro/debian/__init__.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/debian/loader.py b/azurelinuxagent/distro/debian/loader.py index 0787758..cc0c06f 100644 --- a/azurelinuxagent/distro/debian/loader.py +++ b/azurelinuxagent/distro/debian/loader.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/default/__init__.py b/azurelinuxagent/distro/default/__init__.py index 4b2b9e1..d9b82f5 100644 --- a/azurelinuxagent/distro/default/__init__.py +++ b/azurelinuxagent/distro/default/__init__.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/default/deprovision.py b/azurelinuxagent/distro/default/deprovision.py index 231f4eb..b62c5f6 100644 --- a/azurelinuxagent/distro/default/deprovision.py +++ b/azurelinuxagent/distro/default/deprovision.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # @@ -19,6 +19,7 @@ import azurelinuxagent.conf as conf from azurelinuxagent.utils.osutil import OSUTIL +from azurelinuxagent.future import read_input import azurelinuxagent.protocol as prot import azurelinuxagent.protocol.ovfenv as ovf import azurelinuxagent.utils.fileutil as fileutil @@ -58,8 +59,6 @@ class DeprovisionHandler(object): def regen_ssh_host_key(self, warnings, actions): warnings.append("WARNING! All SSH host key pairs will be deleted.") - actions.append(DeprovisionAction(OSUTIL.set_hostname, - ['localhost.localdomain'])) actions.append(DeprovisionAction(shellutil.run, ['rm -f /etc/ssh/ssh_host_*key*'])) @@ -80,6 +79,11 @@ class DeprovisionHandler(object): dirs_to_del = [OSUTIL.get_lib_dir()] actions.append(DeprovisionAction(fileutil.rm_dirs, dirs_to_del)) + def reset_hostname(self, warnings, actions): + localhost = ["localhost.localdomain"] + actions.append(DeprovisionAction(OSUTIL.set_hostname, localhost)) + actions.append(DeprovisionAction(OSUTIL.set_dhcp_hostname, localhost)) + def setup(self, deluser): warnings = [] actions = [] @@ -89,6 +93,7 @@ class DeprovisionHandler(object): self.regen_ssh_host_key(warnings, actions) self.del_dhcp_lease(warnings, actions) + self.reset_hostname(warnings, actions) if conf.get_switch("Provisioning.DeleteRootPassword", False): self.del_root_password(warnings, actions) @@ -107,7 +112,7 @@ class DeprovisionHandler(object): print(warning) if not force: - confirm = input("Do you want to proceed (y/n)") + confirm = read_input("Do you want to proceed (y/n)") if not confirm.lower().startswith('y'): return diff --git a/azurelinuxagent/distro/default/dhcp.py b/azurelinuxagent/distro/default/dhcp.py index 574ebd4..4fd23ef 100644 --- a/azurelinuxagent/distro/default/dhcp.py +++ b/azurelinuxagent/distro/default/dhcp.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/default/env.py b/azurelinuxagent/distro/default/env.py index 6a67113..28bf718 100644 --- a/azurelinuxagent/distro/default/env.py +++ b/azurelinuxagent/distro/default/env.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/default/extension.py b/azurelinuxagent/distro/default/extension.py index 58ba84e..f6c02aa 100644 --- a/azurelinuxagent/distro/default/extension.py +++ b/azurelinuxagent/distro/default/extension.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # @@ -21,18 +21,35 @@ import zipfile import time import json import subprocess +import shutil import azurelinuxagent.logger as logger from azurelinuxagent.future import text from azurelinuxagent.utils.osutil import OSUTIL import azurelinuxagent.protocol as prot +from azurelinuxagent.metadata import AGENT_VERSION from azurelinuxagent.event import add_event, WALAEventOperation from azurelinuxagent.exception import ExtensionError import azurelinuxagent.utils.fileutil as fileutil import azurelinuxagent.utils.restutil as restutil import azurelinuxagent.utils.shellutil as shellutil +from azurelinuxagent.utils.textutil import Version + +#HandlerEnvironment.json schema version +HANDLER_ENVIRONMENT_VERSION = 1.0 VALID_EXTENSION_STATUS = ['transitioning', 'error', 'success', 'warning'] +VALID_HANDLER_STATUS = ['Ready', 'NotReady', "Installing", "Unresponsive"] + +def handler_state_to_status(handler_state): + if handler_state == "Enabled": + return "Ready" + elif handler_state in VALID_HANDLER_STATUS: + return handler_state + else: + return "NotReady" + + def validate_has_key(obj, key, fullname): if key not in obj: raise ExtensionError("Missing: {0}".format(fullname)) @@ -41,103 +58,52 @@ def validate_in_range(val, valid_range, name): if val not in valid_range: raise ExtensionError("Invalid {0}: {1}".format(name, val)) -def try_get(dictionary, key, default=None): - try: - return dictionary[key] - except KeyError: - return default +def parse_formatted_message(formatted_message): + if formatted_message is None: + return None + validate_has_key(formatted_message, 'lang', 'formattedMessage/lang') + validate_has_key(formatted_message, 'message', 'formattedMessage/message') + return formatted_message.get('message') + -def extension_sub_status_to_v2(substatus): +def parse_ext_substatus(substatus): #Check extension sub status format - validate_has_key(substatus, 'name', 'substatus/name') validate_has_key(substatus, 'status', 'substatus/status') - validate_has_key(substatus, 'code', 'substatus/code') - validate_has_key(substatus, 'formattedMessage', 'substatus/formattedMessage') - validate_has_key(substatus['formattedMessage'], 'lang', - 'substatus/formattedMessage/lang') - validate_has_key(substatus['formattedMessage'], 'message', - 'substatus/formattedMessage/message') - validate_in_range(substatus['status'], VALID_EXTENSION_STATUS, 'substatus/status') status = prot.ExtensionSubStatus() - status.name = try_get(substatus, 'name') - status.status = try_get(substatus, 'status') - status.code = try_get(substatus, 'code') - status.message = try_get(substatus['formattedMessage'], 'message') + status.name = substatus.get('name') + status.status = substatus.get('status') + status.code = substatus.get('code', 0) + formatted_message = substatus.get('formattedMessage') + status.message = parse_formatted_message(formatted_message) return status -def ext_status_to_v2(ext_status, seq_no): +def parse_ext_status(ext_status, data): + if data is None or len(data) is None: + return + #Currently, only the first status will be reported + data = data[0] #Check extension status format - validate_has_key(ext_status, 'status', 'status') - validate_has_key(ext_status['status'], 'status', 'status/status') - validate_has_key(ext_status['status'], 'operation', 'status/operation') - validate_has_key(ext_status['status'], 'code', 'status/code') - validate_has_key(ext_status['status'], 'name', 'status/name') - validate_has_key(ext_status['status'], 'formattedMessage', - 'status/formattedMessage') - validate_has_key(ext_status['status']['formattedMessage'], 'lang', - 'status/formattedMessage/lang') - validate_has_key(ext_status['status']['formattedMessage'], 'message', - 'status/formattedMessage/message') - - validate_in_range(ext_status['status']['status'], VALID_EXTENSION_STATUS, + validate_has_key(data, 'status', 'status') + status_data = data['status'] + validate_has_key(status_data, 'status', 'status/status') + + validate_in_range(status_data['status'], VALID_EXTENSION_STATUS, 'status/status') - status = prot.ExtensionStatus() - status.name = try_get(ext_status['status'], 'name') - status.configurationAppliedTime = try_get(ext_status['status'], - 'configurationAppliedTime') - status.operation = try_get(ext_status['status'], 'operation') - status.status = try_get(ext_status['status'], 'status') - status.code = try_get(ext_status['status'], 'code') - status.message = try_get(ext_status['status']['formattedMessage'], 'message') - status.sequenceNumber = seq_no - - substatus_list = try_get(ext_status['status'], 'substatus', []) + applied_time = status_data.get('configurationAppliedTime') + ext_status.configurationAppliedTime = applied_time + ext_status.operation = status_data.get('operation') + ext_status.status = status_data.get('status') + ext_status.code = status_data.get('code', 0) + formatted_message = status_data.get('formattedMessage') + ext_status.message = parse_formatted_message(formatted_message) + substatus_list = status_data.get('substatus') + if substatus_list is None: + return for substatus in substatus_list: - status.substatusList.extend(extension_sub_status_to_v2(substatus)) - return status - -class ExtensionsHandler(object): - - def process(self): - protocol = prot.FACTORY.get_default_protocol() - ext_list = protocol.get_extensions() - - h_status_list = [] - for extension in ext_list.extensions: - #TODO handle extension in parallel - pkg_list = protocol.get_extension_pkgs(extension) - h_status = self.process_extension(extension, pkg_list) - h_status_list.append(h_status) - - return h_status_list - - def process_extension(self, extension, pkg_list): - installed_version = get_installed_version(extension.name) - if installed_version is not None: - ext = ExtensionInstance(extension, pkg_list, - installed_version, installed=True) - else: - ext = ExtensionInstance(extension, pkg_list, - extension.properties.version) - try: - ext.init_logger() - ext.handle() - status = ext.collect_handler_status() - except ExtensionError as e: - logger.error("Failed to handle extension: {0}-{1}\n {2}", - ext.get_name(), ext.get_version(), e) - add_event(name=ext.get_name(), is_success=False, - op=ext.get_curr_op(), message = text(e)) - ext_status = prot.ExtensionStatus(status='error', code='-1', - operation = ext.get_curr_op(), - message = text(e), - seq_no = ext.get_seq_no()) - status = ext.create_handler_status(ext_status) - status.status = "Ready" - return status + ext_status.substatusList.append(parse_ext_substatus(substatus)) def parse_extension_dirname(dirname): """ @@ -160,67 +126,204 @@ def get_installed_version(target_name): name, version = parse_extension_dirname(dir_name) #Here we need to ensure names are exactly the same. if name == target_name: - if installed_version is None or installed_version < version: + if installed_version is None or \ + Version(installed_version) < Version(version): installed_version = version return installed_version -class ExtensionInstance(object): - def __init__(self, extension, pkg_list, curr_version, installed=False): - self.extension = extension +class ExtHandlerState(object): + Enabled = "Enabled" + Disabled = "Disabled" + Failed = "Failed" + + +class ExtHandlersHandler(object): + + def process(self): + try: + protocol = prot.FACTORY.get_default_protocol() + ext_handlers = protocol.get_ext_handlers() + except prot.ProtocolError as e: + add_event(name="WALA", is_success=False, message = text(e)) + return + + + vm_status = prot.VMStatus() + vm_status.vmAgent.version = AGENT_VERSION + vm_status.vmAgent.status = "Ready" + vm_status.vmAgent.message = "Guest Agent is running" + + if ext_handlers.extHandlers is None or \ + len(ext_handlers.extHandlers) == 0: + logger.verb("No extensions to handle") + else: + for ext_handler in ext_handlers.extHandlers: + #TODO handle extension in parallel + try: + pkg_list = protocol.get_ext_handler_pkgs(ext_handler) + except prot.ProtocolError as e: + add_event(name="WALA", is_success=False, message=text(e)) + continue + + handler_status = self.process_extension(ext_handler, pkg_list) + if handler_status is not None: + vm_status.vmAgent.extensionHandlers.append(handler_status) + + try: + logger.verb("Report vm agent status") + protocol.report_vm_status(vm_status) + except prot.ProtocolError as e: + add_event(name="WALA", is_success=False, message = text(e)) + + def process_extension(self, ext_handler, pkg_list): + installed_version = get_installed_version(ext_handler.name) + if installed_version is not None: + handler = ExtHandlerInstance(ext_handler, pkg_list, + installed_version, installed=True) + else: + handler = ExtHandlerInstance(ext_handler, pkg_list, + ext_handler.properties.version) + handler.handle() + + if handler.ext_status is not None: + try: + protocol = prot.FACTORY.get_default_protocol() + protocol.report_ext_status(handler.name, handler.ext.name, + handler.ext_status) + except prot.ProtocolError as e: + add_event(name="WALA", is_success=False, message=text(e)) + + return handler.handler_status + +class ExtHandlerInstance(object): + def __init__(self, ext_handler, pkg_list, curr_version, installed=False): + self.ext_handler = ext_handler + self.name = ext_handler.name + self.version = ext_handler.properties.version self.pkg_list = pkg_list + self.state = ext_handler.properties.state + self.update_policy = ext_handler.properties.upgradePolicy + self.curr_version = curr_version - self.lib_dir = OSUTIL.get_lib_dir() self.installed = installed - self.settings = None - - #Extension will have no more than 1 settings instance - if len(extension.properties.extensions) > 0: - self.settings = extension.properties.extensions[0] - self.enabled = False - self.curr_op = None + self.handler_state = None + self.lib_dir = OSUTIL.get_lib_dir() + + self.ext_status = prot.ExtensionStatus() + self.handler_status = prot.ExtHandlerStatus() + self.handler_status.name = self.name + self.handler_status.version = self.curr_version + + #Currently, extension settings will have no more than 1 instance + if len(ext_handler.properties.extensions) > 0: + self.ext = ext_handler.properties.extensions[0] + self.handler_status.extensions = [self.ext.name] + else: + #When no extension settings, set sequenceNumber to 0 + self.ext = prot.Extension(sequenceNumber=0) + self.ext_status.sequenceNumber = self.ext.sequenceNumber prefix = "[{0}]".format(self.get_full_name()) self.logger = logger.Logger(logger.DEFAULT_LOGGER, prefix) def init_logger(self): #Init logger appender for extension - fileutil.mkdir(self.get_log_dir(), mode=0o700) + fileutil.mkdir(self.get_log_dir(), mode=0o644) log_file = os.path.join(self.get_log_dir(), "CommandExecution.log") self.logger.add_appender(logger.AppenderType.FILE, - logger.LogLevel.INFO, log_file) + logger.LogLevel.INFO, log_file) def handle(self): - self.logger.info("Process extension settings:") - self.logger.info(" Name: {0}", self.get_name()) - self.logger.info(" Version: {0}", self.get_version()) + self.init_logger() + self.logger.verb("Start processing extension handler") + + try: + self.handle_state() + except ExtensionError as e: + self.set_state_err(text(e)) + self.report_event(is_success=False, message=text(e)) + self.logger.error("Failed to process extension handler") + return + try: + if self.installed: + self.collect_ext_status() + self.collect_handler_status() + except ExtensionError as e: + self.report_event(is_success=False, message=text(e)) + self.logger.error("Failed to get extension handler status") + return + + self.logger.verb("Finished processing extension handler") + + def handle_state(self): if self.installed: - self.logger.info("Installed version:{0}", self.curr_version) - h_status = self.get_handler_status() - self.enabled = (h_status == "Ready") - - state = self.get_state() - if state == 'enabled': - self.handle_enable() - elif state == 'disabled': - self.handle_disable() - elif state == 'uninstall': - self.handle_disable() - self.handle_uninstall() + self.handler_state = self.get_state() + + self.handler_status.status = handler_state_to_status(self.handler_state) + self.logger.verb("Handler state: {0}", self.handler_state) + self.logger.verb("Sequence number: {0}", self.ext.sequenceNumber) + + if self.state == 'enabled': + if self.handler_state == ExtHandlerState.Failed: + self.logger.verb("Found previous failure, quit handle_enable") + return + + if self.handler_state == ExtHandlerState.Enabled: + self.logger.verb("Already enabled with sequenceNumber: {0}", + self.ext.sequenceNumber) + self.logger.verb("Quit handle_enable") + return + + try: + new = self.handle_enable() + if new is not None: + #Upgrade happened + new.set_state(ExtHandlerState.Enabled) + else: + self.set_state(ExtHandlerState.Enabled) + + except ExtensionError as e: + self.set_state(ExtHandlerState.Failed) + raise e + elif self.state == 'disabled': + if self.handler_state == ExtHandlerState.Failed: + self.logger.verb("Found previous failure, quit handle_disable") + return + + if self.handler_state == ExtHandlerState.Disabled: + self.logger.verb("Already disabled with sequenceNumber: {0}", + self.ext.sequenceNumber) + self.logger.verb("Quit handle_disable") + return + + try: + self.handle_disable() + self.set_state(ExtHandlerState.Disabled) + except ExtensionError as e: + self.set_state(ExtHandlerState.Failed) + raise e + elif self.state == 'uninstall': + try: + self.handle_uninstall() + except ExtensionError as e: + self.set_state(ExtHandlerState.Failed) + raise e else: - raise ExtensionError("Unknown extension state:{0}".format(state)) + raise ExtensionError("Unknown state:{0}".format(self.state)) def handle_enable(self): target_version = self.get_target_version() + self.logger.info("Target version: {0}", target_version) if self.installed: - if target_version > self.curr_version: - self.upgrade(target_version) - elif target_version == self.curr_version: + if Version(target_version) > Version(self.curr_version): + return self.upgrade(target_version) + elif Version(target_version) == Version(self.curr_version): self.enable() else: - raise ExtensionError("A newer version has already been installed") + raise ExtensionError("A newer version is already installed") else: - if target_version > self.get_version(): + if Version(target_version) > Version(self.version): #This will happen when auto upgrade policy is enabled self.logger.info("Auto upgrade to new version:{0}", target_version) @@ -231,21 +334,45 @@ class ExtensionInstance(object): self.enable() def handle_disable(self): - if not self.installed or not self.enabled: + if not self.installed: + self.logger.verb("Not installed, quit disable") return + self.disable() def handle_uninstall(self): if not self.installed: + self.logger.verb("Not installed, quit unistall") + self.handler_status = None + self.ext_status = None return + self.disable() self.uninstall() + def report_event(self, is_success=True, message=""): + if self.ext_status is not None: + if not is_success: + self.ext_status.status = "error" + self.ext_status.code = -1 + if self.handler_status is not None: + self.handler_status.message = message + if not is_success: + self.handler_status.status = "NotReady" + add_event(name=self.name, op=self.ext_status.operation, + is_success=is_success, message=message) + + def set_operation(self, operation): + if self.ext_status.operation != WALAEventOperation.Upgrade: + self.ext_status.operation = operation + def upgrade(self, target_version): self.logger.info("Upgrade from: {0} to {1}", self.curr_version, target_version) - self.curr_op=WALAEventOperation.Upgrade + self.set_operation(WALAEventOperation.Upgrade) + old = self - new = ExtensionInstance(self.extension, self.pkg_list, target_version) + new = ExtHandlerInstance(self.ext_handler, self.pkg_list, + target_version) self.logger.info("Download new extension package") new.init_logger() new.download() @@ -262,19 +389,20 @@ class ExtensionInstance(object): new.install() self.logger.info("Enable new extension") new.enable() - add_event(name=self.get_name(), is_success=True, - op=self.curr_op, message="") + return new def download(self): self.logger.info("Download extension package") - self.curr_op=WALAEventOperation.Download + self.set_operation(WALAEventOperation.Download) + uris = self.get_package_uris() package = None for uri in uris: try: resp = restutil.http_get(uri.uri, chk_proxy=True) - package = resp.read() - break + if resp.status == restutil.httpclient.OK: + package = resp.read() + break except restutil.HttpError as e: self.logger.warn("Failed download extension from: {0}", uri.uri) @@ -287,14 +415,13 @@ class ExtensionInstance(object): zipfile.ZipFile(pkg_file).extractall(self.get_base_dir()) chmod = "find {0} -type f | xargs chmod u+x".format(self.get_base_dir()) shellutil.run(chmod) - add_event(name=self.get_name(), is_success=True, - op=self.curr_op, message="") + self.report_event(message="Download succeeded") def init_dir(self): self.logger.info("Initialize extension directory") #Save HandlerManifest.json man_file = fileutil.search_file(self.get_base_dir(), - 'HandlerManifest.json') + 'HandlerManifest.json') man = fileutil.read_file(man_file, remove_bom=True) fileutil.write_file(self.get_manifest_file(), man) @@ -303,106 +430,141 @@ class ExtensionInstance(object): fileutil.mkdir(status_dir, mode=0o700) conf_dir = self.get_conf_dir() fileutil.mkdir(conf_dir, mode=0o700) - - #Init handler state to uninstall - self.set_handler_status("NotReady") + + self.make_handler_state_dir() #Save HandlerEnvironment.json self.create_handler_env() def enable(self): self.logger.info("Enable extension.") - self.curr_op=WALAEventOperation.Enable + self.set_operation(WALAEventOperation.Enable) + man = self.load_manifest() self.launch_command(man.get_enable_command()) - self.set_handler_status("Ready") - add_event(name=self.get_name(), is_success=True, - op=self.curr_op, message="") def disable(self): self.logger.info("Disable extension.") - self.curr_op=WALAEventOperation.Disable + self.set_operation(WALAEventOperation.Disable) + man = self.load_manifest() self.launch_command(man.get_disable_command(), timeout=900) - self.set_handler_status("Ready") - add_event(name=self.get_name(), is_success=True, - op=self.curr_op, message="") def install(self): self.logger.info("Install extension.") - self.curr_op=WALAEventOperation.Install + self.set_operation(WALAEventOperation.Install) + man = self.load_manifest() - self.set_handler_status("Installing") self.launch_command(man.get_install_command(), timeout=900) - self.set_handler_status("Ready") - add_event(name=self.get_name(), is_success=True, - op=self.curr_op, message="") + self.installed = True def uninstall(self): self.logger.info("Uninstall extension.") - self.curr_op=WALAEventOperation.UnInstall + self.set_operation(WALAEventOperation.UnInstall) + man = self.load_manifest() self.launch_command(man.get_uninstall_command()) - self.set_handler_status("NotReady") - add_event(name=self.get_name(), is_success=True, - op=self.curr_op, message="") + + self.logger.info("Remove ext handler dir: {0}", self.get_base_dir()) + try: + shutil.rmtree(self.get_base_dir()) + except IOError as e: + raise ExtensionError("Failed to rm ext handler dir: {0}".format(e)) + + self.installed = False + self.handler_status = None + self.ext_status = None def update(self): self.logger.info("Update extension.") - self.curr_op=WALAEventOperation.Update + self.set_operation(WALAEventOperation.Update) + man = self.load_manifest() self.launch_command(man.get_update_command(), timeout=900) - add_event(name=self.get_name(), is_success=True, - op=self.curr_op, message="") - - def create_handler_status(self, ext_status, heartbeat=None): - status = prot.ExtensionHandlerStatus() - status.handlerName = self.get_name() - status.handlerVersion = self.get_version() - status.status = self.get_handler_status() - status.extensionStatusList.append(ext_status) - return status def collect_handler_status(self): + self.logger.verb("Collect extension handler status") + if self.handler_status is None: + return + + handler_state = self.get_state() + self.handler_status.status = handler_state_to_status(handler_state) + self.handler_status.message = self.get_state_err() man = self.load_manifest() - heartbeat=None if man.is_report_heartbeat(): heartbeat = self.collect_heartbeat() - ext_status = self.collect_extension_status() - status= self.create_handler_status(ext_status, heartbeat) - status.status = self.get_handler_status() - if heartbeat is not None: - status.status = heartbeat['status'] - status.extensionStatusList.append(ext_status) - return status - - def collect_extension_status(self): + if heartbeat is not None: + self.handler_status.status = heartbeat['status'] + + def collect_ext_status(self): + self.logger.verb("Collect extension status") + if self.handler_status is None: + return + + if self.ext is None: + return + ext_status_file = self.get_status_file() try: - ext_status_str = fileutil.read_file(ext_status_file) - ext_status = json.loads(ext_status_str) + data_str = fileutil.read_file(ext_status_file) + data = json.loads(data_str) + parse_ext_status(self.ext_status, data) except IOError as e: raise ExtensionError("Failed to get status file: {0}".format(e)) except ValueError as e: raise ExtensionError("Malformed status file: {0}".format(e)) - return ext_status_to_v2(ext_status[0], - self.settings.sequenceNumber) + + def make_handler_state_dir(self): + handler_state_dir = self.get_handler_state_dir() + fileutil.mkdir(handler_state_dir, 0o600) + if not os.path.exists(handler_state_dir): + os.makedirs(handler_state_dir) - def get_handler_status(self): - h_status = "uninstalled" - h_status_file = self.get_handler_state_file() + def get_state(self): + handler_state_file = self.get_handler_state_file() + if not os.path.isfile(handler_state_file): + return None try: - h_status = fileutil.read_file(h_status_file) - return h_status + handler_state = fileutil.read_file(handler_state_file) + if handler_state is not None: + handler_state = handler_state.rstrip() + return handler_state except IOError as e: - raise ExtensionError("Failed to get handler status: {0}".format(e)) + err = "Failed to get handler state: {0}".format(e) + add_event(name=self.name, is_success=False, message=err) - def set_handler_status(self, status): - h_status_file = self.get_handler_state_file() + def set_state(self, state): + handler_state_file = self.get_handler_state_file() + if not os.path.isfile(handler_state_file): + self.make_handler_state_dir() + try: + fileutil.write_file(handler_state_file, state) + except IOError as e: + err = "Failed to set handler state: {0}".format(e) + add_event(name=self.name, is_success=False, message=err) + + def get_state_err(self): + """Get handler error message""" + handler_state_err_file= self.get_handler_state_err_file() + if not os.path.isfile(handler_state_err_file): + return None try: - fileutil.write_file(h_status_file, status) + message = fileutil.read_file(handler_state_err_file) + return message except IOError as e: - raise ExtensionError("Failed to set handler status: {0}".format(e)) + err = "Failed to get handler state message: {0}".format(e) + add_event(name=self.name, is_success=False, message=err) + + def set_state_err(self, message): + """Set handler error message""" + handler_state_err_file = self.get_handler_state_err_file() + if not os.path.isfile(handler_state_err_file): + self.make_handler_state_dir() + try: + fileutil.write_file(handler_state_err_file, message) + except IOError as e: + err = "Failed to set handler state message: {0}".format(e) + add_event(name=self.name, is_success=False, message=err) def collect_heartbeat(self): self.logger.info("Collect heart beat") @@ -426,7 +588,7 @@ class ExtensionInstance(object): return heartbeat def is_responsive(self, heartbeat_file): - last_update=int(time.time()-os.stat(heartbeat_file).st_mtime) + last_update=int(time.time() - os.stat(heartbeat_file).st_mtime) return last_update > 600 # not updated for more than 10 min def launch_command(self, cmd, timeout=300): @@ -452,6 +614,7 @@ class ExtensionInstance(object): ret = child.wait() if ret == None or ret != 0: raise ExtensionError("Non-zero exit code: {0}, {1}".format(ret, cmd)) + self.report_event(message="Launch command succeeded: {0}".format(cmd)) def load_manifest(self): man_file = self.get_manifest_file() @@ -464,16 +627,15 @@ class ExtensionInstance(object): return HandlerManifest(data[0]) - def update_settings(self): - if self.settings is None: - self.logger.verbose("Extension has no settings") + if self.ext is None: + self.logger.verb("Extension has no settings") return settings = { - 'publicSettings': self.settings.publicSettings, - 'protectedSettings': self.settings.privateSettings, - 'protectedSettingsCertThumbprint': self.settings.certificateThumbprint + 'publicSettings': self.ext.publicSettings, + 'protectedSettings': self.ext.privateSettings, + 'protectedSettingsCertThumbprint': self.ext.certificateThumbprint } ext_settings = { "runtimeSettings":[{ @@ -482,13 +644,10 @@ class ExtensionInstance(object): } fileutil.write_file(self.get_settings_file(), json.dumps(ext_settings)) - latest = os.path.join(self.get_conf_dir(), "latest") - fileutil.write_file(latest, self.settings.sequenceNumber) - def create_handler_env(self): env = [{ - "name": self.get_name(), - "version" : self.get_version(), + "name": self.name, + "version" : HANDLER_ENVIRONMENT_VERSION, "handlerEnvironment" : { "logFolder" : self.get_log_dir(), "configFolder" : self.get_conf_dir(), @@ -500,8 +659,8 @@ class ExtensionInstance(object): json.dumps(env)) def get_target_version(self): - version = self.get_version() - update_policy = self.get_upgrade_policy() + version = self.version + update_policy = self.update_policy if update_policy is None or update_policy.lower() != 'auto': return version @@ -509,45 +668,29 @@ class ExtensionInstance(object): if major is None: raise ExtensionError("Wrong version format: {0}".format(version)) - packages = [x for x in self.pkg_list.versions if x.version.startswith(major + ".")] - packages = sorted(packages, key=lambda x: x.version, reverse=True) + packages = [x for x in self.pkg_list.versions \ + if x.version.startswith(major + ".")] + packages = sorted(packages, key=lambda x: Version(x.version), + reverse=True) if len(packages) <= 0: raise ExtensionError("Can't find version: {0}.*".format(major)) return packages[0].version def get_package_uris(self): - version = self.get_version() + version = self.curr_version packages = self.pkg_list.versions if packages is None: raise ExtensionError("Package uris is None.") for package in packages: - if package.version == version: + if Version(package.version) == Version(version): return package.uris raise ExtensionError("Can't get package uris for {0}.".format(version)) - - def get_curr_op(self): - return self.curr_op - - def get_name(self): - return self.extension.name - - def get_version(self): - return self.extension.properties.version - - def get_state(self): - return self.extension.properties.state - - def get_seq_no(self): - return self.settings.sequenceNumber - - def get_upgrade_policy(self): - return self.extension.properties.upgradePolicy - + def get_full_name(self): - return "{0}-{1}".format(self.get_name(), self.curr_version) + return "{0}-{1}".format(self.name, self.curr_version) def get_base_dir(self): return os.path.join(OSUTIL.get_lib_dir(), self.get_full_name()) @@ -557,17 +700,27 @@ class ExtensionInstance(object): def get_status_file(self): return os.path.join(self.get_status_dir(), - "{0}.status".format(self.settings.sequenceNumber)) + "{0}.status".format(self.ext.sequenceNumber)) def get_conf_dir(self): return os.path.join(self.get_base_dir(), 'config') def get_settings_file(self): return os.path.join(self.get_conf_dir(), - "{0}.settings".format(self.settings.sequenceNumber)) + "{0}.settings".format(self.ext.sequenceNumber)) + + def get_handler_state_dir(self): + return os.path.join(OSUTIL.get_lib_dir(), "handler_state", + self.get_full_name()) def get_handler_state_file(self): - return os.path.join(self.get_conf_dir(), 'HandlerState') + return os.path.join(self.get_handler_state_dir(), + '{0}.state'.format(self.ext.sequenceNumber)) + + def get_handler_state_err_file(self): + return os.path.join(self.get_handler_state_dir(), + '{0}.error'.format(self.ext.sequenceNumber)) + def get_heartbeat_file(self): return os.path.join(self.get_base_dir(), 'heartbeat.log') @@ -579,7 +732,7 @@ class ExtensionInstance(object): return os.path.join(self.get_base_dir(), 'HandlerEnvironment.json') def get_log_dir(self): - return os.path.join(OSUTIL.get_ext_log_dir(), self.get_name(), + return os.path.join(OSUTIL.get_ext_log_dir(), self.name, self.curr_version) class HandlerEnvironment(object): diff --git a/azurelinuxagent/distro/default/handlerFactory.py b/azurelinuxagent/distro/default/handlerFactory.py index 98b2380..dceb2a3 100644 --- a/azurelinuxagent/distro/default/handlerFactory.py +++ b/azurelinuxagent/distro/default/handlerFactory.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # @@ -23,7 +23,7 @@ from .dhcp import DhcpHandler from .env import EnvHandler from .provision import ProvisionHandler from .resourceDisk import ResourceDiskHandler -from .extension import ExtensionsHandler +from .extension import ExtHandlersHandler from .deprovision import DeprovisionHandler class DefaultHandlerFactory(object): @@ -35,6 +35,6 @@ class DefaultHandlerFactory(object): self.env_handler = EnvHandler(self) self.provision_handler = ProvisionHandler() self.resource_disk_handler = ResourceDiskHandler() - self.extension_handler = ExtensionsHandler() + self.ext_handlers_handler = ExtHandlersHandler() self.deprovision_handler = DeprovisionHandler() diff --git a/azurelinuxagent/distro/default/init.py b/azurelinuxagent/distro/default/init.py index 337fdea..db74fef 100644 --- a/azurelinuxagent/distro/default/init.py +++ b/azurelinuxagent/distro/default/init.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/default/loader.py b/azurelinuxagent/distro/default/loader.py index d7dbe87..55a51e0 100644 --- a/azurelinuxagent/distro/default/loader.py +++ b/azurelinuxagent/distro/default/loader.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/default/osutil.py b/azurelinuxagent/distro/default/osutil.py index 8e3fb77..00a57cc 100644 --- a/azurelinuxagent/distro/default/osutil.py +++ b/azurelinuxagent/distro/default/osutil.py @@ -117,22 +117,16 @@ class DefaultOSUtil(object): "retcode:{1}, " "output:{2}").format(username, retcode, out)) - def chpasswd(self, username, password, use_salt=True, salt_type=6, - salt_len=10): + def chpasswd(self, username, password, crypt_id=6, salt_len=10): if self.is_sys_user(username): raise OSUtilError(("User {0} is a system user. " "Will not set passwd.").format(username)) - passwd_hash = textutil.gen_password_hash(password, use_salt, salt_type, - salt_len) - try: - passwd_content = fileutil.read_file(self.passwd_file_path) - passwd = passwd_content.split("\n") - new_passwd = [x for x in passwd if not x.startswith(username)] - new_passwd.append("{0}:{1}:14600::::::".format(username, passwd_hash)) - fileutil.write_file(self.passwd_file_path, "\n".join(new_passwd)) - except IOError as e: + passwd_hash = textutil.gen_password_hash(password, crypt_id, salt_len) + cmd = "usermod -p '{0}' {1}".format(passwd_hash, username) + ret, output = shellutil.run_get_output(cmd, log_cmd=False) + if ret != 0: raise OSUtilError(("Failed to set password for {0}: {1}" - "").format(username, e)) + "").format(username, output)) def conf_sudoer(self, username, nopasswd): # for older distros create sudoers.d @@ -344,9 +338,10 @@ class DefaultOSUtil(object): raise OSUtilError("Failed to umount dvd.") def eject_dvd(self, chk_err=True): - retcode = shellutil.run("eject") + dvd = self.get_dvd_device() + retcode = shellutil.run("eject {0}".format(dvd)) if chk_err and retcode != 0: - raise OSUtilError("Failed to eject dvd") + raise OSUtilError("Failed to eject dvd: ret={0}".format(retcode)) def load_atappix_mod(self): if self.is_atapiix_mod_loaded(): diff --git a/azurelinuxagent/distro/default/provision.py b/azurelinuxagent/distro/default/provision.py index 1e9c459..424f083 100644 --- a/azurelinuxagent/distro/default/provision.py +++ b/azurelinuxagent/distro/default/provision.py @@ -49,8 +49,13 @@ class ProvisionHandler(object): protocol = prot.FACTORY.get_default_protocol() try: status = prot.ProvisionStatus(status="NotReady", - subStatus="Provision started") - protocol.report_provision_status(status) + subStatus="Provisioning", + description="Starting") + try: + protocol.report_provision_status(status) + except prot.ProtocolError as e: + add_event(name="WALA", is_success=False, message=text(e), + op=WALAEventOperation.Provision) self.provision() fileutil.write_file(provisioned, "") @@ -59,17 +64,28 @@ class ProvisionHandler(object): logger.info("Finished provisioning") status = prot.ProvisionStatus(status="Ready") status.properties.certificateThumbprint = thumbprint - protocol.report_provision_status(status) + + try: + protocol.report_provision_status(status) + except prot.ProtocolError as pe: + add_event(name="WALA", is_success=False, message=text(pe), + op=WALAEventOperation.Provision) add_event(name="WALA", is_success=True, message="", - op=WALAEventOperation.Provision) + op=WALAEventOperation.Provision) except ProvisionError as e: logger.error("Provision failed: {0}", e) status = prot.ProvisionStatus(status="NotReady", - subStatus= text(e)) - protocol.report_provision_status(status) + subStatus="ProvisioningFailed", + description= text(e)) + try: + protocol.report_provision_status(status) + except prot.ProtocolError as pe: + add_event(name="WALA", is_success=False, message=text(pe), + op=WALAEventOperation.Provision) + add_event(name="WALA", is_success=False, message=text(e), - op=WALAEventOperation.Provision) + op=WALAEventOperation.Provision) def reg_ssh_host_key(self): keypair_type = conf.get("Provisioning.SshHostKeyPairType", "rsa") @@ -120,10 +136,10 @@ class ProvisionHandler(object): if ovfenv.user_password is not None: logger.info("Set user password.") - use_salt = conf.get_switch("Provision.UseSalt", True) - salt_type = conf.get_switch("Provision.SaltType", 6) - OSUTIL.chpasswd(ovfenv.username, ovfenv.user_password, - use_salt,salt_type) + crypt_id = conf.get("Provision.PasswordCryptId", "6") + salt_len = conf.get_int("Provision.PasswordCryptSaltLength", 10) + OSUTIL.chpasswd(ovfenv.username, ovfenv.user_password, + crypt_id=crypt_id, salt_len=salt_len) logger.info("Configure sudoer") OSUTIL.conf_sudoer(ovfenv.username, ovfenv.user_password is None) diff --git a/azurelinuxagent/distro/default/resourceDisk.py b/azurelinuxagent/distro/default/resourceDisk.py index d4ef1c9..734863c 100644 --- a/azurelinuxagent/distro/default/resourceDisk.py +++ b/azurelinuxagent/distro/default/resourceDisk.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/default/run.py b/azurelinuxagent/distro/default/run.py index 13880b4..dfd3b03 100644 --- a/azurelinuxagent/distro/default/run.py +++ b/azurelinuxagent/distro/default/run.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # @@ -27,8 +27,8 @@ from azurelinuxagent.metadata import AGENT_LONG_NAME, AGENT_VERSION, \ DISTRO_NAME, DISTRO_VERSION, \ DISTRO_FULL_NAME, PY_VERSION_MAJOR, \ PY_VERSION_MINOR, PY_VERSION_MICRO -import azurelinuxagent.protocol as prot import azurelinuxagent.event as event +import azurelinuxagent.protocol as prot from azurelinuxagent.utils.osutil import OSUTIL import azurelinuxagent.utils.fileutil as fileutil @@ -65,22 +65,7 @@ class MainHandler(object): protocol = prot.FACTORY.get_default_protocol() while True: - #Handle extensions - h_status_list = self.handlers.extension_handler.process() - - #Report status - vm_status = prot.VMStatus() - vm_status.vmAgent.agentVersion = AGENT_LONG_NAME - vm_status.vmAgent.status = "Ready" - vm_status.vmAgent.message = "Guest Agent is running" - for h_status in h_status_list: - vm_status.extensionHandlers.append(h_status) - try: - logger.info("Report vm status") - protocol.report_status(vm_status) - except prot.ProtocolError as e: - logger.error("Failed to report vm status: {0}", e) - + self.handlers.ext_handlers_handler.process() time.sleep(25) diff --git a/azurelinuxagent/distro/default/scvmm.py b/azurelinuxagent/distro/default/scvmm.py index 18fad4b..680c04b 100644 --- a/azurelinuxagent/distro/default/scvmm.py +++ b/azurelinuxagent/distro/default/scvmm.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/loader.py b/azurelinuxagent/distro/loader.py index 0060a7f..375abd2 100644 --- a/azurelinuxagent/distro/loader.py +++ b/azurelinuxagent/distro/loader.py @@ -25,7 +25,7 @@ def get_distro_loader(): logger.verb("Loading distro implemetation from: {0}", DISTRO_NAME) pkg_name = "azurelinuxagent.distro.{0}.loader".format(DISTRO_NAME) return __import__(pkg_name, fromlist="loader") - except ImportError as e: + except (ImportError, ValueError): logger.warn("Unable to load distro implemetation for {0}.", DISTRO_NAME) logger.warn("Use default distro implemetation instead.") return default_loader diff --git a/azurelinuxagent/distro/oracle/__init__.py b/azurelinuxagent/distro/oracle/__init__.py index 4b2b9e1..d9b82f5 100644 --- a/azurelinuxagent/distro/oracle/__init__.py +++ b/azurelinuxagent/distro/oracle/__init__.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/oracle/loader.py b/azurelinuxagent/distro/oracle/loader.py index 379f027..9dc428f 100644 --- a/azurelinuxagent/distro/oracle/loader.py +++ b/azurelinuxagent/distro/oracle/loader.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/redhat/__init__.py b/azurelinuxagent/distro/redhat/__init__.py index 4b2b9e1..d9b82f5 100644 --- a/azurelinuxagent/distro/redhat/__init__.py +++ b/azurelinuxagent/distro/redhat/__init__.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/redhat/loader.py b/azurelinuxagent/distro/redhat/loader.py index 911e74d..8d3c75b 100644 --- a/azurelinuxagent/distro/redhat/loader.py +++ b/azurelinuxagent/distro/redhat/loader.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/redhat/osutil.py b/azurelinuxagent/distro/redhat/osutil.py index c6c3016..7478867 100644 --- a/azurelinuxagent/distro/redhat/osutil.py +++ b/azurelinuxagent/distro/redhat/osutil.py @@ -122,15 +122,14 @@ class Redhat6xOSUtil(DefaultOSUtil): ret= shellutil.run_get_output("pidof dhclient") return ret[1] if ret[0] == 0 else None -class RedhatOSUtil(Redhat6xOSUtil): - def __init__(self): - super(RedhatOSUtil, self).__init__() - def set_hostname(self, hostname): - super(RedhatOSUtil, self).set_hostname(hostname) + """ + Set /etc/sysconfig/network + """ fileutil.update_conf_file('/etc/sysconfig/network', 'HOSTNAME', 'HOSTNAME={0}'.format(hostname)) + shellutil.run("hostname {0}".format(hostname), chk_err=False) def set_dhcp_hostname(self, hostname): ifname = self.get_if_name() @@ -139,6 +138,24 @@ class RedhatOSUtil(Redhat6xOSUtil): 'DHCP_HOSTNAME', 'DHCP_HOSTNAME={0}'.format(hostname)) +class RedhatOSUtil(Redhat6xOSUtil): + def __init__(self): + super(RedhatOSUtil, self).__init__() + + def set_hostname(self, hostname): + """ + Set /etc/hostname + Unlike redhat 6.x, redhat 7.x will set hostname to /etc/hostname + """ + DefaultOSUtil.set_hostname(self, hostname) + + def publish_hostname(self, hostname): + """ + Restart NetworkManager first before publishing hostname + """ + shellutil.run("service NetworkManager restart") + super(RedhatOSUtil, self).publish_hostname(hostname) + def register_agent_service(self): return shellutil.run("systemctl enable waagent", chk_err=False) diff --git a/azurelinuxagent/distro/suse/__init__.py b/azurelinuxagent/distro/suse/__init__.py index 4b2b9e1..d9b82f5 100644 --- a/azurelinuxagent/distro/suse/__init__.py +++ b/azurelinuxagent/distro/suse/__init__.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/suse/loader.py b/azurelinuxagent/distro/suse/loader.py index e38aa17..b01384b 100644 --- a/azurelinuxagent/distro/suse/loader.py +++ b/azurelinuxagent/distro/suse/loader.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/suse/osutil.py b/azurelinuxagent/distro/suse/osutil.py index 870e0b7..8d6f5bf 100644 --- a/azurelinuxagent/distro/suse/osutil.py +++ b/azurelinuxagent/distro/suse/osutil.py @@ -79,6 +79,26 @@ class SUSEOSUtil(SUSE11OSUtil): super(SUSEOSUtil, self).__init__() self.dhclient_name = 'wickedd-dhcp4' + def stop_dhcp_service(self): + cmd = "systemctl stop {0}".format(self.dhclient_name) + return shellutil.run(cmd, chk_err=False) + + def start_dhcp_service(self): + cmd = "systemctl start {0}".format(self.dhclient_name) + return shellutil.run(cmd, chk_err=False) + + def start_network(self) : + return shellutil.run("systemctl start network", chk_err=False) + + def restart_ssh_service(self): + return shellutil.run("systemctl restart sshd", chk_err=False) + + def stop_agent_service(self): + return shellutil.run("systemctl stop waagent", chk_err=False) + + def start_agent_service(self): + return shellutil.run("systemctl start waagent", chk_err=False) + def register_agent_service(self): return shellutil.run("systemctl enable waagent", chk_err=False) diff --git a/azurelinuxagent/distro/ubuntu/__init__.py b/azurelinuxagent/distro/ubuntu/__init__.py index 4b2b9e1..d9b82f5 100644 --- a/azurelinuxagent/distro/ubuntu/__init__.py +++ b/azurelinuxagent/distro/ubuntu/__init__.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/ubuntu/deprovision.py b/azurelinuxagent/distro/ubuntu/deprovision.py index 10fa123..0c3c4e5 100644 --- a/azurelinuxagent/distro/ubuntu/deprovision.py +++ b/azurelinuxagent/distro/ubuntu/deprovision.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/ubuntu/handlerFactory.py b/azurelinuxagent/distro/ubuntu/handlerFactory.py index c8d0906..11f7f04 100644 --- a/azurelinuxagent/distro/ubuntu/handlerFactory.py +++ b/azurelinuxagent/distro/ubuntu/handlerFactory.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # diff --git a/azurelinuxagent/distro/ubuntu/loader.py b/azurelinuxagent/distro/ubuntu/loader.py index 26db4fa..3fe2239 100644 --- a/azurelinuxagent/distro/ubuntu/loader.py +++ b/azurelinuxagent/distro/ubuntu/loader.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # @@ -17,16 +17,20 @@ # Requires Python 2.4+ and Openssl 1.0+ # -from azurelinuxagent.metadata import DISTRO_NAME, DISTRO_VERSION +from azurelinuxagent.metadata import DISTRO_NAME, DISTRO_VERSION, DISTRO_FULL_NAME def get_osutil(): from azurelinuxagent.distro.ubuntu.osutil import Ubuntu1204OSUtil, \ UbuntuOSUtil, \ - Ubuntu14xOSUtil + Ubuntu14xOSUtil, \ + UbuntuSnappyOSUtil + if DISTRO_VERSION == "12.04": return Ubuntu1204OSUtil() elif DISTRO_VERSION == "14.04" or DISTRO_VERSION == "14.10": return Ubuntu14xOSUtil() + elif DISTRO_FULL_NAME == "Snappy Ubuntu Core": + return UbuntuSnappyOSUtil() else: return UbuntuOSUtil() diff --git a/azurelinuxagent/distro/ubuntu/osutil.py b/azurelinuxagent/distro/ubuntu/osutil.py index 1e51c2a..adf7660 100644 --- a/azurelinuxagent/distro/ubuntu/osutil.py +++ b/azurelinuxagent/distro/ubuntu/osutil.py @@ -63,3 +63,13 @@ class UbuntuOSUtil(Ubuntu14xOSUtil): def unregister_agent_service(self): return shellutil.run("systemctl mask walinuxagent", chk_err=False) +class UbuntuSnappyOSUtil(Ubuntu14xOSUtil): + def __init__(self): + super(UbuntuSnappyOSUtil, self).__init__() + self.conf_file_path = '/apps/walinuxagent/current/waagent.conf' + + def remove_rules_files(self, rules_files=""): + pass + + def restore_rules_files(self, rules_files=""): + pass diff --git a/azurelinuxagent/distro/ubuntu/provision.py b/azurelinuxagent/distro/ubuntu/provision.py index 7551074..a68fe4d 100644 --- a/azurelinuxagent/distro/ubuntu/provision.py +++ b/azurelinuxagent/distro/ubuntu/provision.py @@ -1,4 +1,4 @@ -# Windows Azure Linux Agent +# Microsoft Azure Linux Agent # # Copyright 2014 Microsoft Corporation # @@ -23,6 +23,7 @@ import azurelinuxagent.logger as logger from azurelinuxagent.future import text import azurelinuxagent.conf as conf import azurelinuxagent.protocol as prot +from azurelinuxagent.event import add_event, WALAEventOperation from azurelinuxagent.exception import * from azurelinuxagent.utils.osutil import OSUTIL import azurelinuxagent.utils.shellutil as shellutil @@ -54,11 +55,25 @@ class UbuntuProvisionHandler(ProvisionHandler): logger.info("Finished provisioning") status = prot.ProvisionStatus(status="Ready") status.properties.certificateThumbprint = thumbprint - protocol.report_provision_status(status) + try: + protocol.report_provision_status(status) + except prot.ProtocolError as pe: + add_event(name="WALA", is_success=False, message=text(pe), + op=WALAEventOperation.Provision) except ProvisionError as e: logger.error("Provision failed: {0}", e) - protocol.report_provision_status(status="NotReady", subStatus=text(e)) + status = prot.ProvisionStatus(status="NotReady", + subStatus="ProvisioningFailed", + description= text(e)) + try: + protocol.report_provision_status(status) + except prot.ProtocolError as pe: + add_event(name="WALA", is_success=False, message=text(pe), + op=WALAEventOperation.Provision) + + add_event(name="WALA", is_success=False, message=text(e), + op=WALAEventOperation.Provision) def wait_for_ssh_host_key(self, max_retry=60): kepair_type = conf.get("Provisioning.SshHostKeyPairType", "rsa") |