diff --git a/bundles/uberspace-supervisord/items.py b/bundles/uberspace-supervisord/items.py new file mode 100644 index 0000000..9b923d4 --- /dev/null +++ b/bundles/uberspace-supervisord/items.py @@ -0,0 +1,18 @@ +uberspaceify = repo.libs.uberspace.Uberspaceify(node) + +directories = uberspaceify.directories({ + f'/home/{node.username}/etc/services.d': { + "purge": True, + "triggers": [ + "action:supervisord-reread", + ], + }, +}) + +actions["supervisord-reread"] = { + "command": "supervisorctl reread", + "triggered": True, + "needed_by": [ + "svc_uberspace_supervisord:", + ], +} diff --git a/items/svc_uberspace_supervisord.py b/items/svc_uberspace_supervisord.py new file mode 100644 index 0000000..4452a2b --- /dev/null +++ b/items/svc_uberspace_supervisord.py @@ -0,0 +1,80 @@ +from shlex import quote + +from bundlewrap.exceptions import BundleError +from bundlewrap.items import Item + + +def svc_start(node, svcname): + return node.run("supervisorctl start {}".format(quote(svcname)), may_fail=True) + +def svc_running(node, svcname): + result = node.run("supervisorctl status {}".format(quote(svcname)), may_fail=True) + return result.return_code == 0 + +def svc_stop(node, svcname): + return node.run("supervisorctl stop {}".format(quote(svcname)), may_fail=True) + + +class SvcSystemd(Item): + """ + A service managed by supervisord in uberspace. + """ + BUNDLE_ATTRIBUTE_NAME = "svc_uberspace_supervisord" + ITEM_ATTRIBUTES = { + 'running': True, + } + ITEM_TYPE_NAME = "svc_uberspace_supervisord" + + def __repr__(self): + return "".format( + self.name, + self.attributes['running'], + ) + + def cdict(self): + cdict = {} + for option, value in self.attributes.items(): + if value is not None: + cdict[option] = value + return cdict + + def fix(self, status): + if 'running' in status.keys_to_fix: + if self.attributes['running']: + svc_start(self.node, self.name) + else: + svc_stop(self.node, self.name) + + def get_canned_actions(self): + return { + 'stop': { + 'command': "supervisorctl stop {}".format(self.name), + 'needed_by': {self.id}, + }, + 'restart': { + 'command': "supervisorctl restart {}".format(self.name), + 'needs': {self.id}, + }, + 'update': { + 'command': "supervisorctl update {}".format(self.name), + 'needs': {self.id}, + }, + } + + def sdict(self): + return { + 'running': svc_running(self.node, self.name), + } + + @classmethod + def validate_attributes(cls, bundle, item_id, attributes): + for attribute in ('running'): + if attributes.get(attribute, None) not in (True, False, None): + raise BundleError(_( + "expected boolean or None for '{attribute}' on {item} in bundle '{bundle}'" + ).format( + attribute=attribute, + bundle=bundle.name, + item=item_id, + )) +