HcffddlZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl m Z ddl mZddlmZmZmZmZmZmZmZddlmZmZmZdZdZdZd Zd Zd d iZ ejBejDe#Z$d Z%dZ&eddejNfdejNfgZ(edde)fde)fdeejfdee)fdee*fdee*fdee*fdee)fdee)fg Z+edde)fde)fde)fd e)fgZ,ed!d"e)fd#ee*fd$ee*fgZ-ed%d&eee)fd'eee)fgZ.d(Z/d)ej`d*eejfd+Z1d)ej`d*eejfd,Z2e d-d*e+fd.Z3d/Z4e d-d*e)fd0Z5e d-d*e)fd1Z6e d-d*e-fd2Z7e d-d*e)fd3Z8e d-d*e,fd4Z9e d-de)d*e:fd5Z;e d-d*e:fd6Z<e d-de)d*e:fd7Z=e d-de)d*e:fd8Z>e d-d*e:fd9Z?e d-d_d:e)d*e:fd;Z@e d-d*e:fd<ZAe d-d*ee)e)ffd=ZBe d-de)d*e(fd>ZCd?e)d*ee)fd@ZD d`dAeee)dBeee)d*e:fdCZEdDe)d*e:fdEZFdadFe)dGe:d*e)fdHZGdbdFe)dIe*d*dfdJZH dcdFe)dKe)dIee*d*dfdLZIdMe)d*dfdNZJ dddOee)dPeee*dQe:dReeKdSeee)e)fdTe:d*ee)e)ffdUZL dedOee)dPeee*dQe:dReeKdVeeeKdSeee)e)fdTe:d*ee)e)ffdWZMdXe)d*dfdYZNdZe)d*e:fd[ZOdZe)d*ee)fd\ZPd*e)fd]ZQd*ee.fd^ZRy)fN) lru_cache)rmtree)DictList NamedTupleOptionalSequenceSetTuple)defaults exceptionsutilz/var/run/reboot-requiredz/var/run/reboot-required.pkgsz/etc/machine-idz/var/lib/dbus/machine-idz!/usr/share/distro-info/ubuntu.csv GenuineIntelintelz5(?P\d+\.\d+) (LTS\s*)?(\((?P\w+))?.*zd^(?P[\d]+)[.-](?P[\d]+)[.-](?P[\d]+)-(?P[\d]+)-(?P[A-Za-z0-9_-]+)$ DistroInfoeoleol_esm KernelInfouname_machine_arch uname_release build_dateproc_version_signature_versionmajorminorpatchabiflavor ReleaseInfo distributionreleaseseriespretty_versionCpuInfo vendor_idmodelsteppingRebootRequiredPkgsstandard_packageskernel_packagesz(Mon|Tue|Wed|Thu|Fri|Sat|Sun).*unamereturnctrtjdytjd tjdj |j }tjj|jtjjS#t$rtjdYywxYw)NzPNot attempting to use timestamp of kernel changelog because we're in a containerz3Falling back to using timestamp of kernel changelogz1/usr/share/doc/linux-image-{}/changelog.Debian.gzzUnable to stat kernel changelog) is_containerLOGwarningosstatformatr datetime fromtimestampst_mtimetimezoneutc Exception)r* stat_results 1/usr/lib/python3/dist-packages/uaclient/system.py_get_kernel_changelog_timestampr;_s~ ^ KKEF gg ? F F     ..  ("3"3"7"7    56sA/B''CCctjt|j}| tj dt |S|jd} tjj|d}|j*|jtjj}|S#t$r#tj dt |cYSwxYw)Nz*Unable to find build date in uname versionrz%a %b %d %H:%M:%S %Z %Yz-Unable to parse build date from uname version)tzinfo)researchRE_KERNEL_EXTRACT_BUILD_DATEversionr.r/r;groupr3strptime ValueErrorr=replacer6r7)r* date_matchdate_strdts r:_get_kernel_build_daterIxs7GJ @A.u55"H6    ' '2K L yyZZx0044Z 5 I 6 CD.u556s B11)CC)maxsizec d} td}|jd}t j }|jj}t|}|jj}tjt|}|*tj d|t||||ddddd St||||t|j!dt|j!dt|j!d|j!d |j!d  S#t$rtj dY4wxYw) Nz/proc/version_signaturez*failed to process /proc/version_signature.zFailed to parse kernel: %s) rrrrrrrrrrrrrr) load_filesplitr8r.r/r0r*machinestriprIr r>matchRE_KERNEL_UNAMErintrB)rproc_version_signature_fullr*rrr uname_matchs r:get_kernel_inforVsG%)"B&/0I&J#)D)J)J)LQ)O& HHJE,,.'.JMM'')M((?M:K 0-@1'!+I  1'!+Ik''01k''01k''01!!%($$X.  / B @ABsD55EEcddlm}tjs t d|Dcgc]}d|vr| }}t j dDcgc]}dt d|gdvr|}}|Dcgc]}|tdd}}|Dcgc]}|tdd}}|D cgc]} | |vr|  c} Scc}wcc}wcc}wcc}wcc} w) Nr)get_installed_packages_namesz9get_installed_ubuntu_kernels needs to be executed as rootz linux-image-z/boot/vmlinu[x|z]-*z Linux kernelfilez/boot/vmlinu?-) uaclient.aptrXrwe_are_currently_root RuntimeErrorglobsubplen) rXpackage linux_imagerYvmlinux_kernel_files package_namelinux_image_versions file_namevmlinuz_versionsrAs r:get_installed_ubuntu_kernelsrgs$9  % % ' G  45  W $ KII34  T64.1!4 4 AL0< S(*+ .  #&')*(   * *  '    s B<C6CC , CcBtddg\}}|jS)Ndpkgz--print-architecture)r^rP)out_errs r: get_dpkg_archrls"f456IC 99;c tdg\}}|jS#tj$r/ t d}d|vsd|vrYyd|vrYyYy#t $rYYywxYwwxYw)Nsystemd-detect-virtz/proc/1/cgroupdockerbuildkitbuildahpodman)r^rPr ProcessExecutionErrorrMr8)rj_ proc_1_cgroups r: get_virt_typerxs|,-.Qyy{  + +  %&67M=(J-,Gm+   s,!A#A A AA#AA#ctd}i}dD]O}tjdj||tj}|s:|j d}|||<Q|j dd}|j d}|j d}ttj |||r t|nd|rt|SdS) Nz /proc/cpuinfo)r$r%r&z^{}\s*:\s*(?P\w*)infor$rtr%r&) rMr>r?r2 MULTILINErBgetr#CPU_VENDOR_MAPrS)cpu_info_contentcpu_info_valuesfield cpu_matchvaluevendor_id_baser%r&s r: get_cpu_infors 1O3+II & - -e 4  LL OOF+E%*OE "+%((b9N    (E"":.H  $$^^D!c%jt"*X 15 rmcddlm}|jr/|jjdijd}|r|S|j }t t fD]B}tjj|s#t|jd}|s@|cS|r|Sttj}|j||S)z Get system's unique machine-id or create our own in data_dir. We first check for the machine-id in machine-token.json before looking at the system file. r)machine_id_filemachineTokenInfo machineId )uaclient.files.state_filesr machine_tokenr|readETC_MACHINE_IDDBUS_MACHINE_IDr0pathexistsrMrstripstruuiduuid4write)cfgrcfg_machine_idfallback_machine_idrcontent machine_ids r:get_machine_idrs; **../A2FJJ   ! !)..01 77>>$ o,,T2G  ""TZZ\"J*% rmc@t}|jdd}tjdd|jdd}|jdd}|jdd}|r|stjt |}|s't j|jdd| |j}|xs|jd d}|st j| |xs|jd d}t|||j| S)NNAMEUNKNOWNz\.\d LTSz LTSVERSIONrtVERSION_CODENAME VERSION_ID)orig_vermod_verr!)rAr )rr r!r") _parse_os_releaser|r>subrQREGEX_OS_RELEASE_VERSIONr ParsingErrorOnOSReleaseFile groupdictMissingSeriesOnOSReleaseFilerlower) os_releaserr"r!r rQ match_dicts r:get_release_infor.s"$J>>&)4LVVK 21NON ^^. 3Fnn\2.G 1>B88# 26 __& 7:>>(B799& :Z^^Ir: !||~%  rmc*tddg\}}||vS)N/usr/bin/ubuntu-distro-infoz--supported-esmr^r!rjrks r:is_ltsrNs!35FGHIC S=rmc<ttjSN)rrr!rmr:is_current_series_ltsrTs "$++ ,,rmc*tddg\}}||vS)Nrz --supportedrrs r: is_supportedrYs 3]CDIC S=rmcZt|sytdd|dg\}}t|dkS)zCReturn True when Ubuntu series supports ESM and is actively in ESM.Frz--seriesz-yeolr)rr^rSrs r: is_active_esmr_s8 &> & FGDIC s8q=rmc<ttjSr)rrr!rrmr:is_current_series_active_esmrjs )+22 33rmrun_pathc* tdgy#tj$rYnwxYw tgdy#ttf$rYnwxYwdD]C}t j j||}t j j|sCyy)z>Checks to see if this code running in a container of some sortischrootF)ro--quietz --containerT)container_typezsystemd/container) r^r ruIOErrorOSErrorr0rjoinr)rfilenamers r:r-r-os  j\  + +     >? W    <ww||Hh/ 77>>$  s %% 7A A cZddlm}|jD]}d|jvsyy)zReturns True if any package installed has "ubuntu-desktop" in the name. This includes ubuntu-desktop, ubuntu-desktop-minimal, kubuntu-desktop, etc. r)aptzubuntu-desktopTF)uaclientrget_installed_packagesname)rr`s r: is_desktoprs3 --/ w|| + rmc td}i}|jD]<}|jdd\}}|s|j j d||<>|S#t$rtd}YiwxYw)Nz/etc/os-releasez/usr/lib/os-release=rL")rMFileNotFoundError splitlinesrNrP) file_contentsdatalinekeyrs r:rrs9!"34  D((*1ZZQ' U  ++C0DI1 K 9!"78 9s A A76A7c ttj}|D]}|j d}|d|k(s|dk(rd}nd|dvr|dn|d}ttjj|dd jtjj|d j cSt j| #t$rt j wxYw) N,xenialz 2026-04-23LTSrz%Y-%m-%d)rr)r!) rMDISTRO_INFO_CSVrrr MissingDistroInfoFilerNrr3rCdateMissingSeriesInDistroInfoFile)r!linesrvaluesrs r:get_distro_infors1/*557 C !9 !&',q '9&)vay%%..vay*EJJL ))227JGLLN    2 2& AA 1..001s CC6programctjj|vr t|r|Stjj ddj tjDcgc]}|jd}}|Dcgc]!}tjj|#}}|D]1}tjj||}t|s/|cSycc}wcc}w)z;Find whether the provided program is executable in our PATHPATHrtrN) r0rsepis_exeenvironr|rNpathseprPabspathr)rppathsnormalized_pathsr program_paths r:whichrs ww{{g '?N jjnnVR8>>rzzJ   E 5::q*::  ww||D'2 ,     ;s )C&&C+installed_pkgsinstalled_pkgs_regexcVtjjtsy||y t t t jd}|t|j|dk7ry|'|D]"}|D]}tj||sy$y#t$rYywxYw)aCheck if the system needs to be rebooted. :param installed_pkgs: If provided, verify if the any packages in the list are present on /var/run/reboot-required.pkgs. If that param is provided, we will only return true if we have the reboot-required marker file and any package in reboot-required.pkgs file. When both installed_pkgs and installed_pkgs_regex are provided, they act as an OR, so only one of the two lists must have a match to return True. :param installed_pkgs_regex: If provided, verify if the any regex in the list matches any line in /var/run/reboot-required.pkgs. If that param is provided, we will only return true if we have the reboot-required marker file and any match in reboot-required.pkgs file. When both installed_pkgs and installed_pkgs_regex are provided, they act as an OR, so only one of the two lists must have a match to return True. FTrr) r0rrREBOOT_FILE_CHECK_PATHsetrMREBOOT_PKGS_FILE_PATHrNrr_ intersectionr>r?)rrreboot_required_pkgspkg_name pkg_regexs r: should_rebootrs0 77>>0 1"6">" + , 2 24 8 ! ~**+?@ AQ F', H1 99Y1   s'B B('B(rctjj|xr$tj|tjSr)r0risfileaccessX_OK)rs r:rrs) 77>>$  >' ""  s 'A  Amodec tjd|tjtjj |dt j|jtj||y)NzCreating file: %sTexist_ok) r.rr0makedirsrdirnamepathlibPathtouchchmod)rrs r: create_filersOII!8,KK)D9 LL  "HHXtrmrcd}tjj|}|rGtj|j }t j |j}||}n|d} tjtjj|dtjddtjj|}tjd||j|j|j!d |j#|j%tj&|j||r5tj(|jj*|j,tj.|j|y#t0$r(}|tj2|j|d}~wwxYw) a_Write content to the provided filename encoding it if necessary. We preserve the file ownership and permissions if the file is present and no mode argument is provided. @param filename: The full path of the file to write. @param content: The content to write to the file. @param mode: The filesystem mode to set on the file. NTrwbF)rdeletedirz*Writing file %s atomically via tempfile %sr)r0rrr r r1S_IMODEst_moder r tempfileNamedTemporaryFiler.rrrencodeflushcloserchownst_uidst_gidrenamer8unlink)rrrtmpfis_file_present file_statf_modees r: write_filer'sU DggnnX.OLL*//1 i//0 <D  BGGOOH-=**e)B  8(DII  7>>'*+   D!  HHTYY 0 0)2B2B C $))X&    IIdii s0EF22 G#;#GG# file_pathc tj|tjd|y#t$rtjd|YywxYw)z JKs+.AAargsrcscapturetimeoutoverride_env_varspipe_stdouterrc|Dcgc]%}t|tr|n|jd'}}d}d} |r tj}tj} d} |rit j |} |dg}tjdj|} tj||| | } | j|\} }| r| jdnd}|r|jdnd}| j |vr#tj| | j |||r"t$j'd | | j |||fScc}w#t$rr  r| jdnd}r|jdnd}tj|  j ||#t"$rtj| wxYwwxYw) aRun a command and return a tuple of decoded stdout, stderr. @param args: A list of arguments to feed to subprocess.Popen @param rcs: A list of allowed return_codes. If returncode not in rcs raise a ProcessExecutionError. @param capture: Boolean set True to log the command and response. @param timeout: Optional float indicating number of seconds to wait for subp to return. @param override_env_vars: Optional dictionary of environment variables. If None, the current os.environ is used for the subprocess. If defined, these env vars get merged with the current process' os.environ for the subprocess, overriding any values that already existed in os.environ. @return: Tuple of utf-8 decoded stdout, stderr @raises ProcessExecutionError on invalid command or returncode not in rcs. @raises subprocess.TimeoutError when timeout specified and the command exceeds that number of seconds. rNr )stdoutstderrenv)r.rt)cmd exit_coder3r4)r6zRan cmd: %s, rc: %s stderr: %s) isinstancebytesr subprocessPIPEr0rrredact_sensitive_logsrPopen communicaterrr ru returncodeUnboundLocalErrorr.r)r+r,r-r.r/r0x bytes_argsr3r4 merged_env redacted_cmdprocrjerr out_result err_results r:_subprIJs8CG=>Z5 !qxx'88JF F J8 8&78  {c--chhtn=LE    %%g%6 c),G$J(+G$J c!..oo    ,  OO   z !!s8  E E03G,J03G,J22 //!!   ! E22|D D E Es$*E .E G A F&& GG  retry_sleepsc||jnd} t||||||\}} ||fS#tj$r} |rItj t | tjd| j| j|stj t | tj dt|tj|jdYd} ~ nd} ~ wwxYw)aRun a command and return a tuple of decoded stdout, stderr. @param subp: A list of arguments to feed to subprocess.Popen @param rcs: A list of allowed return_codes. If returncode not in rcs raise a ProcessExecutionError. @param capture: Boolean set True to log the command and response. @param timeout: Optional float indicating number of seconds to wait for a subp call to return. @param retry_sleeps: Optional list of sleep lengths to apply between retries. Specifying a list of [0.5, 1] instructs subp to retry twice on failure; sleeping half a second before the first retry and 1 second before the next retry. @param override_env_vars: Optional dictionary of environment variables. If None, the current os.environ is used for the subprocess. If defined, these env vars get merged with the current process' os.environ for the subprocess, overriding any values that already existed in os.environ. @return: Tuple of utf-8 decoded stdout, stderr @raises ProcessExecutionError on invalid command or returncode not in rcs. @raises subprocess.TimeoutError when timeout specified and the command exceeds that number of seconds. N)r/r0zStderr: %s Stdout: %szRetrying %d more times.r)copyrIr rur.rrr/r4r3r_timesleeppop) r+r,r-r.rJr/r0rjrFr&s r:r^r^s@+7*B<$$&L  ,"3- HC  8O// , #a&! 4ahhI IIc!f  II/\1B C JJ|''* + + , s0C<B/C77C< folder_pathc t|tjd|y#t$rtjd|YywxYw)NzRemoved folder: %sz,Tried to remove %s but folder does not exist)rr.rr)rPs r:ensure_folder_absentrRs?O{ & 4 O @+NOs!$AA service_namecV tddd|gy#tj$rYywxYw)a^ Get if the systemd job is active in the system. Note that any status different from "active" will make this function return False. Additionally, if the system doesn't exist we will also return False here. @param service_name: Name of the systemd job to look at @return: A Boolean specifying if the job is active or not systemctlz is-activerFT)r^r ru)rSs r:is_systemd_unit_activerVs7 k; < @A   + +s ((c4 tdddd|g\}}|r3|jdr"|jddjStj d| y#t j$r"}tj d || Yd}~yd}~wwxYw) NrUshowz--property=ActiveStatez --no-pagerz ActiveState=rrLz9Couldn't find ActiveState in systemctl show output for %sz-Failed to get ActiveState for systemd unit %s)exc_info)r^ startswithrNrPr.r/r ru)rSrjrvr&s r:get_systemd_unit_active_stater[s (   Q 3>>.199S>!$**, , KKK    + +  ;      sAA" A""B5BBctjrtjStj j d}|r.tjj|tjStjjtjjddtjS)NXDG_CACHE_HOME~z.cache) rr[r UAC_RUN_PATHr0rr|rrUSER_CACHE_SUBDIR expanduser)xdg_cache_homes r:get_user_cache_dirrcs| !!#$$$ZZ^^$45Nww||NH,F,FGG 77<< 38+E+E rmc& tt}g}g}d}|jD];}t j ||r|j |+|j |=tt|t|S#t$rYywxYw)Nz^(linux-image|linux-base).*)r(r)) rMrrrNr>rQappendr'sorted) pkg_list_strr(r) kernel_regexpkgs r:get_reboot_required_pkgsrjs !67 O0L!!#* 88L# &  " "3 '  $ $S ) *  !23/  sB BB)z/run)NN)T)rr)NFNNT)NFNNNT)Sr3r]loggingr0r r>r1r:rrMr functoolsrshutilrtypingrrrrr r r rr r rrrrrrr} getLoggerreplace_top_level_logger_name__name__r.rrRrrrrSrrr#r'r@ uname_resultr;rIrVrgrlrxrrrboolrrrrrr-rrrrrrrMrr'r*floatrIr^rRrVr[rcrjrrmr:rus    III//37",5 '*g:::8DE=  E8==)Ix}}+EF  s# # x 1 123 )8C=9 (3- (3- (3-   8C=!     C 3 3    c (3- Xc]#   htCy12 HT#Y/0 B ?? h 2 ?? h ( 4& & & V F 4s  4s( 4g. 43> 4+> 434  4-t-- 4  4#$ 44d44 43D4 4 D   4 4S>   4BCBJBB(38C=$*./33SX&3"3s8,3 3l=== ##T#S##ST8<((('/}( (VK#K$K $#26 T" 3-T" $s) T"T"e_ T"  S#X/ T"  T" 38_T"r $#*.265 3-5 $s) 55e_ 5 4;' 5  S#X/ 55 38_5pOcOdO$ 6 C (+=">rm