Add upgrades module that can run unattended-upgrades.

This commit is contained in:
James Valleroy 2015-01-19 22:41:37 -05:00 committed by fonfon
parent c72c03890c
commit 80eff7fd6e
7 changed files with 298 additions and 0 deletions

111
actions/upgrades Executable file
View File

@ -0,0 +1,111 @@
#!/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/>.
#
"""
Configures or runs unattended-upgrades
"""
import argparse
import os
import subprocess
CONF_FILE = '/etc/apt/apt.conf.d/50unattended-upgrades'
AUTO_CONF_FILE = '/etc/apt/apt.conf.d/20auto-upgrades'
def parse_arguments():
"""REturn parsed command line arguments as dictionary"""
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
# Run unattended-upgrades
subparsers.add_parser('run', help='Upgrade packages on the system')
# Enable automatic upgrades
subparsers.add_parser('enable-auto', help='Enable automatic upgrades')
# Disable automatic upgrades
subparsers.add_parser('disable-auto', help='Disable automatic upgrades.')
return parser.parse_args()
def subcommand_run(_):
"""Run unattended-upgrades"""
try:
setup()
except FileNotFoundError:
print('Error: Could not configure unattended-upgrades.')
return
try:
output = subprocess.check_output(['unattended-upgrades', '-v'])
except subprocess.CalledProcessError as error:
print('Error: %s', error)
except FileNotFoundError:
print('Error: unattended-upgrades is not available.')
else:
print('%s', output.decode())
def subcommand_enable_auto(_):
"""Enable automatic upgrades"""
try:
setup()
except FileNotFoundError:
print('Error: Could not configure unattended-upgrades.')
return
with open(AUTO_CONF_FILE, 'w') as conffile:
conffile.write('APT::Periodic::Update-Package-Lists "1";\n')
conffile.write('APT::Periodic::Unattended-Upgrade "1";\n')
def subcommand_disable_auto(_):
"""Disable automatic upgrades"""
os.remove(AUTO_CONF_FILE)
def setup():
"""Sets unattended-upgrades config to upgrade any package from Debian."""
with open(CONF_FILE, 'r') as conffile:
lines = conffile.readlines()
for line in lines:
if '"origin=Debian";' in line:
return # already configured
with open(CONF_FILE, 'w') as conffile:
for line in lines:
conffile.write(line)
if 'Unattended-Upgrade::Origins-Pattern {' in line:
conffile.write(' "origin=Debian";\n')
def main():
"""Parse arguments and perform all duties"""
arguments = parse_arguments()
subcommand = arguments.subcommand.replace('-', '_')
subcommand_method = globals()['subcommand_' + subcommand]
subcommand_method(arguments)
if __name__ == '__main__':
main()

View File

@ -0,0 +1 @@
plinth.modules.upgrades

View File

@ -0,0 +1,27 @@
#
# 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/>.
#
"""
Plinth module for upgrades
"""
from . import upgrades
from .upgrades import init
__all__ = ['upgrades', 'init']
depends = ['plinth.modules.system']

View File

@ -0,0 +1,32 @@
{% extends 'base.html' %}
{% comment %}
#
# 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/>.
#
{% endcomment %}
{% block content %}
<h2>{{ title }}</h2>
<p>This will run unattended-upgrades, which will attempt to upgrade your system
with the latest Debian packages. It may take a minute to complete.</p>
<p><a class="btn btn-primary btn-lg" href="{% url 'upgrades:run' %}">
Upgrade now &raquo;
</a></p>
{% endblock %}

View File

@ -0,0 +1,35 @@
{% extends 'base.html' %}
{% comment %}
#
# 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/>.
#
{% endcomment %}
{% block content %}
<h2>{{title}}</h2>
{% if upgrades_error %}
<p>There was an error while upgrading:<p>
<pre>{{ upgrades_error }}</pre>
{% endif %}
{% if upgrades_output %}
<p>Output from unattended-upgrades:</p>
<pre>{{ upgrades_output }}</pre>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,63 @@
#
# 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/>.
#
"""
Plinth module for upgrades
"""
from django.contrib.auth.decorators import login_required
from django.template.response import TemplateResponse
from gettext import gettext as _
from plinth import actions
from plinth import cfg
from plinth import package
from plinth.errors import ActionError
def init():
"""Initialize the module"""
menu = cfg.main_menu.get('system:index')
menu.add_urlname("Upgrades", "glyphicon-refresh",
"upgrades:index", 21)
@login_required
@package.required('unattended-upgrades')
def index(request):
"""Serve the index page"""
return TemplateResponse(request, 'upgrades.html',
{'title': _('Package Upgrades')})
@login_required
@package.required('unattended-upgrades')
def run(request):
"""Run upgrades and show the output page"""
output = ''
error = ''
try:
output = actions.superuser_run('upgrades', ['run'])
except ActionError as exception:
output, error = exception.args[1:]
except Exception as exception:
error = str(exception)
return TemplateResponse(request, 'upgrades_run.html',
{'title': _('Package Upgrades'),
'upgrades_output': output,
'upgrades__error': error})

View File

@ -0,0 +1,29 @@
#
# 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/>.
#
"""
URLs for the upgrades module
"""
from django.conf.urls import patterns, url
urlpatterns = patterns(
'plinth.modules.upgrades.upgrades',
url(r'^sys/upgrades/$', 'index', name='index'),
url(r'^sys/upgrades/run/$', 'run', name='run'),
)