def start_transient_unit(cmd="/bin/sleep 15", delay_in_seconds=5):
    a_cmd = [c.encode() for c in shlex.split(cmd)]

    random_unit_name = "myservice.{r}.{t}".format(r=random.randint(0, 100),
                                                  t=time.time())

    timer_unit_name = "{}.timer".format(random_unit_name).encode()
    service_unit_name = "{}.service".format(random_unit_name).encode()

    timer_unit_properties = {
        b"Description": b"Example of transient timer unit",
        b"TimersMonotonic": [(b"OnBootSec", delay_in_seconds * 1000000)],
        b"RemainAfterElapse": False,
    }

    service_unit_properties = {
        b"Description": b"Example of transient unit",
        b"ExecStart": [(a_cmd[0], a_cmd, False)],
        b"RemainAfterExit": True,
    }

    with Manager() as manager:
        manager.Manager.StartTransientUnit(
            timer_unit_name,
            b"fail",
            timer_unit_properties,
            [(service_unit_name, service_unit_properties)],
        )
    print("started {} as timer and service".format(random_unit_name))
Example #2
0
def start_transient_unit(cmd='/bin/sleep 15'):
    a_cmd = [c.encode() for c in shlex.split(cmd)]
    random_unit_name = 'myservice.{r}.{t}.service'.format(
        r=random.randint(0, 100), t=time.time()).encode()

    unit = {
        b'Description': b'Example of transient unit',
        b'ExecStart': [(a_cmd[0], a_cmd, False)],
        b'RemainAfterExit': True}

    with Manager() as manager:
        manager.Manager.StartTransientUnit(
            random_unit_name, b'fail', unit)

    with Unit(random_unit_name) as unit:
        while True:
            print(
                'service `{cmd}` (name={random_unit_name}) has MainPID '
                '{unit.Service.MainPID}'.format(**locals()))
            if unit.Service.MainPID == 0:
                print(
                    'service finished with '
                    '{unit.Service.ExecMainStatus}/{unit.Service.Result} '
                    'will stop it and then... bye'.format(**locals()))
                unit.Unit.Stop(b'replace')
                break
            print('service still runing, sleeping by 5 seconds')
            time.sleep(5)
 def read_services_dbus(self):
     services = {}
     with Manager() as manager:
         for _unit in manager.Manager.ListUnits():
             idx = _unit[0].find(b"maverick-")
             if idx == -1:
                 continue
             service_name = _unit[0][9:-8].decode()
             category = None
             if "@" in service_name:
                 category = service_name.split("@")[-1].strip()
             unit = Unit(_unit[0])
             services[unit.path] = {
                 "unit": unit,
                 "path": unit.path,
                 "category_name": category,
                 "category_display_name": category,
                 "command": _unit[0][0:-8].decode(),
                 "service_name": _unit[0][9:-8].decode(),
                 "service_display_name": _unit[1].decode(),
                 "last_update": int(time.time()),
                 "enabled": None,
                 "running": True if _unit[4] == b"running" else False,
             }
     for service in services:
         application_log.debug(f"Adding service: {services[service]}")
     return services
Example #4
0
def start_transient_unit(cmd="/bin/sleep 15"):
    a_cmd = [c.encode() for c in shlex.split(cmd)]
    random_unit_name = "myservice.{r}.{t}.service".format(
        r=random.randint(0, 100), t=time.time()).encode()

    unit = {
        b"Description": b"Example of transient unit",
        b"ExecStart": [(a_cmd[0], a_cmd, False)],
        b"RemainAfterExit": True,
    }

    with Manager() as manager:
        manager.Manager.StartTransientUnit(random_unit_name, b"fail", unit)

    with Unit(random_unit_name) as unit:
        while True:
            print("service `{cmd}` (name={random_unit_name}) has MainPID "
                  "{unit.Service.MainPID}".format(**locals()))
            if unit.Service.MainPID == 0:
                print("service finished with "
                      "{unit.Service.ExecMainStatus}/{unit.Service.Result} "
                      "will stop it and then... bye".format(**locals()))
                unit.Unit.Stop(b"replace")
                break
            print("service still runing, sleeping by 5 seconds")
            time.sleep(5)
def start_transient_unit(cmd="/bin/sleep 15"):
    a_cmd = [c.encode() for c in shlex.split(cmd)]
    random_unit_name = "myservice.{r}.{t}.service".format(
        r=random.randint(0, 100), t=time.time()).encode()

    unit = {
        b"Description": b"Example of transient unit",
        b"ExecStart": [(a_cmd[0], a_cmd, False)],
        b"RemainAfterExit": True,
    }
    # if we need interactive prompts for passwords, we can create our own DBus object.
    # if we dont need interactive, we would just do `with Manager() as manager:`.
    with DBus(interactive=True) as bus, Manager(bus=bus) as manager:
        manager.Manager.StartTransientUnit(random_unit_name, b"fail", unit)

        with Unit(random_unit_name, bus=bus) as unit:
            while True:
                print("service `{cmd}` (name={random_unit_name}) has MainPID "
                      "{unit.Service.MainPID}".format(**locals()))
                if unit.Service.MainPID == 0:
                    print(
                        "service finished with "
                        "{unit.Service.ExecMainStatus}/{unit.Service.Result} "
                        "will stop it and then... bye".format(**locals()))
                    unit.Unit.Stop(b"replace")
                    break
                print("service still running, sleeping by 5 seconds")
                time.sleep(5)
Example #6
0
class ServiceController(object):
    """
        A simple wrapper around pystemd to manage systemd services
    """

    manager = Manager(_autoload=True)

    def __init__(self, unit):
        """
            param: unit: a systemd unit name (ie str2str_tcp.service...)
        """
        self.unit = Unit(bytes(unit, 'utf-8'), _autoload=True)

    def isActive(self):
        if self.unit.Unit.ActiveState == b'active':
            return True
        elif self.unit.Unit.ActiveState == b'activating':
            #TODO manage this transitionnal state differently
            return True
        else:
            return False

    def get_nrestart(self):
        """
            Get the number of restarts since the last service startup
        """
        return self.unit.Service.NRestarts

    def get_result(self):
        """
            Get the service return status.
            success => it's ok
            exit-code => str2str doesn't start successfully
            We can read a success between the startup and the first error
        """
        return self.unit.Service.Result.decode()

    def getUser(self):
        return self.unit.Service.User.decode()

    def status(self):
        """
            get the unit status:
            auto-restart: the service will restart later
            start: the service is starting
            running; the service is running
        """
        return (self.unit.Unit.SubState).decode()

    def start(self):
        self.manager.Manager.EnableUnitFiles(self.unit.Unit.Names, False, True)
        return self.unit.Unit.Start(b'replace')

    def stop(self):
        self.manager.Manager.DisableUnitFiles(self.unit.Unit.Names, False)
        return self.unit.Unit.Stop(b'replace')

    def restart(self):
        return self.unit.Unit.Restart(b'replace')
Example #7
0
def list_units():
    with Manager() as manager:
        print("Version", manager.Manager.Version)
        print("Architecture", manager.Manager.Architecture)

        # List Units
        for unit, state in manager.Manager.ListUnitFiles():
            print("    {} is {}".format(unit, state))
def start_webserver(listen_stream="0.0.0.0:7042",):
    a_cmd = [
        "/usr/bin/python3",
        "-c",
        textwrap.dedent(
            """
            import socket

            with socket.fromfd(3, socket.AF_INET, socket.SOCK_STREAM) as s:
                conn, addr = s.accept()
                with conn:
                    print(f"got connection from {addr}")
                    while True:
                        data = conn.recv(1024)
                        if not data: break
                        print(data)
                        conn.sendall(data)
            """
        ),
    ]

    random_unit_name = "myservice.{r}.{t}".format(
        r=random.randint(0, 100), t=time.time()
    )

    socket_unit_name = "{}.socket".format(random_unit_name).encode()
    service_unit_name = "{}.service".format(random_unit_name).encode()

    socket_unit_properties = {
        b"Description": b"Example of transient socket unit",
        b"Listen": [("Stream", listen_stream)],
    }

    service_unit_properties = {
        b"Description": b"Example of transient unit",
        b"ExecStart": [(a_cmd[0], a_cmd, False)],
        b"RemainAfterExit": True,
    }

    with Manager() as manager:
        manager.Manager.StartTransientUnit(
            socket_unit_name,
            b"fail",
            socket_unit_properties,
            [(service_unit_name, service_unit_properties)],
        )
    print("started {} as socket and service".format(random_unit_name))
Example #9
0
def set_persistence(unit: Unit, enable: bool = True) -> None:
    """Set the Persistence of a systemd Unit.

    Args:
        unit (Unit): A systemd Unit object, already loaded.
        enable (bool, optional): Wether to enable or disable the Unit. Defaults to True.
    """
    with Manager() as mgr, perms.run_as(0, 0):
        if enable:
            # Enable Unit file named "x.service", not in runtime (persistently), and force
            link = mgr.Manager.EnableUnitFiles([unit.Unit.Id], False, True)[1]
            if link:
                print(f"Linked Unit: '{link[0][1].decode()}'.")
            else:
                raise ValueError("Unit already linked")
        else:
            link = mgr.Manager.DisableUnitFiles([unit.Unit.Id], False)
            if link:
                print(f"Unlinked Unit: '{link[0][1].decode()}'.")
            else:
                raise ValueError("Unit already unlinked")
Example #10
0
class ServiceController(object):
    """
        A simple wrapper around pystemd to manage systemd services
    """
    
    manager = Manager(_autoload=True)

    def __init__(self, unit):
        """
            param: unit: a systemd unit name (ie str2str_tcp.service...)
        """
        self.unit = Unit(bytes(unit, 'utf-8'), _autoload=True)
        
    def isActive(self):
        if self.unit.Unit.ActiveState == b'active':
            return True
        elif self.unit.Unit.ActiveState == b'activating':
            #TODO manage this transitionnal state differently
            return True
        else:
            return False

    def getUser(self):
        return self.unit.Service.User.decode()
    
    def status(self):
        return (self.unit.Unit.SubState).decode()

    def start(self):
        self.manager.Manager.EnableUnitFiles(self.unit.Unit.Names, False, True)
        return self.unit.Unit.Start(b'replace')
        
    def stop(self):
        self.manager.Manager.DisableUnitFiles(self.unit.Unit.Names, False)
        return self.unit.Unit.Stop(b'replace')
        
    def restart(self):
        return self.unit.Unit.Restart(b'replace')
Example #11
0
class McUnit:
    """
    A class to represent a Unit of the minecraft service.
    The factory function discover_units expects to find installations of
    Minecraft Server in folders under /home/minecraft/MinecraftServers
    and returns a list of McUnit
    """

    repr_format = "{:3.2s}{:20.19s}{:11.10s}{:8.7s}{:9.8s}{:10.9s}{:15.14s}{:4.4s}"
    heading = repr_format.format("No", "Name", "State", "SubSt", "Auto Start",
                                 "GameMode", "World", "Wlds")
    config_name = "server.properties"

    # keep a dbus and a manager for the lifetime of the class/app
    dbus = DBus(user_mode=True)
    dbus.open()
    manager = Manager(bus=dbus)
    manager.load()

    def __init__(self, name, unit, unit_name, num):
        self.name = name
        self.unit = unit
        self.unit_name = unit_name
        self.num = num
        self.config_path = Config.mc_root / name / self.config_name

        self.properties = Properties(self.config_path)
        self.properties.read()
        self.world = self.properties["level-name"]
        self.mode = self.properties["gamemode"]

        self.worlds = [
            f.name for f in (Config.mc_root / name).iterdir()
            if f.name not in Config.non_worlds and f.is_dir()
        ]

    @classmethod
    def discover_units(cls):
        # factory function that queries systemd files and returns a list
        # of McUints (1 systemd unit per Minecraft installation)
        mc_installs = list(Config.mc_root.glob("*"))
        mc_names = [
            str(mc.name) for mc in mc_installs
            if not str(mc.name).startswith(".")
        ]
        units = []

        for i, mc_name in enumerate(mc_names):
            unit_name = Config.unit_name_format.format(mc_name)
            unit = Unit(unit_name.encode("utf8"), bus=cls.dbus)
            unit.load()
            units.append(McUnit(mc_name, unit, unit_name, i))

        return units

    def __repr__(self):
        state = self.unit.Unit.ActiveState.decode("utf8")
        sub_state = self.unit.Unit.SubState.decode("utf8")
        enabled = self.manager.Manager.GetUnitFileState(
            self.unit_name).decode()
        return self.repr_format.format(str(self.num), self.name, state,
                                       sub_state, enabled, self.mode,
                                       self.world, str(len(self.worlds)))

    def get_world_path(self, world_num):
        if not len(self.worlds) >= world_num >= 0:
            raise ValueError(f"world number {world_num} does not exist")
        return Config.mc_root / self.name / self.worlds[world_num]

    def set_world(self, world_num):
        self.properties.read()
        if not len(self.worlds) >= world_num >= 0:
            raise ValueError(f"world number {world_num} does not exist")

        self.properties["level-name"] = self.worlds[world_num]
        self.properties.write()
        self.world = self.worlds[world_num]

    def start(self):
        print(f"Starting {self.name} ...")
        self.unit.Start(b"replace")

    def stop(self):
        print(f"Stopping {self.name} ...")
        self.unit.Stop(b"replace")

        # wait for the service to complete termination
        while self.running:
            sleep(.2)

    def restart(self):
        # unit.Restart does not work for some reason
        self.stop()
        self.start()

    def enable(self):
        self.manager.Manager.EnableUnitFiles([self.unit_name], False, False)

    def disable(self):
        self.manager.Manager.DisableUnitFiles([self.unit_name], False)

    def console(self):
        cmd = Config.screen_cmd_format.format(self.name)
        os.system(cmd)

    @property
    def running(self):
        state = self.unit.Unit.ActiveState.decode("utf8")
        return state != "inactive"

    actions = {
        "s": start,
        "k": stop,
        "e": enable,
        "d": disable,
        "r": restart,
        "c": console,
    }