refactor: Add Deployer base class

- Added a Deployer class that defines the base for objects that will
  handle installation of individual components, with install,
  configure, and activate stages.  Subclasses will override the
  implementation methods of those stages as needed, while the base
  class handles all the logic of deciding which stages to execute.
- The CMDEPLOY_STAGES environment variable is used to determine what
  stages to run.  If this is not defined, all stages run as usual.
- Added import of Deployer to cmdeploy/__init__.py.  This is not yet
  used, but the next series of commits will use it.
- In deploy_chatmail(), define an empty list of deployers, and call
  the create_groups() and create_users() methods for the items in the
  list.  This list will get filled with Deployer objects in the next
  series of commits.
This commit is contained in:
cliffmccarthy
2025-09-09 11:39:55 -05:00
parent 39fd04473c
commit ffcd657a88
2 changed files with 94 additions and 0 deletions

View File

@@ -20,6 +20,7 @@ from pyinfra.facts.systemd import SystemdEnabled
from pyinfra.operations import apt, files, pip, server, systemd
from .acmetool import deploy_acmetool
from .deployer import Deployer
from .www import build_webpages, find_merge_conflict, get_paths
@@ -690,6 +691,19 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
line="nameserver 9.9.9.9",
)
all_deployers = [
]
#
# Create all groups before users, because some users reference groups
# from other classes.
#
for deployer in all_deployers:
deployer.create_groups()
for deployer in all_deployers:
deployer.create_users()
server.group(name="Create vmail group", group="vmail", system=True)
server.user(name="Create vmail user", user="vmail", group="vmail", system=True)
server.group(name="Create opendkim group", group="opendkim", system=True)

View File

@@ -0,0 +1,80 @@
import os
from pyinfra.operations import server
class Deployer:
def __init__(self, **kwargs):
super().__init__(**kwargs)
default_stages = "install,configure,activate"
stages = os.getenv("CMDEPLOY_STAGES", default_stages).split(",")
self.run_install = "install" in stages
self.run_configure = "configure" in stages
self.run_activate = "activate" in stages
self.need_restart = False
#
# In any override, this method should return a list of 3-element
# (user, group, secondary-group-list) tuples. If the group is None,
# no group is created corresponding to that user. If the secondary
# group list is not None, the listed groups are created as well.
#
@staticmethod
def required_users():
return []
def create_groups(self):
if not self.run_install:
return
for user, group, groups in self.required_users():
if group is not None:
server.group(
name="Create {} group".format(group), group=group, system=True
)
if groups is not None:
for group2 in groups:
server.group(
name="Create {} group".format(group2), group=group2, system=True
)
def create_users(self):
if not self.run_install:
return
for user, group, groups in self.required_users():
server.user(
name="Create {} user".format(user),
user=user,
group=group,
groups=groups,
system=True,
)
def install(self):
if self.run_install:
self.need_restart |= bool(self.install_impl())
#
# If a subclass overrides this with a method that returns a true
# value, self.need_restart will be set when install() is called.
#
@staticmethod
def install_impl():
pass
def configure(self):
if self.run_configure:
self.configure_impl()
def configure_impl(self):
pass
def activate(self):
if self.run_activate:
self.activate_impl()
def activate_impl(self):
pass