Python Forum
a class that gets available, running, and stopped services (Ubuntu/Debian)
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
a class that gets available, running, and stopped services (Ubuntu/Debian)
#1
#! /usr/bin/python3
import os


class ServiceReport:
    def __init__(self):
        self.services = []
        self.all_services = []
        self.stopped_services = []
        self.running_services = []
        self.srvc_cmd = "service --status-all &> /dev/null"
        self.set_services()
        self.extract_services()

    def set_services(self):
        self.services = os.popen(self.srvc_cmd)

    def get_all_services(self):
        return self.all_services

    def get_running_services(self):
        return self.running_services

    def get_stopped_services(self):
        return self.stopped_services

    def running_services_count(self):
        return len(self.running_services)

    def stopped_services_count(self):
        return len(self.stopped_services)

    def all_services_count(self):
        return len(self.all_services)

    def extract_services(self):
        for service in sorted(self.services):
            self.all_services.append(service[8:-1])
            if "+" in service:
                self.running_services.append(service[8:-1])
            else:
                self.stopped_services.append(service[8:-1])


if __name__ == "__main__":
    sr = ServiceReport()
    print("\n" + str(sr.all_services_count()) + " services are available")
    for x in sr.get_all_services():
        print(x)
    print("\n" + str(sr.running_services_count()) + " services are running")
    for y in sr.get_running_services():
        print(y)
    print("\n" + str(sr.stopped_services_count()) + " services are stopped")
    for z in sr.get_stopped_services():
print(z)
Reply
#2
I would rather return a sequence of small Service objects for such a program, because Python is very strong at manipulating collections and I think it opens more flexible possibilities. Here is a proposal
from collections import namedtuple
import os

class Service(namedtuple('Service', 'name status')):
    __slots__ = ()
    def is_running(self):
        return self.status == '+'
    def is_stopped(self):
        return self.status == '-'
    def has_no_status(self):
        return self.status == '?'

def service_status_all():
    for line in os.popen("service --status-all &> /dev/null"):
        _, status, _, name = line.strip().split()
        yield Service(name, status)
        
if __name__ == '__main__':
    services = list(service_status_all())
    print("{} services are available".format(len(services)))
    for x in services:
        print(x.name)
    running = [s for s in services if s.is_running()]
    print()
    print("{} services are running".format(len(running)))
    for y in running:
        print(y.name)
    stopped = [s for s in services if s.is_stopped()]
    print()
    print("{} services are stopped".format(len(stopped)))
    for y in stopped:
        print(y.name)
Reply
#3
Ah I like the yield keyword. I actually attempted to use that as the service command seems to gradually output the services. I couldn’t get it to work. I’m glad you posted that to see how to return an iterator correctly
Reply
#4
Just out of curiosity... I noticed that you used the "?" in case of no status... does the output of service --status-all on your machine give a service/status that does not have a [+] or a [-]?
Reply
#5
(Aug-26-2018, 01:32 AM)rootVIII Wrote: does the output of service --status-all on your machine give a service/status that does not have a [+] or a [-]?
They all have [ + ] or [ - ], however man service indicates

Quote: service --status-all runs all init scripts, in alphabetical order, with the status
command. The status is [ + ] for running services, [ - ] for stopped services and
[ ? ] for services without a 'status' command. This option only calls status for
sysvinit jobs; upstart jobs can be queried in a similar manner with initctl list.

It could be a good idea to parse more seriously the lines of output in case the syntax of service --status-all changes. The re module can be used for this. Also the command can be made a classmethod of the Service class, which would allow further code to subclass the Service class

from collections import namedtuple
import os
import re

class Service(namedtuple('Service', 'name status')):
    __slots__ = ()
    def is_running(self):
        return self.status == '+'
    def is_stopped(self):
        return self.status == '-'
    def has_no_status(self):
        return self.status == '?'

    @classmethod
    def iterate_all(cls):
        for line in os.popen("service --status-all &> /dev/null"):
            match = re.match(
                r"\[\s*(?P<status>[-+?])\s*\]\s*(?P<name>[^\s].+)", line.strip())
            if not match:
                raise ValueError(('Unknown service status syntax:', line))
            yield cls(match.group('name'), match.group('status'))

if __name__ == '__main__':
    for service in Service.iterate_all():
        print(service)
Reply
#6
Yes thank you:)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  A torsocks DDOS tool for Debian Linux Distros: python + wget + tor rootVIII 0 2,368 Jun-09-2019, 09:53 AM
Last Post: rootVIII
  A small/simple class for running nslookup on a list of domain names rootVIII 1 3,517 Apr-17-2019, 04:49 AM
Last Post: rootVIII

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020