summaryrefslogtreecommitdiff
path: root/azurelinuxagent/pa
diff options
context:
space:
mode:
Diffstat (limited to 'azurelinuxagent/pa')
-rw-r--r--azurelinuxagent/pa/deprovision/arch.py33
-rw-r--r--azurelinuxagent/pa/deprovision/default.py129
-rw-r--r--azurelinuxagent/pa/deprovision/factory.py3
-rw-r--r--azurelinuxagent/pa/provision/cloudinit.py132
-rw-r--r--azurelinuxagent/pa/provision/default.py188
-rw-r--r--azurelinuxagent/pa/provision/factory.py10
-rw-r--r--azurelinuxagent/pa/provision/ubuntu.py102
7 files changed, 426 insertions, 171 deletions
diff --git a/azurelinuxagent/pa/deprovision/arch.py b/azurelinuxagent/pa/deprovision/arch.py
new file mode 100644
index 0000000..e661f79
--- /dev/null
+++ b/azurelinuxagent/pa/deprovision/arch.py
@@ -0,0 +1,33 @@
+# 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 azurelinuxagent.common.utils.fileutil as fileutil
+from azurelinuxagent.pa.deprovision.default import DeprovisionHandler, \
+ DeprovisionAction
+
+class ArchDeprovisionHandler(DeprovisionHandler):
+ def __init__(self):
+ super(ArchDeprovisionHandler, self).__init__()
+
+ def setup(self, deluser):
+ warnings, actions = super(ArchDeprovisionHandler, self).setup(deluser)
+ warnings.append("WARNING! /etc/machine-id will be removed.")
+ files_to_del = ['/etc/machine-id']
+ actions.append(DeprovisionAction(fileutil.rm_files, files_to_del))
+ return warnings, actions
diff --git a/azurelinuxagent/pa/deprovision/default.py b/azurelinuxagent/pa/deprovision/default.py
index ced87ee..90d16c7 100644
--- a/azurelinuxagent/pa/deprovision/default.py
+++ b/azurelinuxagent/pa/deprovision/default.py
@@ -17,13 +17,17 @@
# Requires Python 2.4+ and Openssl 1.0+
#
+import glob
+import os.path
import signal
import sys
+
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.exception import ProtocolError
+from azurelinuxagent.common.future import read_input
from azurelinuxagent.common.osutil import get_osutil
from azurelinuxagent.common.protocol import get_protocol_util
@@ -68,15 +72,19 @@ 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(fileutil.rm_files,
- ['/etc/ssh/ssh_host_*key*']))
+ [conf.get_ssh_key_glob()]))
def stop_agent_service(self, warnings, actions):
warnings.append("WARNING! The waagent service will be stopped.")
actions.append(DeprovisionAction(self.osutil.stop_agent_service))
+ def del_dirs(self, warnings, actions):
+ dirs = [conf.get_lib_dir(), conf.get_ext_log_dir()]
+ actions.append(DeprovisionAction(fileutil.rm_dirs, dirs))
+
def del_files(self, warnings, actions):
- files_to_del = ['/root/.bash_history', '/var/log/waagent.log']
- actions.append(DeprovisionAction(fileutil.rm_files, files_to_del))
+ files = ['/root/.bash_history', '/var/log/waagent.log']
+ actions.append(DeprovisionAction(fileutil.rm_files, files))
def del_resolv(self, warnings, actions):
warnings.append("WARNING! /etc/resolv.conf will be deleted.")
@@ -92,9 +100,63 @@ class DeprovisionHandler(object):
actions.append(DeprovisionAction(fileutil.rm_files, ["/var/db/dhclient.leases.hn0",
"/var/lib/NetworkManager/dhclient-*.lease"]))
- def del_lib_dir(self, warnings, actions):
- dirs_to_del = [conf.get_lib_dir()]
- actions.append(DeprovisionAction(fileutil.rm_dirs, dirs_to_del))
+
+ def del_lib_dir_files(self, warnings, actions):
+ known_files = [
+ 'HostingEnvironmentConfig.xml',
+ 'Incarnation',
+ 'Protocol',
+ 'SharedConfig.xml',
+ 'WireServerEndpoint'
+ ]
+ known_files_glob = [
+ 'Extensions.*.xml',
+ 'ExtensionsConfig.*.xml',
+ 'GoalState.*.xml'
+ ]
+
+ lib_dir = conf.get_lib_dir()
+ files = [f for f in \
+ [os.path.join(lib_dir, kf) for kf in known_files] \
+ if os.path.isfile(f)]
+ for p in known_files_glob:
+ files += glob.glob(os.path.join(lib_dir, p))
+
+ if len(files) > 0:
+ actions.append(DeprovisionAction(fileutil.rm_files, files))
+
+ def cloud_init_dirs(self, include_once=True):
+ dirs = [
+ "/var/lib/cloud/instance",
+ "/var/lib/cloud/instances/",
+ "/var/lib/cloud/data"
+ ]
+ if include_once:
+ dirs += [
+ "/var/lib/cloud/scripts/per-once"
+ ]
+ return dirs
+
+ def cloud_init_files(self, include_once=True):
+ files = [
+ "/etc/sudoers.d/90-cloud-init-users"
+ ]
+ if include_once:
+ files += [
+ "/var/lib/cloud/sem/config_scripts_per_once.once"
+ ]
+ return files
+
+ def del_cloud_init(self, warnings, actions, include_once=True):
+ dirs = [d for d in self.cloud_init_dirs(include_once=include_once) \
+ if os.path.isdir(d)]
+ if len(dirs) > 0:
+ actions.append(DeprovisionAction(fileutil.rm_dirs, dirs))
+
+ files = [f for f in self.cloud_init_files(include_once=include_once) \
+ if os.path.isfile(f)]
+ if len(files) > 0:
+ actions.append(DeprovisionAction(fileutil.rm_files, files))
def reset_hostname(self, warnings, actions):
localhost = ["localhost.localdomain"]
@@ -117,7 +179,8 @@ class DeprovisionHandler(object):
if conf.get_delete_root_password():
self.del_root_password(warnings, actions)
- self.del_lib_dir(warnings, actions)
+ self.del_cloud_init(warnings, actions)
+ self.del_dirs(warnings, actions)
self.del_files(warnings, actions)
self.del_resolv(warnings, actions)
@@ -126,19 +189,55 @@ class DeprovisionHandler(object):
return warnings, actions
+ def setup_changed_unique_id(self):
+ warnings = []
+ actions = []
+
+ self.del_cloud_init(warnings, actions, include_once=False)
+ self.del_dhcp_lease(warnings, actions)
+ self.del_lib_dir_files(warnings, actions)
+ self.del_resolv(warnings, actions)
+
+ return warnings, actions
+
def run(self, force=False, deluser=False):
warnings, actions = self.setup(deluser)
- for warning in warnings:
- print(warning)
- if not force:
- confirm = read_input("Do you want to proceed (y/n)")
- if not confirm.lower().startswith('y'):
- return
+ self.do_warnings(warnings)
+ self.do_confirmation(force=force)
+ self.do_actions(actions)
+
+ def run_changed_unique_id(self):
+ '''
+ Clean-up files and directories that may interfere when the VM unique
+ identifier has changed.
+ While users *should* manually deprovision a VM, the files removed by
+ this routine will help keep the agent from getting confused
+ (since incarnation and extension settings, among other items, will
+ no longer be monotonically increasing).
+ '''
+ warnings, actions = self.setup_changed_unique_id()
+
+ self.do_warnings(warnings)
+ self.do_actions(actions)
+
+ def do_actions(self, actions):
self.actions_running = True
for action in actions:
action.invoke()
+ self.actions_running = False
+
+ def do_confirmation(self, force=False):
+ if force:
+ return True
+
+ confirm = read_input("Do you want to proceed (y/n)")
+ return True if confirm.lower().startswith('y') else False
+
+ def do_warnings(self, warnings):
+ for warning in warnings:
+ print(warning)
def handle_interrupt_signal(self, signum, frame):
if not self.actions_running:
diff --git a/azurelinuxagent/pa/deprovision/factory.py b/azurelinuxagent/pa/deprovision/factory.py
index 72a5be1..5ac35a7 100644
--- a/azurelinuxagent/pa/deprovision/factory.py
+++ b/azurelinuxagent/pa/deprovision/factory.py
@@ -21,6 +21,7 @@ from azurelinuxagent.common.version import DISTRO_NAME, DISTRO_VERSION, \
DISTRO_FULL_NAME
from .default import DeprovisionHandler
+from .arch import ArchDeprovisionHandler
from .clearlinux import ClearLinuxDeprovisionHandler
from .coreos import CoreOSDeprovisionHandler
from .ubuntu import UbuntuDeprovisionHandler
@@ -28,6 +29,8 @@ 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 == "arch":
+ return ArchDeprovisionHandler()
if distro_name == "ubuntu":
return UbuntuDeprovisionHandler()
if distro_name == "coreos":
diff --git a/azurelinuxagent/pa/provision/cloudinit.py b/azurelinuxagent/pa/provision/cloudinit.py
new file mode 100644
index 0000000..5789e9a
--- /dev/null
+++ b/azurelinuxagent/pa/provision/cloudinit.py
@@ -0,0 +1,132 @@
+# 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 os.path
+import time
+
+from datetime import datetime
+
+import azurelinuxagent.common.conf as conf
+import azurelinuxagent.common.logger as logger
+import azurelinuxagent.common.utils.fileutil as fileutil
+import azurelinuxagent.common.utils.shellutil as shellutil
+
+from azurelinuxagent.common.event import elapsed_milliseconds
+from azurelinuxagent.common.exception import ProvisionError, ProtocolError
+from azurelinuxagent.common.future import ustr
+from azurelinuxagent.common.protocol import OVF_FILE_NAME
+from azurelinuxagent.common.protocol.ovfenv import OvfEnv
+from azurelinuxagent.pa.provision.default import ProvisionHandler
+
+
+class CloudInitProvisionHandler(ProvisionHandler):
+ def __init__(self):
+ super(CloudInitProvisionHandler, self).__init__()
+
+ def run(self):
+ # If provision is enabled, run default provision handler
+ if conf.get_provision_enabled():
+ logger.warn("Provisioning flag is enabled, which overrides using "
+ "cloud-init; running the default provisioning code")
+ super(CloudInitProvisionHandler, self).run()
+ return
+
+ try:
+ if super(CloudInitProvisionHandler, self).is_provisioned():
+ logger.info("Provisioning already completed, skipping.")
+ return
+
+ utc_start = datetime.utcnow()
+ logger.info("Running CloudInit provisioning handler")
+ self.wait_for_ovfenv()
+ self.protocol_util.get_protocol()
+ self.report_not_ready("Provisioning", "Starting")
+
+ thumbprint = self.wait_for_ssh_host_key()
+ self.write_provisioned()
+ logger.info("Finished provisioning")
+
+ self.report_ready(thumbprint)
+ self.report_event("Provision succeed",
+ is_success=True,
+ duration=elapsed_milliseconds(utc_start))
+
+ except ProvisionError as e:
+ logger.error("Provisioning failed: {0}", ustr(e))
+ self.report_not_ready("ProvisioningFailed", ustr(e))
+ self.report_event(ustr(e))
+ return
+
+ def wait_for_ovfenv(self, max_retry=360, sleep_time=5):
+ """
+ Wait for cloud-init to copy ovf-env.xml file from provision ISO
+ """
+ ovf_file_path = os.path.join(conf.get_lib_dir(), OVF_FILE_NAME)
+ for retry in range(0, max_retry):
+ if os.path.isfile(ovf_file_path):
+ try:
+ OvfEnv(fileutil.read_file(ovf_file_path))
+ return
+ except ProtocolError as pe:
+ raise ProvisionError("OVF xml could not be parsed "
+ "[{0}]: {1}".format(ovf_file_path,
+ ustr(pe)))
+ else:
+ if retry < max_retry - 1:
+ logger.info(
+ "Waiting for cloud-init to copy ovf-env.xml to {0} "
+ "[{1} retries remaining, "
+ "sleeping {2}s]".format(ovf_file_path,
+ max_retry - retry,
+ sleep_time))
+ if not self.validate_cloud_init():
+ logger.warn("cloud-init does not appear to be running")
+ time.sleep(sleep_time)
+ raise ProvisionError("Giving up, ovf-env.xml was not copied to {0} "
+ "after {1}s".format(ovf_file_path,
+ max_retry * sleep_time))
+
+ def wait_for_ssh_host_key(self, max_retry=360, sleep_time=5):
+ """
+ Wait for cloud-init to generate ssh host key
+ """
+ keypair_type = conf.get_ssh_host_keypair_type()
+ path = conf.get_ssh_key_public_path()
+ for retry in range(0, max_retry):
+ if os.path.isfile(path):
+ logger.info("ssh host key found at: {0}".format(path))
+ try:
+ thumbprint = self.get_ssh_host_key_thumbprint(chk_err=False)
+ logger.info("Thumbprint obtained from : {0}".format(path))
+ return thumbprint
+ except ProvisionError:
+ logger.warn("Could not get thumbprint from {0}".format(path))
+ if retry < max_retry - 1:
+ logger.info("Waiting for ssh host key be generated at {0} "
+ "[{1} attempts remaining, "
+ "sleeping {2}s]".format(path,
+ max_retry - retry,
+ sleep_time))
+ if not self.validate_cloud_init():
+ logger.warn("cloud-init does not appear to be running")
+ time.sleep(sleep_time)
+ raise ProvisionError("Giving up, ssh host key was not found at {0} "
+ "after {1}s".format(path,
+ max_retry * sleep_time))
diff --git a/azurelinuxagent/pa/provision/default.py b/azurelinuxagent/pa/provision/default.py
index 3a3f36f..d4870f1 100644
--- a/azurelinuxagent/pa/provision/default.py
+++ b/azurelinuxagent/pa/provision/default.py
@@ -20,19 +20,31 @@ Provision handler
"""
import os
+import os.path
+import re
+
+from datetime import datetime
+
+import azurelinuxagent.common.conf as conf
import azurelinuxagent.common.logger as logger
+import azurelinuxagent.common.utils.shellutil as shellutil
+import azurelinuxagent.common.utils.fileutil as fileutil
+
from azurelinuxagent.common.future import ustr
-import azurelinuxagent.common.conf as conf
-from azurelinuxagent.common.event import add_event, WALAEventOperation
+from azurelinuxagent.common.event import add_event, WALAEventOperation, \
+ elapsed_milliseconds
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.restapi import ProvisionStatus
from azurelinuxagent.common.protocol import get_protocol_util
+from azurelinuxagent.common.version import AGENT_NAME
CUSTOM_DATA_FILE = "CustomData"
+CLOUD_INIT_PATTERN = b".*/bin/cloud-init.*"
+CLOUD_INIT_REGEX = re.compile(CLOUD_INIT_PATTERN)
+
+PROVISIONED_FILE = 'provisioned'
class ProvisionHandler(object):
@@ -41,54 +53,85 @@ class ProvisionHandler(object):
self.protocol_util = get_protocol_util()
def run(self):
- # if provisioning is already done, return
- provisioned = os.path.join(conf.get_lib_dir(), "provisioned")
- if os.path.isfile(provisioned):
- logger.info("Provisioning already completed, skipping.")
- return
-
- thumbprint = None
# If provision is not enabled, report ready and then return
if not conf.get_provision_enabled():
logger.info("Provisioning is disabled, skipping.")
- else:
- logger.info("Running provisioning handler")
- try:
- logger.info("Copying ovf-env.xml")
- ovf_env = self.protocol_util.copy_ovf_env()
- self.protocol_util.get_protocol_by_file()
- self.report_not_ready("Provisioning", "Starting")
- logger.info("Starting provisioning")
- self.provision(ovf_env)
- thumbprint = self.reg_ssh_host_key()
- self.osutil.restart_ssh_service()
- self.report_event("Provision succeed", is_success=True)
- except ProtocolError as e:
- logger.error("[ProtocolError] Provisioning failed: {0}", e)
- self.report_not_ready("ProvisioningFailed", ustr(e))
- self.report_event("Failed to copy ovf-env.xml: {0}".format(e))
- return
- except ProvisionError as e:
- logger.error("[ProvisionError] Provisioning failed: {0}", e)
- self.report_not_ready("ProvisioningFailed", ustr(e))
- self.report_event(ustr(e))
+ return
+
+ try:
+ utc_start = datetime.utcnow()
+ thumbprint = None
+
+ # if provisioning is already done, return
+ if self.is_provisioned():
+ logger.info("Provisioning already completed, skipping.")
return
- # write out provisioned file and report Ready
- fileutil.write_file(provisioned, "")
- self.report_ready(thumbprint)
- logger.info("Provisioning complete")
+
+ logger.info("Running default provisioning handler")
+
+ if not self.validate_cloud_init(is_expected=False):
+ raise ProvisionError("cloud-init appears to be running, "
+ "this is not expected, cannot continue")
+
+ logger.info("Copying ovf-env.xml")
+ ovf_env = self.protocol_util.copy_ovf_env()
+
+ self.protocol_util.get_protocol_by_file()
+ self.report_not_ready("Provisioning", "Starting")
+ logger.info("Starting provisioning")
+
+ self.provision(ovf_env)
+
+ thumbprint = self.reg_ssh_host_key()
+ self.osutil.restart_ssh_service()
+
+ # write out provisioned file and report Ready
+ self.write_provisioned()
+
+ self.report_event("Provision succeed",
+ is_success=True,
+ duration=elapsed_milliseconds(utc_start))
+
+ self.report_ready(thumbprint)
+ logger.info("Provisioning complete")
+
+ except (ProtocolError, ProvisionError) as e:
+ self.report_not_ready("ProvisioningFailed", ustr(e))
+ self.report_event(ustr(e))
+ logger.error("Provisioning failed: {0}", ustr(e))
+ return
+
+ @staticmethod
+ def validate_cloud_init(is_expected=True):
+ pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]
+ is_running = False
+ for pid in pids:
+ try:
+ pname = open(os.path.join('/proc', pid, 'cmdline'), 'rb').read()
+ if CLOUD_INIT_REGEX.match(pname):
+ is_running = True
+ msg = "cloud-init is running [PID {0}, {1}]".format(pid,
+ pname)
+ if is_expected:
+ logger.verbose(msg)
+ else:
+ logger.error(msg)
+ break
+ except IOError:
+ continue
+ return is_running == is_expected
def reg_ssh_host_key(self):
keypair_type = conf.get_ssh_host_keypair_type()
if conf.get_regenerate_ssh_host_key():
- fileutil.rm_files("/etc/ssh/ssh_host_*key*")
- keygen_cmd = "ssh-keygen -N '' -t {0} -f /etc/ssh/ssh_host_{1}_key"
- shellutil.run(keygen_cmd.format(keypair_type, keypair_type))
- thumbprint = self.get_ssh_host_key_thumbprint(keypair_type)
- return thumbprint
-
- def get_ssh_host_key_thumbprint(self, keypair_type, chk_err=True):
- cmd = "ssh-keygen -lf /etc/ssh/ssh_host_{0}_key.pub".format(keypair_type)
+ fileutil.rm_files(conf.get_ssh_key_glob())
+ keygen_cmd = "ssh-keygen -N '' -t {0} -f {1}"
+ shellutil.run(keygen_cmd.format(keypair_type,
+ conf.get_ssh_key_private_path()))
+ return self.get_ssh_host_key_thumbprint()
+
+ def get_ssh_host_key_thumbprint(self, chk_err=True):
+ cmd = "ssh-keygen -lf {0}".format(conf.get_ssh_key_public_path())
ret = shellutil.run_get_output(cmd, chk_err=chk_err)
if ret[0] == 0:
return ret[1].rstrip().split()[1].replace(':', '')
@@ -96,6 +139,45 @@ class ProvisionHandler(object):
raise ProvisionError(("Failed to generate ssh host key: "
"ret={0}, out= {1}").format(ret[0], ret[1]))
+ def provisioned_file_path(self):
+ return os.path.join(conf.get_lib_dir(), PROVISIONED_FILE)
+
+ def is_provisioned(self):
+ '''
+ A VM is considered provisionend *anytime* the provisioning
+ sentinel file exists and not provisioned *anytime* the file
+ is absent.
+
+ If the VM was provisioned using an agent that did not record
+ the VM unique identifier, the provisioning file will be re-written
+ to include the identifier.
+
+ A warning is logged *if* the VM unique identifier has changed
+ since VM was provisioned.
+ '''
+ if not os.path.isfile(self.provisioned_file_path()):
+ return False
+
+ s = fileutil.read_file(self.provisioned_file_path()).strip()
+ if s != self.osutil.get_instance_id():
+ if len(s) > 0:
+ logger.warn("VM is provisioned, "
+ "but the VM unique identifier has changed -- "
+ "clearing cached state")
+ from azurelinuxagent.pa.deprovision \
+ import get_deprovision_handler
+ deprovision_handler = get_deprovision_handler()
+ deprovision_handler.run_changed_unique_id()
+
+ self.write_provisioned()
+
+ return True
+
+ def write_provisioned(self):
+ fileutil.write_file(
+ self.provisioned_file_path(),
+ get_osutil().get_instance_id())
+
def provision(self, ovfenv):
logger.info("Handle ovf-env.xml.")
try:
@@ -113,7 +195,7 @@ class ProvisionHandler(object):
self.osutil.del_root_password()
except OSUtilError as e:
- raise ProvisionError("Failed to handle ovf-env.xml: {0}".format(e))
+ raise ProvisionError("Failed to provision: {0}".format(ustr(e)))
def config_user_account(self, ovfenv):
logger.info("Create user account if not exists")
@@ -141,11 +223,12 @@ class ProvisionHandler(object):
if customdata is None:
return
- logger.info("Save custom data")
lib_dir = conf.get_lib_dir()
- if conf.get_decode_customdata():
+ if conf.get_decode_customdata() or conf.get_execute_customdata():
+ logger.info("Decode custom data")
customdata = self.osutil.decode_customdata(customdata)
+ logger.info("Save custom data")
customdata_file = os.path.join(lib_dir, CUSTOM_DATA_FILE)
fileutil.write_file(customdata_file, customdata)
@@ -164,9 +247,12 @@ class ProvisionHandler(object):
logger.info("Deploy ssh key pairs.")
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,
- op=WALAEventOperation.Provision)
+ def report_event(self, message, is_success=False, duration=0):
+ add_event(name=AGENT_NAME,
+ message=message,
+ duration=duration,
+ is_success=is_success,
+ op=WALAEventOperation.Provision)
def report_not_ready(self, sub_status, description):
status = ProvisionStatus(status="NotReady", subStatus=sub_status,
diff --git a/azurelinuxagent/pa/provision/factory.py b/azurelinuxagent/pa/provision/factory.py
index 9bbe35c..d87765f 100644
--- a/azurelinuxagent/pa/provision/factory.py
+++ b/azurelinuxagent/pa/provision/factory.py
@@ -15,18 +15,22 @@
# Requires Python 2.4+ and Openssl 1.0+
#
+import azurelinuxagent.common.conf as conf
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
+from .cloudinit import CloudInitProvisionHandler
def get_provision_handler(distro_name=DISTRO_NAME,
distro_version=DISTRO_VERSION,
distro_full_name=DISTRO_FULL_NAME):
- if distro_name == "ubuntu":
- return UbuntuProvisionHandler()
+
+ if conf.get_provision_cloudinit():
+ return CloudInitProvisionHandler()
return ProvisionHandler()
diff --git a/azurelinuxagent/pa/provision/ubuntu.py b/azurelinuxagent/pa/provision/ubuntu.py
deleted file mode 100644
index 66866b2..0000000
--- a/azurelinuxagent/pa/provision/ubuntu.py
+++ /dev/null
@@ -1,102 +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 time
-
-import azurelinuxagent.common.conf as conf
-import azurelinuxagent.common.logger as logger
-import azurelinuxagent.common.utils.fileutil as fileutil
-from azurelinuxagent.common.exception import ProvisionError, ProtocolError
-from azurelinuxagent.common.future import ustr
-from azurelinuxagent.pa.provision.default import ProvisionHandler
-
-"""
-On ubuntu image, provision could be disabled.
-"""
-
-
-class UbuntuProvisionHandler(ProvisionHandler):
- def __init__(self):
- super(UbuntuProvisionHandler, self).__init__()
-
- def run(self):
- # If provision is enabled, run default provision handler
- if conf.get_provision_enabled():
- super(UbuntuProvisionHandler, self).run()
- return
-
- logger.info("run Ubuntu provision handler")
- provisioned = os.path.join(conf.get_lib_dir(), "provisioned")
- if os.path.isfile(provisioned):
- return
-
- logger.info("Waiting cloud-init to copy ovf-env.xml.")
- self.wait_for_ovfenv()
- self.protocol_util.get_protocol()
- self.report_not_ready("Provisioning", "Starting")
- logger.info("Sleeping 1 second to avoid throttling.")
- time.sleep(1)
- try:
- logger.info("Wait for ssh host key to be generated.")
- thumbprint = self.wait_for_ssh_host_key()
- fileutil.write_file(provisioned, "")
- logger.info("Finished provisioning")
- except ProvisionError as e:
- logger.error("Provision failed: {0}", e)
- self.report_not_ready("ProvisioningFailed", ustr(e))
- self.report_event(ustr(e))
- return
-
- self.report_ready(thumbprint)
- self.report_event("Provision succeed", is_success=True)
-
- def wait_for_ovfenv(self, max_retry=60):
- """
- Wait for cloud-init to copy ovf-env.xml file from provision ISO
- """
- for retry in range(0, max_retry):
- try:
- self.protocol_util.get_ovf_env()
- return
- except ProtocolError:
- if retry < max_retry - 1:
- logger.info("Wait for cloud-init to copy ovf-env.xml")
- time.sleep(5)
- raise ProvisionError("ovf-env.xml is not copied")
-
- def wait_for_ssh_host_key(self, max_retry=60):
- """
- Wait for cloud-init to generate ssh host key
- """
- keypair_type = conf.get_ssh_host_keypair_type()
- path = '/etc/ssh/ssh_host_{0}_key.pub'.format(keypair_type)
- for retry in range(0, max_retry):
- if os.path.isfile(path):
- logger.info("ssh host key found at: {0}".format(path))
- try:
- thumbprint = self.get_ssh_host_key_thumbprint(keypair_type, chk_err=False)
- logger.info("Thumbprint obtained from : {0}".format(path))
- return thumbprint
- except ProvisionError:
- logger.warn("Could not get thumbprint from {0}".format(path))
- if retry < max_retry - 1:
- logger.info("Wait for ssh host key be generated: {0}".format(path))
- time.sleep(5)
- raise ProvisionError("ssh host key is not generated.")