mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-28 08:03:36 +00:00
265 lines
8.9 KiB
Python
Executable File
265 lines
8.9 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# -*- mode: python -*-
|
|
#
|
|
# This file is part of Plinth.
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
"""
|
|
Configuration helper for Plinth PageKite interface.
|
|
"""
|
|
|
|
import argparse
|
|
import augeas
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
from plinth import action_utils
|
|
from plinth.modules.pagekite import utils
|
|
|
|
aug = None
|
|
|
|
PATHS = {
|
|
'service_on': os.path.join(utils.CONF_PATH, '*', 'service_on', '*'),
|
|
'kitename': os.path.join(utils.CONF_PATH, '10_account.rc', 'kitename'),
|
|
'kitesecret': os.path.join(utils.CONF_PATH, '10_account.rc', 'kitesecret'),
|
|
'abort_not_configured': os.path.join(utils.CONF_PATH, '10_account.rc',
|
|
'abort_not_configured'),
|
|
'defaults': os.path.join(utils.CONF_PATH, '20_frontends.rc', 'defaults'),
|
|
'frontend': os.path.join(utils.CONF_PATH, '20_frontends.rc', 'frontend'),
|
|
}
|
|
|
|
|
|
def parse_arguments():
|
|
"""Return parsed command line arguments as dictionary"""
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
|
|
|
|
# Enable/disable the pagekite service
|
|
subparsers.add_parser('start-and-enable', help='Enable PageKite service')
|
|
subparsers.add_parser('stop-and-disable', help='Disable PageKite service')
|
|
subparsers.add_parser('restart', help='Restart PageKite service')
|
|
subparsers.add_parser('is-disabled',
|
|
help=('Whether PageKite is disabled in the file '
|
|
'/etc/pagekite.d/10_accounts.rc'))
|
|
|
|
# Frontend
|
|
subparsers.add_parser('get-frontend', help='Get pagekite frontend')
|
|
set_frontend = subparsers.add_parser('set-frontend',
|
|
help='Set pagekite frontend')
|
|
set_frontend.add_argument('url', help='frontend url')
|
|
|
|
# Kite details (name + secret)
|
|
subparsers.add_parser('get-kite',
|
|
help='Get configured kite name and secret')
|
|
set_kite = subparsers.add_parser(
|
|
'set-kite',
|
|
help='Configure kite name and its secret. Secret is read from stdin.')
|
|
set_kite.add_argument('--kite-name',
|
|
help='Name of the kite (eg: mybox.pagekite.me)')
|
|
|
|
# Add/remove pagekite services (service_on entries)
|
|
subparsers.add_parser('get-services', help='Get list of enabled services')
|
|
add_service = subparsers.add_parser('add-service',
|
|
help='Add a pagekite service')
|
|
add_service.add_argument('--service', help='json service dictionary')
|
|
remove_service = subparsers.add_parser('remove-service',
|
|
help='Remove a pagekite service')
|
|
remove_service.add_argument('--service', help='json service dictionary')
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def subcommand_restart(_):
|
|
"""Restart the pagekite service"""
|
|
action_utils.service_restart('pagekite')
|
|
print('restarted')
|
|
|
|
|
|
def subcommand_is_disabled(_):
|
|
if aug.match(PATHS['abort_not_configured']):
|
|
print('true')
|
|
else:
|
|
print('false')
|
|
|
|
|
|
def subcommand_start_and_enable(_):
|
|
aug.remove(PATHS['abort_not_configured'])
|
|
aug.save()
|
|
# 'start' alone sometimes fails, even if the service is not running
|
|
action_utils.service_restart('pagekite')
|
|
print('enabled')
|
|
|
|
|
|
def subcommand_stop_and_disable(_):
|
|
action_utils.service_stop('pagekite')
|
|
aug.set(PATHS['abort_not_configured'], '')
|
|
aug.save()
|
|
print('disabled')
|
|
|
|
|
|
def subcommand_get_frontend(_):
|
|
"""Get pagekite frontend url"""
|
|
if aug.match(PATHS['defaults']):
|
|
print("pagekite.net")
|
|
else:
|
|
url = aug.get(PATHS['frontend'])
|
|
print(url or '')
|
|
|
|
|
|
def subcommand_set_frontend(arguments):
|
|
"""Set pagekite frontend url, taking care of defaults and pagekite.net"""
|
|
frontend_domain = arguments.url.split(':')[0]
|
|
if frontend_domain in ('pagekite.net', 'defaults', 'default'):
|
|
enable_pagekitenet_frontend()
|
|
else:
|
|
aug.remove(PATHS['defaults'])
|
|
aug.set(PATHS['frontend'], arguments.url)
|
|
aug.save()
|
|
|
|
|
|
def enable_pagekitenet_frontend():
|
|
"""Enable using default pageket.net frontend
|
|
|
|
This disables any other frontends.
|
|
"""
|
|
aug.set(PATHS['defaults'], '')
|
|
aug.remove(PATHS['frontend'])
|
|
aug.save()
|
|
print("enabled")
|
|
|
|
|
|
def subcommand_get_services(arguments):
|
|
""" lists all available (enabled) services """
|
|
for match in aug.match(PATHS['service_on']):
|
|
service = dict([(param, aug.get(os.path.join(match, param)))
|
|
for param in utils.SERVICE_PARAMS])
|
|
print(json.dumps(service))
|
|
|
|
|
|
def subcommand_remove_service(arguments):
|
|
"""Searches and removes the service(s) that match all given parameters"""
|
|
service = utils.load_service(arguments.service)
|
|
paths = get_existing_service_paths(service)
|
|
# TODO: theoretically, everything to do here is:
|
|
# [aug.remove(path) for path in paths]
|
|
# but augeas won't let you save the changed files and doesn't say why
|
|
for path in paths:
|
|
filepath = convert_augeas_path_to_filepath(path)
|
|
service_found = False
|
|
with open(filepath, 'r') as file:
|
|
lines = file.readlines()
|
|
for i, line in enumerate(lines):
|
|
if line.startswith('service_on') and \
|
|
all(param in line for param in service.values()):
|
|
lines[i] = ""
|
|
service_found = True
|
|
break
|
|
if service_found:
|
|
with open(filepath, 'w') as file:
|
|
file.writelines(lines)
|
|
# abort to only allow deleting one service
|
|
break
|
|
action_utils.service_restart('pagekite')
|
|
|
|
|
|
def get_existing_service_paths(service):
|
|
"""Return paths of existing services that match the given service params"""
|
|
# construct an augeas query path with patterns like:
|
|
# */service_on/*[protocol='http']
|
|
path = PATHS['service_on']
|
|
for param, value in service.items():
|
|
path += "[%s='%s']" % (param, value)
|
|
return aug.match(path)
|
|
|
|
|
|
def subcommand_add_service(arguments):
|
|
"""Add one service"""
|
|
service = utils.load_service(arguments.service)
|
|
if get_existing_service_paths(service):
|
|
msg = "Service with the parameters %s already exists"
|
|
raise RuntimeError(msg % service)
|
|
|
|
root = get_new_service_path(service['protocol'])
|
|
# TODO: after adding a service, augeas fails writing the config;
|
|
# so add the service_on entry manually instead
|
|
path = convert_augeas_path_to_filepath(root)
|
|
with open(path, 'a') as servicefile:
|
|
line = "\nservice_on = %s\n" % utils.convert_service_to_string(service)
|
|
servicefile.write(line)
|
|
action_utils.service_restart('pagekite')
|
|
|
|
|
|
def convert_augeas_path_to_filepath(augpath, prefix='/files',
|
|
suffix='service_on'):
|
|
"""Convert an augeas service_on path to the actual file path"""
|
|
if augpath.startswith(prefix):
|
|
augpath = augpath.replace(prefix, "", 1)
|
|
|
|
index = augpath.rfind(suffix)
|
|
if index:
|
|
augpath = augpath[:index]
|
|
return augpath.rstrip('/')
|
|
|
|
|
|
def get_new_service_path(protocol):
|
|
"""Get the augeas path of a new service for a protocol
|
|
|
|
This takes care of existing services using a /service_on/*/ query"""
|
|
root = utils.get_augeas_servicefile_path(protocol)
|
|
new_index = len(aug.match(root + '/*')) + 1
|
|
return os.path.join(root, str(new_index))
|
|
|
|
|
|
def subcommand_get_kite(_):
|
|
"""Print details of the currently configured kite"""
|
|
kitename = aug.get(PATHS['kitename'])
|
|
kitesecret = aug.get(PATHS['kitesecret'])
|
|
print(kitename or '')
|
|
print(kitesecret or '')
|
|
|
|
|
|
def subcommand_set_kite(arguments):
|
|
"""Set details of the kite"""
|
|
aug.set(PATHS['kitename'], arguments.kite_name)
|
|
aug.set(PATHS['kitesecret'], sys.stdin.read())
|
|
aug.save()
|
|
|
|
|
|
def augeas_load():
|
|
"""Initialize Augeas."""
|
|
global aug
|
|
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
|
|
augeas.Augeas.NO_MODL_AUTOLOAD)
|
|
aug.set('/augeas/load/Pagekite/lens', 'Pagekite.lns')
|
|
aug.set('/augeas/load/Pagekite/incl[last() + 1]', '/etc/pagekite.d/*.rc')
|
|
aug.load()
|
|
|
|
|
|
def main():
|
|
"""Parse arguments and perform all duties"""
|
|
augeas_load()
|
|
|
|
arguments = parse_arguments()
|
|
|
|
subcommand = arguments.subcommand.replace('-', '_')
|
|
subcommand_method = globals()['subcommand_' + subcommand]
|
|
subcommand_method(arguments)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|