Source code for podcust.transmission.custodian

"""
Custodian Class for Transmission container.

This module is responsible for setting up and maintaining the container.

The container is intended to live inside the users home directory, in a hardcoded
location. Namely ``$HOME/transmission/``. The container is deployed within a pod
named transmission.
"""

# from typing import List
from shutil import rmtree
import subprocess
import getpass
from pathlib import Path
import importlib.resources as pkg_resources
from podcust.tools import get_user_input


[docs]class TransmissionCust: """ Main class for handling the transmission container. :param name: The full repository name of the image this class is custodian for. """ name: str image_id: str username: str def __init__(self, name: str = "ghcr.io/linuxserver/transmission"): """ Initialize TransmissionCust class. """ self.name = name self.image_id = "" self.username = getpass.getuser() # Main path we 'll use for the container self.main_path: Path = Path.home().joinpath("transmission")
[docs] def pull_latest_transmission_image(self): """ Pull latest transmission container image from linuxserver.io The relevant shell command is:: $ podman pull ghcr.io/linuxserver/transmission """ command_text = "podman pull $name" command_text = command_text.replace("$name", self.name) try: p = subprocess.run( command_text, text=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, ) print(p.stdout) except Exception as e: print(e)
[docs] def clear_location(self): """ Delete all files within the (hard-coded) path used by the transmission image under the podman custodian. """ try: if self.main_path.exists(): rmtree(self.main_path) except PermissionError as err: print( f"Please manually delete folder {str(self.main_path)} with required permissions." ) raise err
[docs] def deploy(self): """ Create a pod named transmission to deploy our container. The steps taken during deployment are the following: - Delete path we 'll use to ensure a clean start. - Create the necessary folders, and give them proper permissions. - Write the proper kube yaml file that we 'll use to deploy the container. - Open the necessary firewall port. - Execute the podman play command to start the pod with the transmission container. """ # Let's delete everything allready present on the space we want to use: self.clear_location() # let's recreate the directory now print("Creating key directories:") self.main_path.mkdir() # let's create additional needed directories config_dir = self.main_path.joinpath("config") config_dir.mkdir() watch_dir = self.main_path.joinpath("watch") watch_dir.mkdir() downloads_dir = self.main_path.joinpath("downloads") downloads_dir.mkdir() # We also need to change the SELinux security context of the new directories: print("Setting proper directory permissions:") command_text = "chcon -u system_u " + str(config_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "chcon -u system_u " + str(watch_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "chcon -u system_u " + str(downloads_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "chcon -r object_r " + str(config_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "chcon -r object_r " + str(watch_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "chcon -r object_r " + str(downloads_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "chcon -t container_file_t " + str(config_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "chcon -t container_file_t " + str(watch_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "chcon -t container_file_t " + str(downloads_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "podman unshare chown -R 1000:1000 " + str(config_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "podman unshare chown -R 1000:1000 " + str(watch_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) command_text = "podman unshare chown -R 1000:1000 " + str(downloads_dir) subprocess.run( command_text, text=True, shell=True, check=True, ) # read package file # https://stackoverflow.com/a/20885799/1904901 # To access a file inside the current module, set the package argument to __package__, yaml_template = pkg_resources.read_text( __package__, "transmission-kube-template.yml" ) # populate template with proper entries: usnmae = get_user_input("Enter transmission username:") yaml_template = yaml_template.replace("$SET_USER", usnmae) password = get_user_input("Enter transmission password:") yaml_template = yaml_template.replace("$SET_PASSWD", password) yaml_template = yaml_template.replace("$LOCAL_USER", self.username) # write kubernetes template kube_yaml_path = self.main_path.joinpath("transmission-kube.yml") kube_yaml_path.write_text(yaml_template) subprocess.run( "podman play kube " + str(kube_yaml_path), text=True, shell=True, check=True, ) # open necessary firewall port # sudo firewall-cmd --permanent --add-port=9091/tcp # There is a bug in Fedora IoT that requires this command to be run under sudo # Fedora docs for handling firewalld commands: # https://docs.fedoraproject.org/en-US/quick-docs/firewalld/ subprocess.run( "sudo firewall-cmd --permanent --add-port=9091/tcp", text=True, shell=True, check=True, )
# I don't like sudo been required but until there's a fix :(
[docs] def stop(self): """ Stop transmission pod """ subprocess.run( "podman pod stop transmission", text=True, shell=True, check=True, )
[docs] def rm(self): """ Delete transmission pod. """ subprocess.run( "podman pod rm transmission", text=True, shell=True, check=True, )
[docs] def start(self): """ Start transmission pod. """ subprocess.run( "podman pod start transmission", text=True, shell=True, check=True, )
[docs] def check_if_new_version_is_available(self) -> bool: """ Check if there is a new version of the transmission docker image from linuxserver io. """ deployed_image_check = subprocess.run( """podman inspect -f '{{ index .Config.Labels "build_version" }}' transmission-main""", text=True, shell=True, check=True, capture_output=True, ) print(f"deployed image version is:\n{deployed_image_check.stdout}") self.pull_latest_transmission_image() remote_image_check = subprocess.run( """podman inspect -f '{{ index .Config.Labels "build_version" }}' ghcr.io/linuxserver/transmission""", # noqa: E501 text=True, shell=True, check=True, capture_output=True, ) print(f"remote image version is:\n{remote_image_check.stdout}") return not deployed_image_check.stdout == remote_image_check.stdout
[docs] def update_running_image(self): """ Checks if a new image is available and if so, rebuilds the container. """ to_update = self.check_if_new_version_is_available() if to_update: self.stop() self.rm() kube_yaml_path = self.main_path.joinpath("transmission-kube.yml") subprocess.run( "podman play kube " + str(kube_yaml_path), text=True, shell=True, check=True, ) print("Deployed new image!") else: print("Current image is latest available")