a ahi @sddlZddlZddlZddlZddlZddlZddlZddlm Z ddl m Z ddl m Z ddlmZmZmZmZmZmZmZmZmZmZddlmmmZddlmZmZm Z mZm!Z!m"Z"m#Z#m$Z$m%Z%m&Z&ddl'm(Z(m)Z)ddl*m+Z+dd l,m-Z-dd l.m/Z/dd l0m1Z1dd l2m3Z3dd l4m5Z5m6Z6m7Z7ddl8m9Z9ddl:m;Z;ddldgdgdgddgddgddgdgdggdgddgd d!gd" Z?e@eAZBeCd#ZDgd$ZEejFejGd%ZHeeeIeeeeeIeeeIeeIfeeeIeeIeffZJGd&d'd'eKZLGd(d)d)e!jMejNd*ZOeIePd+d,d-ZQeId.d/d0ZRde&jSfd1d2ZTd3d4ZUeIeeOd5d6d7ZVd>d:d;ZWd/usr/lib/python3.9/site-packages/cloudinit/distros/__init__.pyr3sr3c@s\eZdZUdZdZdZdZdZdZdZ dZ d d gZ d Z d Z d gZeeed<iZeeeeeffed<dZeZeeed<ddddZejZeeed<dZ dZ!dZ"eed<dZ#e$eed<dZ%e$eed<ddZ&e'ddd d!Z(d"d#Z)e*e+e,ee-e.fe.fd$d%d&Z/e*d'd(d)Z0e1e2j3d*d+d,Z4e1ee5j6d*d-d.Z7e1e8d*d/d0Z9e8d1d2d3Z:d4d5Z;dd6d7Ze?dd?ZCdd@dAdBZDdCdDZEddEdFZFddGdHZGdIdJZHdeId*dKdLZJeAjBddMdNZKeAjBdOdPZLdQdRZMdSdTZNeAjBddUdVZOeAjBdWdXZPeAjBdYdZZQd[d\ZRd]d^ZSe?d_d`ZTdadbZUdcddZVe1dedfZWdgdhZXeId*didjZYdkdlZZeId*dmdnZ[dodpZ\dqdrZ]edsdtduZ^dvdwZ_ddxdyZ`eaeIdzd{d|Zbd}d~ZcdddZddddZedddZfdddZgehddZiehdddZjehddeeedddZkeeeedddZled*ddZmdeaeedddZne?eeeeeeadddZoe1ddZpepjqddZpe?e'e$e'dddZre?e'e$e'dddZse?e'e'e$e'dddZte?eddddZue?ee$edddZve?eewdddZxdd*ddZydS)Distroz python3-pipz/usr/libz /etc/hostsz/etc/doas.confz"/etc/sudoers.d/90-cloud-init-usersz /etc/hostnamez /etc/shadowz/var/lib/extrausers/shadowz ^{username}::z^{username}:!:z/usr/share/zoneinfoz root:rootserviceinit_cmdrenderer_configsNnetworking_clsz-Hz-Pz-r)ZhaltZpoweroffZrebootnet_opsFz/etc/resolv.confZosfamilydhclient_lease_directorydhclient_lease_file_regexcCsT||_||_||_||_tj|_tj |_ t ||_ g|_d|_d|_d|_dS)NT)Z_paths_cfgnamer= networkingr!ALL_DHCP_CLIENTSdhcp_client_priorityiproute2Iproute2r>rZRunners_runnerpackage_managers _dhcp_client_fallback_interfaceis_linux)selfrCZcfgpathsr7r7r8__init__s  zDistro.__init__)ci_pkl_versionreturncCsPd|jvs|jjs||_t|ds,d|_t|ds\} } | j dd|jDvrq| | |j|jj | dq|rt||dS)NzcFailed to install the following packages: %s. See associated package manager logs for more details.z"Package manager '%s' not availablecSsg|] }|jqSr7rC).0pr7r7r8 z+Distro.install_packages..rj)rir`rJget __class__difference_update availableredebugrCupdateinstall_packagesinforbZ from_configrIrBr3) rNr_Z error_messagergrhZ total_failedmanagerZmanager_packagesZto_tryZfailedZ manager_typeZpackagesr7r7r8rvsH       zDistro.install_packages)rRc Cs|jr |jS|j}t|jdg}|rxg}td||D]4}tjD]}||j krD| |q:qDt d|q:|rx|}|D]L}z"||_td|j |jWStj fytd|j Yq|0q|t dS)aaccess the distro's preferred dhcp client if no client has been selected yet select one - uses self.dhcp_client_priority, which may be overridden in each distro's object to eliminate checking for clients which will not be provided by the distro )networkrFz.Using configured dhcp client priority list: %sz4Configured dhcp client %s is not supported, skippingzDHCP client selected: %szDHCP client not found: %sN) rKrFrget_cfg_by_pathrBrertr!rEZ client_nameappendwarningZNoDHCPLeaseMissingDhclientError)rNrFZconfig_priorityZ found_clientsZclient_configuredZ client_classZclientr7r7r8 dhcp_client$s>      zDistro.dhcp_clientcCst|jdd}tj|dS)zReturn the configured network activator for this environment. :returns: The network activator class to use :raises: NoActivatorException if no activator is found )ryr Npriority)rrzrBr Zselect_activator)rNrr7r7r8network_activator`szDistro.network_activatorcCsDt|jdd}tj|d\}}td||||j|d}|S)N)ryr"r~z-Selected renderer '%s' from priority list: %s)Zconfig) rrzrBr"Zselectrertr<rp)rNrrCZ render_clsrendererr7r7r8network_rendererlszDistro.network_rendererrcCs||dSN)Zrender_network_state)rN network_staterr7r7r8_write_network_stateyszDistro._write_network_statecCs4tj|jt|}tj|s0td||f|S)Nz(Invalid timezone %s, no file found at %s)ospathjoin tz_zone_dirrXisfileIOError)rNtztz_filer7r7r8 _find_tz_file|s   zDistro._find_tz_filecCs|j||Sr)rBrp)rNopt_namedefaultr7r7r8 get_optionszDistro.get_optioncCs||j|<dSr)rB)rNrvaluer7r7r8 set_optionszDistro.set_optioncCs(|||}|||j||dSr)_select_hostname_write_hostnamehostname_conf_fn_apply_hostname)rNhostnamefqdnZwriteable_hostnamer7r7r8 set_hostnames zDistro.set_hostnamecCstS)z?Wrapper to report whether this distro uses systemd or sysvinit.) uses_systemdr7r7r7r8rszDistro.uses_systemdcCs tdSrNotImplementedError)rNcommandargsZpkgsr7r7r8package_commandszDistro.package_commandforcec Csn|jD]b}|s"td|jqz|j|dWqtyf}ztd|j|WYd}~qd}~00qdS)Nz8Skipping update for package manager '%s': not available.rz%Failed to update package using %s: %s)rJrsrertrCupdate_package_sources Exceptionrf)rNrrxer7r7r8rs zDistro.update_package_sourcescCstd}|dvrdS|S)N)i386Zi486Zi586Zi686r)runame)rNr)r7r7r8get_primary_archs zDistro.get_primary_archcCs"|dg}|s|}t||S)Npackage_mirrors)rr_get_arch_package_mirror_info)rNr) mirror_infor7r7r8rs z$Distro._get_arch_package_mirror_infocCs||}t||dS)N) data_sourcer)r_get_package_mirror_info)rNr)rZ arch_infor7r7r8get_package_mirror_infos zDistro.get_package_mirror_infocCstSr)rgenerate_fallback_configrNr7r7r8rszDistro.generate_fallback_configcCsr|j}t||d}||||rdtdz |j}Wn tjyVtdYdS0| |n tddS)aApply the network config. If bring_up is True, attempt to bring up the passed in devices. If devices is None, attempt to bring up devices returned by _write_network_config. Returns True if any devices failed to come up, otherwise False. rz/Bringing up newly configured network interfacesz>No network activator found, not bringing up network interfacesTz3Not bringing up newly configured network interfacesF) rr$rrertrr ZNoActivatorExceptionr|Zbring_up_all_interfaces)rNZ netconfigZbring_uprrrr7r7r8apply_network_configs       zDistro.apply_network_configcCs tdSrr)rNlocaleZout_fnr7r7r8 apply_localeszDistro.apply_localecCs tdSrr)rNrr7r7r8 set_timezoneszDistro.set_timezonecCsdS)Nz 127.0.0.1r7rr7r7r8_get_localhost_ipszDistro._get_localhost_ipcCs tdSrrrr7r7r8 get_localeszDistro.get_localecCs tdSrr)rNfilenamerr7r7r8_read_hostnameszDistro._read_hostnamecCs tdSrr)rNrrr7r7r8rszDistro._write_hostnamecCs tdSrrrr7r7r8_read_system_hostnameszDistro._read_system_hostnamecCsFtd|ztd|gWn"tjy@ttd|Yn0dS)Nz2Non-persistently setting the system hostname to %srz;Failed to non-persistently adjust the system hostname to %s)rertrProcessExecutionErrorrlogexc)rNrr7r7r8rszDistro._apply_hostnamecCs&t|jd|jr|r|S|s"|S|S)NZprefer_fqdn_over_hostname)rZget_cfg_option_boolrB prefer_fqdn)rNrrr7r7r8r s zDistro._select_hostnamecCs6g}|D](}|tvr"td||t|q|S)Nz&No distributions found for osfamily {}) OSFAMILIESr\formatextend)Z family_listZdistrosZfamilyr7r7r8expand_osfamilyszDistro.expand_osfamilyc Cs|}|||}|r,tj|r,||}nd}|\}}g}|rL||krV|||rj||krt||krt|||r|r||krtd||dSt dd|D}t d|t ||D]8} z| || Wqt yttd|| Yq0q||vr ||dS)Nz6%s differs from %s, assuming user maintained hostname.cSsg|] }|r|qSr7r7)rlfr7r7r8rnOroz*Distro.update_hostname..z/Attempting to update hostname to %s in %s filesz!Failed to write hostname %s to %s)rrrexistsrrr{rerwr`rtr[rrrrr) rNrrZprev_hostname_fnZapplying_hostnameZ prev_hostnameZsys_fnZ sys_hostnameZ update_filesfnr7r7r8update_hostname"sJ         zDistro.update_hostnamec Cs~d}tj|jr&tt|j}ntd}tjdd}| }| |}d}|sj| |||d}nd}|D]T}d} g} t |dkr|d} t |dkr|dd} | durr| |krr|| vrrd}qr|r6t |} | ||g||| D]B}t |dkr| ||dqt |dkr|j |g|Rq|rzt} |rV| d || d |tj|j| d d dS) NaddedbaseFTr?rrVz%s imode)rrrhosts_fnrZ HostsConfrload_text_file make_headerrZ get_entryZ add_entryr[rYr{Z del_entriesrwrite write_filegetvalue) rNrrheaderZehZlocal_ipZ prev_infoZ need_changer]Z entry_fqdnZ entry_aliasesZ new_entriescontentsr7r7r8update_etc_hostscsJ        zDistro.update_etc_hostscCs|jstt|_|jS)z7Allow distro to determine the preferred ntp client list)_preferred_ntp_clientsrYPREFERRED_NTP_CLIENTSrr7r7r8preferred_ntp_clientss zDistro.preferred_ntp_clientscCs |dS)NZ default_user)rrr7r7r8get_default_userszDistro.get_default_userc Kst|rtd|dSd|vr.|d}nd}d|g}d|g}tr^|d|dddd d d d d dddd }dddd}dg}|d} | rt| t r| d} t| t rt j d|dddddd| D} d| |d<|d } | r| | |rB| rB| D]*} t| s|| td!| |qd"|vr`t |d"|d"<t|D]\} } | |vr| rt| t r||| | g| |vr||| d#gn||| | gn,| |vrl| rl||| ||| ql|d$s|d%r2|d&|d&n|d'|d'td(|ztj||d)Wn8ty}zttd*||WYd+}~n d+}~00dS),z Add a user to the system using standard GNU tools This should be overridden on distros where useradd is not desirable or not available. Returns False if user already exists, otherwise True. z!User %s already exists, skipping.F create_groupsTZuseradd --extrausersz --commentz--homez--gidz--uidz--groups --passwordz--shellz --expiredatez --inactivez--selinux-user) Zgecoshomedir primary_groupuidgroupspasswdshellZ expiredateZinactiveZ selinux_userz--no-user-groupz--systemz --no-log-init)Z no_user_groupsystemZ no_log_initrr,z The user z) has a 'groups' config value of type dictz22.3z=Use a comma-delimited string or array instead: group1,group2.Z deprecatedZdeprecated_versionZ extra_messagecSsg|] }|qSr7strip)rlgr7r7r8rnroz#Distro.add_user..rz created group '%s' for user '%s'rZREDACTEDZno_create_homerz-Mz-mzAdding user %s) logstringzFailed to create user %sN)ris_userrerwpopsystem_is_snappyr{rprWrXsplitrar deprecateris_group create_grouprtkeyssortedrbrrrr)rNrCkwargsrZ useradd_cmdZlog_useradd_cmdZ useradd_optsZ useradd_flagsZ redact_optsrrgroupkeyvalrr7r7r8add_users                      zDistro.add_userc Ks|d}|dd}gd}|r,|d||td|z.^:zUser %s not found in %sz0User %s found in %s. Checking for empty passwordTF)rrshadow_extrausers_fn shadow_fnr#shadow_empty_locked_passwd_patternsrrrrrefindall MULTILINErert)rNrZ shadow_filesZshadow_empty_passwd_reZ shadow_fileZshadow_contentr7rr8$_shadow_file_has_empty_user_password-s2   z+Distro._shadow_file_has_empty_user_passwordc Ksd|vr|j|fi|S|j|fi| }d}d}d}d}d|vrld}d}|drh|||dnd}d|vrd}d}|dr|j||dddnd}|r|sd|vrd}ttd tjd |d || }nd|vrd}d}|dsd}|d dr | |n\|s|r6|r*t d ||| |n0|rRttd tjd|d nttd tjd|d d|vr|dr| ||dd|vr|dr| ||dn&|ddurtjd|ddddd|vrd|d}t|tr|g}nt|trt|}|durTt|tttfsFtdt|g}nt|pRg}tt||d|vr|dg} | std||dn:|d} tj} | d| } | d|} tjt| || ddS)a Creates or partially updates the ``name`` user in the system. This defers the actual user creation to ``self.add_user`` or ``self.add_snap_user``, and most of the keys in ``kwargs`` will be processed there if and only if the user does not already exist. Once the existence of the ``name`` user has been ensured, this method then processes these keys (for both just-created and pre-existing users): * ``plain_text_passwd`` * ``hashed_passwd`` * ``lock_passwd`` * ``doas`` * ``sudo`` * ``ssh_authorized_keys`` * ``ssh_redirect_user`` rFNZplain_text_passwdTZ hashed_passwd)hashedrz24.3z5'passwd' in user-data is ignored for existing user %s)loggerversionZrequested_levelmsgr lock_passwdzIAllowing unlocking empty password for %s based on empty '%s' in user-datazNot unlocking blank password for existing user %s. 'lock_passwd: false' present in user-data but no existing password set and no 'plain_text_passwd'/'hashed_passwd' provided in user-datazNot unlocking password for user %s. 'lock_passwd: false' present in user-data but no 'passwd'/'plain_text_passwd'/'hashed_passwd' provided in user-dataZdoasZsudozThe value of 'false' in user z's 'sudo' configz22.2zUse 'null' instead.rZssh_authorized_keyszZInvalid type '%s' detected for 'ssh_authorized_keys', expected list, string, dict, or set.Zssh_redirect_userZcloud_public_ssh_keysz^Unable to disable SSH logins for %s given ssh_redirect_user: %s. No cloud public-keys present.z$USERz $DISABLE_USER)options)rr set_passwdrreloggingZWARNINGr rprrt unlock_passwdwrite_doas_ruleswrite_sudo_rulesrrrWrXrarYvaluesrZr`r|typerZsetup_user_keysZDISABLE_USER_OPTSreplace) rNrCrZpre_existing_userZhas_existing_passwordZud_blank_password_specifiedZud_password_specifiedZ password_keyrZ cloud_keysZ redirect_userZdisable_optionr7r7r8 create_userOs                    zDistro.create_userc Csdd|gdd|gf}ztdd|D}Wn@tyj}z(td|dd |Df|WYd }~n d }~00zt|Wn6ty}zttd ||WYd }~n d }~00d S) zL Lock the password of a user, i.e., disable password logins rz-lusermodz--lockcss |]}t|dr|VqdSrNrwhichrlZtoolr7r7r8 roz%Distro.lock_passwd..zBUnable to lock user account '%s'. No tools available. Tried: %s.cSsg|] }|dqSrr7rlcr7r7r8rn roz&Distro.lock_passwd..Nz&Failed to disable password for user %snext StopIteration RuntimeErrorrrrrre)rNrCZ lock_toolscmdrr7r7r8rs zDistro.lock_passwdrkc Csdd|gdd|gf}ztdd|D}Wn@tyj}z(td|dd |Df|WYd }~n d }~00ztj|d d gd \}}Wn6ty}zttd||WYd }~n d }~00|r|dd|gddd|gf}ztdd|D}WnBty2}z(td|dd |Df|WYd }~n d }~00zt|Wn8tyz}zttd||WYd }~n d }~00d S)zM Unlock the password of a user, i.e., enable password logins rz-urz--unlockcss |]}t|dr|VqdSrrrr7r7r8rroz'Distro.unlock_passwd..zDUnable to unlock user account '%s'. No tools available. Tried: %s.cSsg|] }|dqSr r7r!r7r7r8rn roz(Distro.unlock_passwd..Nrrcsz%Failed to enable password for user %sz-drz''css |]}t|dr|VqdSrrrr7r7r8r0szTUnable to set blank password for user account '%s'. No tools available. Tried: %s.cSsg|] }|dqSr r7r!r7r7r8rn7roz(Failed to set blank password for user %sr#)rNrCZ unlock_toolsr'r_rZpasswd_set_toolsr7r7r8rsN  zDistro.unlock_passwdc CsPztdd|gWn6tyJ}zttd||WYd}~n d}~00dS)Nrz--expirezFailed to set 'expire' for %s)rrrrre)rNuserrr7r7r8 expire_passwdAs zDistro.expire_passwdc Cstd||f}dg}|r |dztj||d|dWn6tyn}zttd||WYd}~n d}~00dS)Nz%s:%schpasswd-ezchpasswd for %s)datarzFailed to set password for %sT)r{rrrrre)rNr,rr Z pass_stringr'rr7r7r8rHs   zDistro.set_passwd)plist_inr cCs>ddd|Dd}dg|r&dgng}tj||ddS)N css |]\}}d||gVqdS)rNr)rlrCpasswordr7r7r8r_roz"Distro.chpasswd..r.r/)r0)rr)rNr1r Zpayloadr'r7r7r8r.\s  zDistro.chpasswdcCszd}td||t||}|rhtd|d|d|krPtddStd|ddSntd dSdS) Nz^(?:permit|deny)(?:\s+(?:nolog|nopass|persist|keepenv|setenv \{[^}]+\})+)*\s+([a-zA-Z0-9_]+)+(?:\s+as\s+[a-zA-Z0-9_]+)*(?:\s+cmd\s+[^\s]+(?:\s+args\s+[^\s]+(?:\s*[^\s]+)*)*)*\s*$z3Checking if user '%s' is referenced in doas rule %rz!User '%s' referenced in doas ruler?z'Correct user is referenced in doas ruleTz.Incorrect user '%s' is referenced in doas ruleFz/doas rule does not appear to reference any user)rertrsearchr)rNr,ruleZ rule_patternZ valid_matchr7r7r8is_doas_rule_validis(     zDistro.is_doas_rule_validc Cs<|s |j}|D],}|||sd||f}t|dSqdd|g}|D]}|d|qLd|}|d7}tj|st |g}zt j |d|ddWn6t y} zt td|| WYd} ~ n d} ~ 00nZ|t |vr8zt ||Wn8t y6} zt td || WYd} ~ n d} ~ 00dS) NzHInvalid doas rule %r for user '%s', not writing any doas rules for user!rz# cloud-init User rules for %s%sr2 rzFailed to write doas file %sz Failed to append to doas file %s)doas_fnr7rerfr{rrrrrrrrrr append_file) rNr,rulesZ doas_filer6rlinescontentrrr7r7r8rs<      zDistro.write_doas_rules /etc/sudoersc Csvd}d}d}tj|r(t|}d}ntj|r>t|}d}|D]N}|}td|}|shqJ| d} | s|qJtj | } | |krJd}qqJ|sfz|sddtj dd d |dg} |rt d ||d | 7}t||d n.dtj dd d |dg} d | }t||t d||Wn8tyd} ztt d|| WYd} ~ n d} ~ 00t|ddS)NrFz/usr/etc/sudoersTz^[#|@]includedir\s+(.*)$r?z?# See sudoers(5) for more information on "#include" directives:rrz#includedir %szUsing content from '%s'r2r9zAdded '#includedir %s' to %szFailed to write %si)rrrrr splitlinesrrr5rabspathrrerwrrr;rtrrZ ensure_dir) rNrZ sudo_baseZsudoers_contentsZ base_existsZsystem_sudo_baseZ found_includelineZ include_matchZ included_dirr=rr7r7r8ensure_sudo_dirs\            zDistro.ensure_sudo_dirc Csf|s |j}dd|g}t|ttfrB|D]}|d||fq(n4t|tr`|d||fnd}t|t|d |}|d7}| t j |t j |st|g}zt|d |dWn8ty} zttd|| WYd} ~ n d} ~ 00nZ|t|vrbzt||Wn8ty`} zttd|| WYd} ~ n d} ~ 00dS) Nrz# User rules for %sz%s %sz1Can not create sudoers rule addition with type %rr2r9zFailed to write sudoers file %sz#Failed to append to sudoers file %s) ci_sudoers_fnrWrYrZr{rX TypeErrorrZobj_namerrCrrdirnamerrrrrrrerr;) rNr,r<Z sudo_filer=r6rr>rrr7r7r8rs@  zDistro.write_sudo_rulescCsd|g}tr|d|s"g}t|r:td|n|rd|dnd}tjdd|d|dd|gfi|S) a` Perform a command as the requested user. Behaves like subp() Note: We pass `PATH` to the user env by using `env`. This could be probably simplified after bionic EOL by using `su --whitelist-environment=PATH ...`, more info on: https://lore.kernel.org/all/20180815110445.4qefy5zx5gfgbqly@ws.net.home/T/ zcd z && rZsur2z-czenv PATH=$PATH  )rr)rNrr,rarZ directoryr7r7r8do_ass z Distro.do_as)r lease_filepid_file interface config_filerRc Cs*|ddd|d|ddg |r"d||gn|gS)Nz-1z-vz-lfz-pfz-sfz /bin/truez-cfr7)rrdrerfrgr7r7r8build_dhclient_cmds  zDistro.build_dhclient_cmdcCs.|jdur(t|_|js(td|j|jS)zADetermine the network interface used during local network config.Nz0Did not find a fallback interface on distro: %s.)rLrZfind_fallback_nicrer|rCrr7r7r8fallback_interfaces  zDistro.fallback_interfacecCs ||_dSr)rL)rNrr7r7r8ris)pidrRcCsVt|d}|durRttt|WdS1s:0Ytd||dS)=Return the parent pid of a process by parsing /proc/$pid/statrNz&/proc/%s/stat has an invalid ppid [%s]r9_get_proc_stat_by_indexrr\rJrer|rjmatchr7r7r8 get_proc_ppids   &zDistro.get_proc_ppidcCsVt|d}|durRttt|WdS1s:0Ytd||dS)rkNz&/proc/%s/stat has an invalid pgid [%s]rlrnr7r7r8 get_proc_pgids   &zDistro.get_proc_pgid)rjfieldrRc CszJtjd|dd}td|}|srorr7r7r8rms0 "  zDistro._get_proc_stat_by_index)devicerRcCsLd}tdrd|g}n&tdr.dd|g}ntjddddt|dS)NZejectz/lib/udev/cdrom_idz --eject-mediaZeject_media_cmdzeject command not foundz.neither eject nor /lib/udev/cdrom_id are found)r' descriptionreason)rrr)rvr'r7r7r8 eject_medias    zDistro.eject_media)blockdevrRcCs,tj|}|dr(td|||SdS)aReturns underlying block device for a mapped device. If it is mapped, blockdev will usually take the form of /dev/mapper/some_name If blockdev is a symlink pointing to a /dev/dm-* device, return the device pointed to. Otherwise, return None. z/dev/dm-z$%s is a mapped device pointing to %sN)rrrealpath startswithrert)rzr{r7r7r8get_mapped_devices  zDistro.get_mapped_device)devpathrRc Cstj|}tj|}d|}tj|sr#Z_ci_pkl_versionrZresolve_conf_fnr@r rArPrJrUr^ PackageListr rrr rirvpropertyr!Z DhcpClientr}r ZNetworkActivatorrr%rrrrrr staticmethodrabcabstractmethodrrrrrrboolrrrrrrrrrrrrrrrrrr rrrr-rrYr.r7rrCrr classmethodrMrPrZr^r`rcrhrisetterrprrrmryr}rZrrr7r7r7r8r9s     5;               A+ y"4,   $ 6 )   $     #r9) metaclassurltransformationscCsztj|}Wnty$YdS0|j}|dur8dS|D]}||}|dur<|Sq<|}|jdurvd||j}tj|j|dS)a Apply transformations to a URL's hostname, return transformed URL. This is a separate function because unwrapping and rewrapping only the hostname portion of a URL is complex. :param url: The URL to operate on. :param transformations: A list of ``(str) -> Optional[str]`` functions, which will be applied in order to the hostname portion of the URL. If any function (regardless of ordering) returns None, ``url`` will be returned without any modification. :return: A string whose value is ``url`` with the hostname ``transformations`` applied, or ``None`` if ``url`` is unparsable. Nz{}:{})netloc) urllibparseurlsplitr\rportr urlunsplit_replace)rrpartsZ new_hostnameZtransformationZ new_netlocr7r7r8&_apply_hostname_transformations_to_urlCs   r)rcs2tdddddfddddg}t||S)aH Given a mirror URL, replace or remove any invalid URI characters. This performs the following actions on the URL's hostname: * Checks if it is an IP address, returning the URL immediately if it is * Converts it to its IDN form (see below for details) * Replaces any non-Letters/Digits/Hyphen (LDH) characters in it with hyphens * Removes any leading/trailing hyphens from each domain name label Before we replace any invalid domain name characters, we first need to ensure that any valid non-ASCII characters in the hostname will not be replaced, by ensuring the hostname is in its Internationalized domain name (IDN) representation (see RFC 5890). This conversion has to be applied to the whole hostname (rather than just the substitution variables), because the Punycode algorithm used by IDNA transcodes each part of the hostname as a whole string (rather than encoding individual characters). It cannot be applied to the whole URL, because (a) the Punycode algorithm expects to operate on domain names so doesn't output a valid URL, and (b) non-ASCII characters in non-hostname parts of the URL aren't encoded via Punycode. To put this in RFC 5890's terminology: before we remove or replace any characters from our domain name (which we do to ensure that each label is a valid LDH Label), we first ensure each label is in its A-label form. (Note that Python's builtin idna encoding is actually IDNA2003, not IDNA2008. This changes the specifics of how some characters are encoded to ASCII, but doesn't affect the logic here.) :param url: The URL to operate on. :return: A sanitized version of the URL, which will have been IDNA encoded if necessary, or ``None`` if the generated string is not a parseable URL. .cSst|rdS|Sr)rZ is_ip_addressrr7r7r8roz&_sanitize_mirror_url..cSs|ddS)NZidnaascii)encodedecoderr7r7r8rrocsdfdd|DS)Nrc3s|]}|vr|ndVqdSr2Nr7r!Zacceptable_charsr7r8rs9_sanitize_mirror_url....r3rrr7r8rscSsddd|dDS)Nrcss|]}|dVqdSrr)rlpartr7r7r8rsr)rrrr7r7r8rs )LDH_ASCII_CHARSrrr7rr8_sanitize_mirror_urlns& rc Cs&|si}i}|rb|jrb|j|d<t|jrb|jdd}trLd||d<n|jdkrbd||d<|rv|jrv|j|d<i}|diD]\}}|||<q|d iD]h\}}g} |D]B} z | |}WntyYqYn0t |}|dur| |q|| } | r| ||<qt d ||S) Navailability_zonerr8 ec2_regionZec2regionZfailsafer5zfiltered distro mirror info: %s) r _EC2_AZ_RErorZ platform_typerrprbrdrr{rert) rrZ mirror_filtersubstrresultsrCZmirrorZ searchlistZmirrorsZtmplfoundr7r7r8rs>              rcCs8d}|D]*}|d}||vr&|Sd|vr|}q|S)Narchesr)rp)rr)ritemrr7r7r8rs r)rCrRcCsHt|dtgdg\}}|s,td||ft|d}t|d}|S)Nrr9z1No distribution found for distro %s (searched %s)r)r find_moduler4 ImportError import_modulegetattr)rCZlocsZ looked_locsmodrKr7r7r8fetchs r /etc/timezone/etc/localtimecCsht|t|d|rd|rdtj|}|s s   0 0          '    I+< 3