cdn-ops/global/overlay/etc/puppet/setup_cosmos_modules
Patrik Lundin 94a65a31e0
Fix problems with outdated sunet puppet modules
Problem seen:
```
Error: Evaluation Error: Error while evaluating a Resource Statement, Evaluation Error: Unknown variable: '::osfamily'. (file: /etc/puppet/cosmos-modules/augeas/manifests/params.pp, line: 7, column: 8) on node example-1.sunet.se
```

This way we run modules installed from upstream apt packages instead.
Solution to delete keys to use local pacakges from pahol.

While here fix pylint issue with not importing platform module at
beginning of file.
2024-07-04 14:42:34 +02:00

161 lines
4.6 KiB
Python
Executable file

#!/usr/bin/env python3
""" Write out a puppet cosmos-modules.conf """
import hashlib
import os
import os.path
import platform
import sys
from debian import debian_support
try:
from configobj import ConfigObj
OS_INFO = ConfigObj("/etc/os-release")
except (IOError, ModuleNotFoundError):
OS_INFO = None
def get_file_hash(modulesfile):
"""
Based on https://github.com/python/cpython/pull/31930: should use
hashlib.file_digest() but it is only available in python 3.11
"""
try:
with open(modulesfile, "rb") as fileobj:
digestobj = hashlib.sha256()
_bufsize = 2**18
buf = bytearray(_bufsize) # Reusable buffer to reduce allocations.
view = memoryview(buf)
while True:
size = fileobj.readinto(buf)
if size == 0:
break # EOF
digestobj.update(view[:size])
except FileNotFoundError:
return ""
return digestobj.hexdigest()
def get_list_hash(file_lines):
"""Get hash of list contents"""
file_lines_hash = hashlib.sha256()
for line in file_lines:
file_lines_hash.update(line)
return file_lines_hash.hexdigest()
def create_file_content(modules):
"""
Write out the expected file contents to a list so we can check the
expected checksum before writing anything
"""
file_lines = []
file_lines.append(
"# Generated by {}\n".format( # pylint: disable=consider-using-f-string
os.path.basename(sys.argv[0])
).encode("utf-8")
)
for key in modules:
file_lines.append(
"{0:11} {1} {2} {3}\n".format( # pylint: disable=consider-using-f-string
key,
modules[key]["repo"],
modules[key]["upgrade"],
modules[key]["tag"],
).encode("utf-8")
)
return file_lines
def main():
"""Starting point of the program"""
modulesfile: str = "/etc/puppet/cosmos-modules.conf"
modulesfile_tmp: str = modulesfile + ".tmp"
modules: dict = {
"sunet": {
"repo": "https://github.com/SUNET/puppet-sunet.git",
"upgrade": "yes",
"tag": "stable-2023v1-2*",
},
"augeas": {
"repo": "https://github.com/SUNET/puppet-augeas.git",
"upgrade": "yes",
"tag": "sunet-2*",
},
"concat": {
"repo": "https://github.com/SUNET/puppetlabs-concat.git",
"upgrade": "yes",
"tag": "sunet-2*",
},
"stdlib": {
"repo": "https://github.com/SUNET/puppetlabs-stdlib.git",
"upgrade": "yes",
"tag": "sunet-2*",
},
"apt": {
"repo": "https://github.com/SUNET/puppetlabs-apt.git",
"upgrade": "yes",
"tag": "sunet-2*",
},
"docker": {
"repo": "https://github.com/SUNET/garethr-docker.git",
"upgrade": "yes",
"tag": "sunet-2*",
},
}
if OS_INFO:
# Provided by Debian/Ubuntu via
# https://github.com/SUNET/multiverse/blob/main/global/pre-tasks.d/030puppet
if (OS_INFO["ID"] == "debian" and int(OS_INFO["VERSION_ID"]) >= 12) or (
OS_INFO["ID"] == "ubuntu"
and debian_support.version_compare(OS_INFO["VERSION_ID"], "24.04") >= 0
):
del modules["augeas"]
del modules["apt"]
del modules["concat"]
del modules["stdlib"]
# Make test machines use special test branch of puppet-sunet:
if OS_INFO["ID"] == "ubuntu":
nodename = platform.node()
name_parts = nodename.split("-")
if len(name_parts) > 1:
if name_parts[1] == "test":
modules["sunet"]["tag"] = "testing-2*"
# Build list of expected file content
file_lines = create_file_content(modules)
# Get hash of the list
list_hash = get_list_hash(file_lines)
# Get hash of the existing file on disk
file_hash = get_file_hash(modulesfile)
# Update the file if necessary
if list_hash != file_hash:
# Since we are reading the file with 'rb' when computing our hash use 'wb' when
# writing so we dont end up creating a file that does not match the
# expected hash
with open(modulesfile_tmp, "wb") as fileobj:
for line in file_lines:
fileobj.write(line)
# Rename it in place so the update is atomic for anything else trying to
# read the file
os.rename(modulesfile_tmp, modulesfile)
if __name__ == "__main__":
main()