{"id":8790,"date":"2022-03-21T21:07:00","date_gmt":"2022-03-22T02:07:00","guid":{"rendered":"https:\/\/www.rushworth.us\/lisa\/?p=8790"},"modified":"2022-03-22T15:11:59","modified_gmt":"2022-03-22T20:11:59","slug":"reporting-last-patch-dates-on-fedora-redhat-centos-systems","status":"publish","type":"post","link":"https:\/\/www.rushworth.us\/lisa\/?p=8790","title":{"rendered":"Reporting Last Patch Dates on Fedora \/ RedHat \/ CentOS Systems"},"content":{"rendered":"\n<p>I needed to verify the last time a bunch of servers were patched &#8212; basically to ensure compliance with the stated quarterly patching interval. This python script pulls the list of installed packages and the date for each package, sorts the info by date DESC, and then reports the latest date on any packages &#8212; as well as the number of packages updated on that date. If there&#8217;s only one &#8230; the system still might bear some investigation. But if a couple of dozen packages were updated in the past quarter &#8230; we don&#8217;t need to be too worried about turning up on the out-of-compliance report. <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nimport subprocess\nimport re\nimport datetime\nfrom collections import OrderedDict\n\ndef getFirstElement(odictInput):\n    &#039;&#039;&#039;\n        This function returns the first element from an ordered collection (an arbitrary element if an unordered collection is passed in)\n        Input -- odictInput -- ordered collection\n        Output -- type varies -- first element of ordered collection, arbitrary element of unordered collection\n\n    &#039;&#039;&#039;\n    return next(iter(odictInput))\n\nlistHosts = &#x5B;&#039;host01.example.com&#039;, &#039;host02.example.com&#039;, &#039;host03.example.com&#039;,&#039;host04.example.com&#039;,&#039;host05.example.com&#039;]\n\nfor strHost in listHosts:\n        dictPatchDates = {}\n\n        objResults = subprocess.Popen(&#x5B;&#039;ssh&#039;, strHost, &#039;rpm&#039;, &#039;-qa&#039;, &#039;--last&#039;],stdout=subprocess.PIPE)\n        for strLine in objResults.stdout:\n                strPackageInfo  = strLine.decode(&#039;utf-8&#039;).rstrip()\n                listPackageInfo = re.split(r&#039;\\s*(&#x5B;a-zA-Z]{3,}\\s&#x5B;0-9]{2,}\\s&#x5B;a-zA-Z]{3,}\\s&#x5B;0-9]{2,})&#039;,strPackageInfo)\n                strUpdateDate = listPackageInfo&#x5B;1]\n                dateUpdateDate = datetime.datetime.strptime(strUpdateDate, &quot;%a %d %b %Y&quot;).date()\n                if dictPatchDates.get(dateUpdateDate) is not None:\n                        dictPatchDates&#x5B;dateUpdateDate] = dictPatchDates&#x5B;dateUpdateDate] + 1\n                else:\n                        dictPatchDates&#x5B;dateUpdateDate] = 1\n\n        dictOrderedPatchDates = OrderedDict(sorted(dictPatchDates.items(), key=lambda t: t&#x5B;0],reverse=True))\n        dateLatestPatch = getFirstElement(dictOrderedPatchDates)\n        print(f&quot;{strHost}\\t{dateLatestPatch}\\t{dictOrderedPatchDates&#x5B;dateLatestPatch]}&quot;)\n\n<\/pre><\/div>","protected":false},"excerpt":{"rendered":"<p>I needed to verify the last time a bunch of servers were patched &#8212; basically to ensure compliance with the stated quarterly patching interval. This python script pulls the list of installed packages and the date for each package, sorts the info by date DESC, and then reports the latest date on any packages &#8212; &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[33,30],"tags":[304,1570,69,1571,396],"class_list":["post-8790","post","type-post","status-publish","format-standard","hentry","category-coding","category-system-administration","tag-automation","tag-patch-management","tag-security","tag-security-compliance","tag-system-administration"],"_links":{"self":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/8790","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=8790"}],"version-history":[{"count":1,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/8790\/revisions"}],"predecessor-version":[{"id":8791,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/8790\/revisions\/8791"}],"wp:attachment":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=8790"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=8790"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=8790"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}