def mount_dvd(self, max_retry=6, chk_err=True): dvd = self.get_dvd_device() mount_point = conf.get_dvd_mount_point() mountlist = shellutil.run_get_output("mount")[1] existing = self.get_mount_point(mountlist, dvd) if existing is not None: #Already mounted logger.info("{0} is already mounted at {1}", dvd, existing) return if not os.path.isdir(mount_point): os.makedirs(mount_point) for retry in range(0, max_retry): retcode = self.mount(dvd, mount_point, option="-o ro -t iso9660,udf", chk_err=chk_err) if retcode == 0: logger.info("Successfully mounted dvd") return if retry < max_retry - 1: logger.warn("Mount dvd failed: retry={0}, ret={1}", retry, retcode) time.sleep(5) if chk_err: raise OSUtilError("Failed to mount dvd.")
def copy_ovf_env(self): """ Copy ovf env file from dvd to hard disk. Remove password before save it to the disk """ dvd_mount_point = conf.get_dvd_mount_point() 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() ovfxml = fileutil.read_file(ovf_file_path_on_dvd, remove_bom=True) ovfenv = OvfEnv(ovfxml) ovfxml = re.sub("<UserPassword>.*?<", "<UserPassword>*<", ovfxml) ovf_file_path = os.path.join(conf.get_lib_dir(), OVF_FILE_NAME) fileutil.write_file(ovf_file_path, ovfxml) if os.path.isfile(tag_file_path_on_dvd): logger.info("Found {0} in provisioning ISO", TAG_FILE_NAME) tag_file_path = os.path.join(conf.get_lib_dir(), TAG_FILE_NAME) shutil.copyfile(tag_file_path_on_dvd, tag_file_path) except (OSUtilError, IOError) as e: raise ProtocolError(ustr(e)) try: self.distro.osutil.umount_dvd() self.distro.osutil.eject_dvd() except OSUtilError as e: logger.warn(ustr(e)) return ovfenv
def enable_swap(self, mount_point): logger.info("Enable swap") try: size_mb = conf.get_resourcedisk_swap_size_mb() self.create_swap_space(mount_point, size_mb) except ResourceDiskError as e: logger.error("Failed to enable swap {0}", e)
def replace_file(filepath, contents): """ Write 'contents' to 'filepath' by creating a temp file, and replacing original. """ handle, temp = tempfile.mkstemp(dir=os.path.dirname(filepath)) #if type(contents) == str: #contents=contents.encode('latin-1') try: os.write(handle, contents) except IOError as err: logger.error('Write to file {0}, Exception is {1}', filepath, err) return 1 finally: os.close(handle) try: os.rename(temp, filepath) except IOError as err: logger.info('Rename {0} to {1}, Exception is {2}', temp, filepath, err) logger.info('Remove original file and retry') try: os.remove(filepath) except IOError as err: logger.error('Remove {0}, Exception is {1}', temp, filepath, err) try: os.rename(temp, filepath) except IOError as err: logger.error('Rename {0} to {1}, Exception is {2}', temp, filepath, err) return 1 return 0
def daemon(self): logger.info("Run daemon") #Create lib dir if not os.path.isdir(conf.get_lib_dir()): fileutil.mkdir(conf.get_lib_dir(), mode=0o700) os.chdir(conf.get_lib_dir()) if conf.get_detect_scvmm_env(): if self.distro.scvmm_handler.run(): return self.distro.provision_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.distro.event_handler.run() self.distro.env_handler.run() while self.running: #Handle extensions self.distro.ext_handlers_handler.run() time.sleep(25)
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() protocol = self.distro.protocol_util.detect_protocol() self.report_not_ready("Provisioning", "Starting") logger.info("Sleep 15 seconds to prevent throttling") time.sleep(15) #Sleep to prevent throttling 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 send_dhcp_req(self): """ Build dhcp request with mac addr Configure route to allow dhcp traffic Stop dhcp service if necessary """ logger.info("Send dhcp request") mac_addr = self.distro.osutil.get_mac_addr() req = build_dhcp_request(mac_addr) # 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() if missing_default_route: self.distro.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() resp = self._send_dhcp_req(req) if self.distro.osutil.is_dhcp_enabled(): self.distro.osutil.start_dhcp_service() if missing_default_route: self.distro.osutil.remove_route_for_dhcp_broadcast(ifname) if resp is None: raise DhcpError("Failed to receive dhcp response.") self.endpoint, self.gateway, self.routes = parse_dhcp_resp(resp)
def _detect_protocol(self, protocols): """ 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) for retry in range(0, MAX_RETRY): for protocol in protocols: try: if protocol == "WireProtocol": return self._detect_wire_protocol() if protocol == "MetadataProtocol": return self._detect_metadata_protocol() except ProtocolError as e: logger.info("Protocol endpoint not found: {0}, {1}", protocol, e) if retry < MAX_RETRY - 1: logger.info("Retry detect protocols: retry={0}", retry) time.sleep(PROBE_INTERVAL) raise ProtocolNotFoundError("No protocol found.")
def handle_hostname_update(self): curr_hostname = socket.gethostname() 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.hostname = curr_hostname
def del_resolv(): if os.path.realpath('/etc/resolv.conf') != '/run/resolvconf/resolv.conf': logger.info("resolvconf is not configured. Removing /etc/resolv.conf") fileutil.rm_files('/etc/resolv.conf') else: logger.info("resolvconf is enabled; leaving /etc/resolv.conf intact") fileutil.rm_files('/etc/resolvconf/resolv.conf.d/tail', '/etc/resolvconf/resolv.conf.d/originial')
def set_block_device_timeout(self, dev, timeout): if dev is not None and timeout is not None: file_path = "/sys/block/{0}/device/timeout".format(dev) content = fileutil.read_file(file_path) original = content.splitlines()[0].rstrip() if original != timeout: fileutil.write_file(file_path, timeout) logger.info("Set block dev timeout: {0} with timeout: {1}", dev, timeout)
def conf_sshd(self, disable_password): option = "no" if disable_password else "yes" conf_file_path = conf.get_sshd_conf_file_path() conf_file = fileutil.read_file(conf_file_path).split("\n") textutil.set_ssh_config(conf_file, "PasswordAuthentication", option) textutil.set_ssh_config(conf_file, "ChallengeResponseAuthentication", option) fileutil.write_file(conf_file_path, "\n".join(conf_file)) logger.info("Disabled SSH password-based authentication methods.")
def handle_ext_handlers(self, ext_handlers): if ext_handlers.extHandlers is None or \ len(ext_handlers.extHandlers) == 0: logger.info("No ext handler config found") return for ext_handler in ext_handlers.extHandlers: #TODO handle install in sequence, enable in parallel self.handle_ext_handler(ext_handler)
def is_atapiix_mod_loaded(self, max_retry=1): for retry in range(0, max_retry): ret = shellutil.run("lsmod | grep ata_piix", chk_err=False) if ret == 0: logger.info("Module driver for ATAPI CD-ROM is already present.") return True if retry < max_retry - 1: time.sleep(1) return False
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() 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) return found
def is_atapiix_mod_loaded(self, max_retry=1): for retry in range(0, max_retry): ret = shellutil.run("lsmod | grep ata_piix", chk_err=False) if ret == 0: logger.info( "Module driver for ATAPI CD-ROM is already present.") return True if retry < max_retry - 1: time.sleep(1) return False
def wait_for_network(self): """ Wait for network stack to be initialized. """ ipv4 = self.distro.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()
def update_ext_conf(self, goal_state): if goal_state.ext_uri is None: logger.info("ExtensionsConfig.xml uri is empty") self.ext_conf = ExtensionsConfig(None) return incarnation = goal_state.incarnation local_file = os.path.join(conf.get_lib_dir(), EXT_CONF_FILE_NAME.format(incarnation)) xml_text = self.fetch_config(goal_state.ext_uri, self.get_header()) self.save_cache(local_file, xml_text) self.ext_conf = ExtensionsConfig(xml_text)
def check_pid(self): """Check whether daemon is already running""" pid = None pid_file = conf.get_agent_pid_file_path() if os.path.isfile(pid_file): pid = fileutil.read_file(pid_file) if pid is not None and os.path.isdir(os.path.join("/proc", pid)): logger.info("Daemon is already running: {0}", pid) sys.exit(0) fileutil.write_file(pid_file, ustr(os.getpid()))
def __init__(self, endpoint): logger.info("Wire server endpoint:{0}", endpoint) self.endpoint = endpoint self.goal_state = None self.updated = None self.hosting_env = None self.shared_conf = None self.certs = None self.ext_conf = None self.last_request = 0 self.req_count = 0 self.status_blob = StatusBlob(self)
def get_ext_handler_pkgs(self, ext_handler): ext_handler_pkgs = ExtHandlerPackageList() data = None for version_uri in ext_handler.versionUris: try: data, etag = self._get_data(version_uri.uri) break except ProtocolError as e: logger.warn("Failed to get version uris: {0}", e) logger.info("Retry getting version uris") set_properties("extensionPackages", ext_handler_pkgs, data) return ext_handler_pkgs
def run(self): if not self.stopped: logger.info("Stop existing env monitor service.") self.stop() self.stopped = False logger.info("Start env monitor service.") self.distro.dhcp_handler.conf_routes() self.hostname = socket.gethostname() self.dhcpid = self.distro.osutil.get_dhcp_pid() self.server_thread = threading.Thread(target=self.monitor) self.server_thread.setDaemon(True) self.server_thread.start()
def run(self): if not self.stopped: logger.info("Stop existing env monitor service.") self.stop() self.stopped = False logger.info("Start env monitor service.") self.distro.dhcp_handler.conf_routes() self.hostname = socket.gethostname() self.dhcpid = self.distro.osutil.get_dhcp_pid() self.server_thread = threading.Thread(target = self.monitor) self.server_thread.setDaemon(True) self.server_thread.start()
def wait_for_ssh_host_key(self, max_retry=60): """ Wait for cloud-init to generate ssh host key """ kepair_type = conf.get_ssh_host_keypair_type() path = '/etc/ssh/ssh_host_{0}_key'.format(kepair_type) for retry in range(0, max_retry): if os.path.isfile(path): return self.get_ssh_host_key_thumbprint(kepair_type) if retry < max_retry - 1: logger.info("Wait for ssh host key be generated: {0}", path) time.sleep(5) raise ProvisionError("Ssh hsot key is not generated.")
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.distro.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 parse(self, xml_text): xml_doc = parse_doc(xml_text) preferred = find(xml_doc, "Preferred") self.preferred = findtext(preferred, "Version") logger.info("Fabric preferred wire protocol version:{0}", self.preferred) self.supported = [] supported = find(xml_doc, "Supported") supported_version = findall(supported, "Version") for node in supported_version: version = gettext(node) logger.verb("Fabric supported wire protocol version:{0}", version) self.supported.append(version)
def config_user_account(self, ovfenv): logger.info("Create user account if not exists") self.distro.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, crypt_id=crypt_id, salt_len=salt_len) logger.info("Configure sudoer") self.distro.osutil.conf_sudoer(ovfenv.username, ovfenv.user_password is None) logger.info("Configure sshd") self.distro.osutil.conf_sshd(ovfenv.disable_ssh_password_auth) #Disable selinux temporary sel = self.distro.osutil.is_selinux_enforcing() if sel: self.distro.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.distro.osutil.restart_ssh_service()
def http_request(method, url, data, headers=None, max_retry=3, chk_proxy=False): """ Sending http request to server On error, sleep 10 and retry max_retry times. """ logger.verb("HTTP Req: {0} {1}", method, url) logger.verb(" Data={0}", data) logger.verb(" Header={0}", headers) host, port, secure, rel_uri = _parse_url(url) #Check proxy proxy_host, proxy_port = (None, None) if chk_proxy: proxy_host, proxy_port = get_http_proxy() #If httplib module is not built with ssl support. Fallback to http if secure and not hasattr(httpclient, "HTTPSConnection"): logger.warn("httplib is not built with ssl support") secure = False #If httplib module doesn't support https tunnelling. Fallback to http if secure and \ proxy_host is not None and \ proxy_port is not None and \ not hasattr(httpclient.HTTPSConnection, "set_tunnel"): logger.warn("httplib doesn't support https tunnelling(new in python 2.7)") secure = False for retry in range(0, max_retry): try: resp = _http_request(method, host, rel_uri, port=port, data=data, secure=secure, headers=headers, proxy_host=proxy_host, proxy_port=proxy_port) logger.verb("HTTP Resp: Status={0}", resp.status) logger.verb(" Header={0}", resp.getheaders()) return resp except httpclient.HTTPException as e: logger.warn('HTTPException {0}, args:{1}', e, repr(e.args)) except IOError as e: logger.warn('Socket IOError {0}, args:{1}', e, repr(e.args)) if retry < max_retry - 1: logger.info("Retry={0}, {1} {2}", retry, method, url) time.sleep(RETRY_WAITING_INTERVAL) if url is not None and len(url) > 100: url_log = url[0: 100] #In case the url is too long else: url_log = url raise HttpError("HTTP Err: {0} {1}".format(method, url_log))
def detect_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) return self.protocol finally: self.lock.release()
def check_wire_protocol_version(self): uri = VERSION_INFO_URI.format(self.endpoint) version_info_xml = self.fetch_config(uri, None) version_info = VersionInfo(version_info_xml) preferred = version_info.get_preferred() if PROTOCOL_VERSION == preferred: logger.info("Wire protocol version:{0}", PROTOCOL_VERSION) elif PROTOCOL_VERSION in version_info.get_supported(): logger.info("Wire protocol version:{0}", PROTOCOL_VERSION) logger.warn("Server prefered version:{0}", preferred) else: error = ("Agent supported wire protocol version: {0} was not " "advised by Fabric.").format(PROTOCOL_VERSION) raise ProtocolNotFoundError(error)
def call_storage_service(self, http_req, *args, **kwargs): """ Call storage service, handle SERVICE_UNAVAILABLE(503) """ for retry in range(0, 3): resp = http_req(*args, **kwargs) if resp.status == httpclient.SERVICE_UNAVAILABLE: logger.warn("Storage service is not avaible temporaryly") logger.info("Will retry later, in {0} seconds", LONG_WAITING_INTERVAL) time.sleep(LONG_WAITING_INTERVAL) else: return resp raise ProtocolError(("Calling storage endpoint failed: {0}" "").format(resp.status))
def activate_resource_disk(self): logger.info("Activate resource disk") try: mount_point = conf.get_resourcedisk_mountpoint() fs = conf.get_resourcedisk_filesystem() mount_point = self.mount_resource_disk(mount_point, fs) warning_file = os.path.join(mount_point, DATALOSS_WARNING_FILE_NAME) try: fileutil.write_file(warning_file, DATA_LOSS_WARNING) except IOError as e: logger.warn("Failed to write data loss warnning:{0}", e) return mount_point except ResourceDiskError as e: logger.error("Failed to mount resource disk {0}", e) add_event(name="WALA", is_success=False, message=ustr(e), op=WALAEventOperation.ActivateResourceDisk)
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() return #The dhcp process hasn't changed since last check if os.path.isdir(os.path.join('/proc', self.dhcpid.strip())): return newpid = self.distro.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.dhcpid = newpid
def save_customdata(self, ovfenv): customdata = ovfenv.customdata if customdata is None: return logger.info("Save custom data") lib_dir = conf.get_lib_dir() if conf.get_decode_customdata(): customdata= self.distro.osutil.decode_customdata(customdata) customdata_file = os.path.join(lib_dir, CUSTOM_DATA_FILE) fileutil.write_file(customdata_file, customdata) if conf.get_execute_customdata(): logger.info("Execute custom data") os.chmod(customdata_file, 0o700) shellutil.run(customdata_file)