Commit f4485d8a authored by Rafael Monnerat's avatar Rafael Monnerat

[slapos.package.update] Reimplement upgrade WIP

  Move Signature Handling to signature
  Use classes for make easy to testing for mock it
  Introduce Tester (former slapos-test)
parent 72e4ef5f
#!/usr/bin/python
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2012 Vifib SARL and Contributors.
# All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import ConfigParser
import os
import tempfile
from slapos.networkcachehelper import helper_download_network_cached_to_file
class NetworkCache:
def __init__(self, configuration):
if not os.path.exists(slapos_conf):
raise ValueError("You need configuration file")
self.configuration = configuration
def _load(self):
network_cache_info = ConfigParser.RawConfigParser()
network_cache_info.read(self.configuration)
self.download_binary_cache_url = network_cache_info.get('networkcache', 'download-binary-cache-url')
self.download_cache_url = network_cache_info.get('networkcache', 'download-cache-url')
self.download_binary_dir_url = network_cache_info.get('networkcache', 'download-binary-dir-url')
self.signature_certificate_list = network_cache_info.get('networkcache', 'signature-certificate-list')
if network_cache_info.has_section('slapupdate'):
self.directory_key = network_cache_info.get('slapupdate', 'upgrade_key')
else:
self.directory_key = "slapos-upgrade-testing-key"
class Signature:
def __init__(self, config, logger=None):
self.config = config
self.logger = logger
self.current_state_path = config.srv_file
# Get configuration
self.current_state = ConfigParser.RawConfigParser()
self.current_state.read(config.srv_file)
self.next_state = ConfigParser.RawConfigParser()
self.next_state.read(self.download())
def _download(self, path):
"""
Download a tar of the repository from cache, and untar it.
"""
shacache = NetworkCache(self.config.slapos_configuration)
def strategy(entry_list):
"""Get the latest entry. """
timestamp = 0
best_entry = None
for entry in entry_list:
if entry['timestamp'] > timestamp:
best_entry = entry
return best_entry
return helper_download_network_cached_to_file(
path=path,
directory_key=shacache.directory_key,
required_key_list=['timestamp'],
strategy=strategy,
# Then we give a lot of not interesting things
dir_url=shacache.download_binary_dir_url,
cache_url=shacache.download_binary_cache_url,
signature_certificate_list=shacache.signature_certificate_list,
)
def download(self):
"""
Get status information and return its path
"""
info, path = tempfile.mkstemp()
if not self._download(path) == False:
print open(path).read()
return path
else:
raise ValueError("No result from shacache")
def update(self, reboot=None, upgrade=None):
if reboot is None and upgrade is None:
return
if not self.current_state.has_section('system'):
self.current_state.add_section('system')
if reboot is not None:
self.current_state.set('system', 'reboot', reboot)
if upgrade is not None:
self.current_state.set('system', 'upgrade', upgrade)
current_state_file = open(self.current_state_path, "w")
self.current_state.write(current_state_file)
current_state_file.close()
def _read_state(self, state, name):
""" Extract information from config file """
if not state.has_section('system'):
return None
return datetime.datetime.strptime(
state.get('system', name), "%Y-%m-%d").date()
def load(self):
"""
Extract information from config file and server file
"""
self.reboot = self._read_state(self.next_state, "upgrade")
self.upgrade = self._read_state(self.next_state, "upgrade")
self.last_reboot = self._read_state(self.current_state, "reboot")
self.last_upgrade = self._read_state(self.current_state, "upgrade")
This diff is collapsed.
......@@ -36,10 +36,6 @@ import os
import subprocess as sub
import sys
import tempfile
import _autoupdate
from slapos.networkcachehelper import helper_download_network_cached_to_file
# create console handler and set level to warning
ch = logging.StreamHandler()
......@@ -49,7 +45,6 @@ formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(messag
# add formatter to ch
ch.setFormatter(formatter)
class Parser(OptionParser):
"""
Parse all arguments.
......@@ -83,193 +78,66 @@ class Parser(OptionParser):
(options, args) = self.parse_args()
return options
class NetworkCache ():
def __init__(self, slapos_conf):
if os.path.exists(slapos_conf):
network_cache_info = ConfigParser.RawConfigParser()
network_cache_info.read(slapos_conf)
self.download_binary_cache_url = network_cache_info.get('networkcache', 'download-binary-cache-url')
self.download_cache_url = network_cache_info.get('networkcache', 'download-cache-url')
self.download_binary_dir_url = network_cache_info.get('networkcache', 'download-binary-dir-url')
self.signature_certificate_list = network_cache_info.get('networkcache', 'signature-certificate-list')
else:
self.download_binary_cache_url = "http://www.shacache.org/shacache"
self.download_cache_url = "https://www.shacache.org/shacache"
self.download_binary_dir_url = "http://www.shacache.org/shadir"
self.signature_certificate_list = ""
self.signature_certificate_list = """
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJANd3qMXJcWPgMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtOTAyMCAXDTEyMDkwNDEyMDM1OFoYDzIxMTIwODExMTIwMzU4WjAT
MREwDwYDVQQDDAhDT01QLTkwMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
nhfhuGEO3gsQXkYjbhMFzY3b74bAcOvT3vwYd3V+V38XYC2Ds7ugyKIp3EisrREN
8bRzxLTJjEwNhBjdS3GfFt/8uxB7hoKul4lEtdYmM4NCIlLbmoXwoJOVYzL7QWNg
4uMEm9Bf46zhgY3ZNgCLELn8YgUDSr/dfdSDnN7wpoUCAwEAAaNQME4wHQYDVR0O
BBYEFHgf9WN8LY9BZvtAcWrGtk6rCTq3MB8GA1UdIwQYMBaAFHgf9WN8LY9BZvtA
cWrGtk6rCTq3MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAIFHRgb3D
7va0+kUmw6xidJf9t4X5bkhOt/FBKpJK3tXctIN6DYPlPcemktMmrnYtYimq387I
NYK/ZbWhfgv7VZqJ2OUvGaDQIm9oAuRfcu7QCbEzN10RibLLRKdDDgIhb34iLxVg
jlD7tZ2DbRKHu5FadsKWNZpqC9H0BRLjBwY=
-----END CERTIFICATE-----
""" + self.signature_certificate_list
def download_info_from_networkcache(path, slapos_conf):
"""
Download a tar of the repository from cache, and untar it.
"""
shacache = NetworkCache(slapos_conf)
def strategy(entry_list):
"""
Get the latest entry.
"""
timestamp = 0
best_entry = None
for entry in entry_list:
if entry['timestamp'] > timestamp:
best_entry = entry
return best_entry
return helper_download_network_cached_to_file(
path=path,
directory_key='slapos-under-testing-key',
required_key_list=['timestamp'],
strategy=strategy,
# Then we give a lot of not interesting things
dir_url=shacache.download_binary_dir_url,
cache_url=shacache.download_binary_cache_url,
signature_certificate_list=shacache.signature_certificate_list,
)
def get_info_from_master(config):
"""
Get status information and return its path
"""
info, path = tempfile.mkstemp()
if not download_info_from_networkcache(
path, config.slapos_configuration) == False:
print open(path).read()
return path
else:
raise ValueError("No result from shacache")
def save_current_state(current_state, config):
"""
Will save ConfigParser to config file
"""
file = open(config.srv_file, "w")
current_state.write(file)
file.close()
def checkConsistency(*args, **kw):
print "CHECK CONSISTENCY %s" % ((args, kw),)
def update_machine(config):
"""
Will fetch information from web and update and/or reboot
machine if needed
"""
# Define logger for update_machine
logger = logging.getLogger('Updating your machine')
logger.setLevel(logging.DEBUG)
# add ch to logger
logger.addHandler(ch)
# Get configuration
current_state = ConfigParser.RawConfigParser()
current_state.read(config.srv_file)
next_state = ConfigParser.RawConfigParser()
next_state_file = get_info_from_master(config)
next_state.read(next_state_file)
os.remove(next_state_file)
config.getSystemInfo(current_state, next_state)
config.displayConfig()
# Check if run for first time
if config.first_time:
current_state.add_section('system')
current_state.set('system', 'reboot', config.today.isoformat())
current_state.set('system', 'upgrade', config.today.isoformat())
save_current_state(current_state, config)
# Purge repositories list and add new ones
checkConsistency()
else:
if config.last_upgrade < config.upgrade:
# Purge repositories list and add new ones
current_state.set('system', 'upgrade', config.today.isoformat())
save_current_state(current_state, config)
checkConcistency()
else:
logger.info("Your system is up to date")
if config.last_reboot < config.reboot:
current_state.set('system', 'reboot', config.today.isoformat())
save_current_state(current_state, config)
# Class containing all parameters needed for configuration
class Config:
def setConfig(self, option_dict):
"""
Set options given by parameters.
"""
def __init__(self, option_dict):
# Set options parameters
for option, value in option_dict.__dict__.items():
setattr(self, option, value)
self.today = datetime.date.today()
class Upgrader:
def __init__(self, config_dict):
# Set options parameters
self.config = Config(config_dict)
# Define logger for register
self.logger = logging.getLogger('slapupdate configuration')
self.logger = logging.getLogger('Updating your machine')
self.logger.setLevel(logging.DEBUG)
# add ch to logger
self.logger.addHandler(ch)
if self.verbose:
ch.setLevel(logging.DEBUG)
def getSystemInfo(self, current_state, next_state):
"""
Extract information from config file and server file
"""
self.reboot = datetime.datetime.strptime(next_state.get('system', 'reboot'),
"%Y-%m-%d").date()
self.upgrade = datetime.datetime.strptime(next_state.get('system', 'upgrade'),
"%Y-%m-%d").date()
self.opensuse_version = next_state.getfloat('system', 'opensuse_version')
if not current_state.has_section('system'):
self.first_time = True
else:
self.first_time = False
self.last_reboot = datetime.datetime.strptime(
current_state.get('system', 'reboot'),
"%Y-%m-%d").date()
self.last_upgrade = datetime.datetime.strptime(
current_state.get('system', 'upgrade'),
"%Y-%m-%d").date()
def checkConsistency(self, *args, **kw):
print "CHECK CONSISTENCY %s" % ((args, kw),)
def displayConfig(self):
def run(self):
"""
Display Config
Will fetch information from web and update and/or reboot
machine if needed
"""
self.logger.debug("reboot %s" % self.reboot)
self.logger.debug("upgrade %s" % self.upgrade)
self.logger.debug("suse version %s" % self.opensuse_version)
if not self.first_time:
self.logger.debug("Last reboot : %s" % self.last_reboot)
self.logger.debug("Last upgrade : %s" % self.last_upgrade)
today = datetime.date.today().isoformat()
# Get configuration
signature = Signature(self.config)
signature.load()
self.logger.debug("Expected Reboot early them %s" % signature.reboot)
self.logger.debug("Expected Upgrade early them %s" % signature.upgrade)
self.logger.debug("Last reboot : %s" % signature.last_reboot)
self.logger.debug("Last upgrade : %s" % signature.last_upgrade)
# Check if run for first time
if signature.last_reboot is None:
signature.update(reboot=today, upgrade=today)
# Purge repositories list and add new ones
self.checkConsistency()
else:
if signature.last_upgrade < signature.upgrade:
# Purge repositories list and add new ones
signature.update(upgrade=today)
self.checkConcistency()
else:
logger.info("Your system is up to date")
if signature.last_reboot < signature.reboot:
signature.update(reboot=today)
def main():
"""Update computer and slapos"""
usage = "usage: %s [options] " % sys.argv[0]
# Parse arguments
config = Config()
config.setConfig(Parser(usage=usage).check_args())
#config.displayUserConfig()
update_machine(config)
upgrader = Upgrader(Parser(usage=usage).check_args())
upgrader.run()
sys.exit()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment