def DoDownload(train, cache_dir, pkg_type, verbose, ignore_space=False): try: if not verbose: with ProgressBar() as progress_bar: handler = UpdateHandler(progress_bar.update) rv = Update.DownloadUpdate( train, cache_dir, get_handler=handler.get_handler, check_handler=handler.check_handler, pkg_type=pkg_type, ) if rv is False: progress_bar.update(message="No updates available") else: rv = Update.DownloadUpdate(train, cache_dir, pkg_type=pkg_type, ignore_space=ignore_space) except Exceptions.ManifestInvalidSignature: log.error("Manifest has invalid signature") print("Manifest has invalid signature", file=sys.stderr) sys.exit(1) except Exceptions.UpdateBusyCacheException as e: log.error(str(e)) print("Download cache directory is busy", file=sys.stderr) sys.exit(1) except Exceptions.UpdateIncompleteCacheException: log.error(str(e)) print("Incomplete download cache, cannot update", file=sys.stderr) sys.exit(1) except Exceptions.ChecksumFailException as e: log.error(str(e)) print("Checksum error, cannot update", file=sys.stderr) sys.exit(1) except Exceptions.UpdateInvalidUpdateException as e: log.error(str(e)) print("Update not permitted:\n{0}".format(e.value), file=sys.stderr) sys.exit(1) except Exceptions.UpdateInsufficientSpace as e: log.error(str(e), exc_info=True) print(e.value if e.value else "Insufficient space for download") sys.exit(1) except BaseException as e: log.error(str(e), exc_info=True) print("Received exception during download phase, cannot update", file=sys.stderr) sys.exit(1) return rv
def DoDownload(train, cache_dir, pkg_type): import freenasOS.Update as Update import freenasOS.Exceptions as Exceptions try: rv = Update.DownloadUpdate(train, cache_dir, pkg_type=pkg_type) except Exceptions.ManifestInvalidSignature: log.error("Manifest has invalid signature") print("Manifest has invalid signature", file=sys.stderr) sys.exit(1) except Exceptions.UpdateBusyCacheException as e: log.error(str(e)) print("Download cache directory is busy", file=sys.stderr) sys.exit(1) except Exceptions.UpdateIncompleteCacheException: log.error(str(e)) print("Incomplete download cache, cannot update", file=sys.stderr) sys.exit(1) except BaseException as e: log.error(str(e)) print("Received exception during download phase, cannot update", file=sys.stderr) sys.exit(1) return rv
def main(handler, args): setproctitle('updated') handler.pid = os.getpid() handler.dump() if args.download: log.debug('Starting DownloadUpdate') Update.DownloadUpdate( args.train, args.cache, check_handler=handler.get_handler, get_handler=handler.get_file_handler, ) log.debug('DownloadUpdate finished') new_manifest = Manifest.Manifest(require_signature=True) try: new_manifest.LoadPath(args.cache + '/MANIFEST') except ManifestInvalidSignature as e: log.error("Cached manifest has invalid signature: %s" % str(e)) raise update_version = new_manifest.Version() if args.apply: log.debug('Starting ApplyUpdate') handler.reboot = Update.ApplyUpdate( args.cache, install_handler=handler.install_handler, ) log.debug('ApplyUpdate finished') if handler.reboot: # Create Alert that update is applied and system should now be rebooted create_update_alert(update_version)
def download(self, job): train = self.middleware.call_sync('update.get_trains')['selected'] location = self.middleware.call_sync('update.get_update_location') job.set_progress(0, 'Retrieving update manifest') handler = UpdateHandler(self, job, 100) Update.DownloadUpdate( train, location, check_handler=handler.check_handler, get_handler=handler.get_handler, ) update = Update.CheckForUpdates(train=train, cache_dir=location) if not update: return False notified = False try: if self.middleware.call_sync('cache.has_key', 'update.notified'): notified = self.middleware.call_sync('cache.get', 'update.notified') except Exception: pass if not notified: self.middleware.call_sync('cache.put', 'update.notified', True) conf = Configuration.Configuration() sys_mani = conf.SystemManifest() if sys_mani: sequence = sys_mani.Sequence() else: sequence = '' changelog = get_changelog(train, start=sequence, end=update.Sequence()) try: # FIXME: Translation self.middleware.call_sync( 'mail.send', { 'subject': 'Update Available', 'text': '''A new update is available for the %(train)s train. Version: %(version)s Changelog: %(changelog)s ''' % { 'train': train, 'version': update.Version(), 'changelog': changelog, }, }).wait_sync() except Exception: self.logger.warn('Failed to send email about new update', exc_info=True) return True
def update(self, job, attrs=None): """ Downloads (if not already in cache) and apply an update. """ train = (attrs or {}).get('train') or self.get_train() location = self.middleware.call('notifier.get_update_location') handler = UpdateHandler(self, job) update = Update.DownloadUpdate( train, location, check_handler=handler.check_handler, get_handler=handler.get_handler, ) if update is False: raise ValueError('No update available') new_manifest = Manifest.Manifest(require_signature=True) new_manifest.LoadPath('{}/MANIFEST'.format(location)) Update.ApplyUpdate( location, install_handler=handler.install_handler, ) self.middleware.call('cache.put', 'update.applied', True) return True
def download_impl(self, job, train, location, progress_proportion): scale_flag = os.path.join(location, 'scale') if 'SCALE' in train: result = self.middleware.call_sync('update.download_impl_scale', job, train, location, progress_proportion) if result: with open(scale_flag, 'w'): pass return result job.set_progress(0, 'Retrieving update manifest') handler = UpdateHandler(self, job, progress_proportion) Update.DownloadUpdate( train, location, check_handler=handler.check_handler, get_handler=handler.get_handler, ) update = Update.CheckForUpdates(train=train, cache_dir=location) result = bool(update) if result: with contextlib.suppress(FileNotFoundError): os.unlink(scale_flag) return result
async def update(self, job, attrs=None): """ Downloads (if not already in cache) and apply an update. """ attrs = attrs or {} train = attrs.get('train') or ( await self.middleware.call('update.get_trains'))['selected'] location = await self.middleware.call('notifier.get_update_location') job.set_progress(0, 'Retrieving update manifest') handler = UpdateHandler(self, job) update = Update.DownloadUpdate( train, location, check_handler=handler.check_handler, get_handler=handler.get_handler, ) if update is False: raise ValueError('No update available') new_manifest = Manifest.Manifest(require_signature=True) new_manifest.LoadPath('{}/MANIFEST'.format(location)) Update.ApplyUpdate( location, install_handler=handler.install_handler, ) await self.middleware.call('cache.put', 'update.applied', True) if attrs.get('reboot'): await self.middleware.call('system.reboot', {'delay': 10}) return True
def main(): try: updateobj = mUpdate.objects.order_by('-id')[0] except IndexError: updateobj = mUpdate.objects.create() if updateobj.upd_autocheck is False: return location = notifier().get_update_location() Update.DownloadUpdate(updateobj.get_train(), location) update = Update.CheckForUpdates( train=updateobj.get_train(), cache_dir=location, ) if not update: return conf = Configuration.Configuration() sys_mani = conf.SystemManifest() if sys_mani: sequence = sys_mani.Sequence() else: sequence = '' changelog = get_changelog( updateobj.get_train(), start=sequence, end=update.Sequence(), ) hostname = socket.gethostname() send_mail( subject='%s: %s' % ( hostname, _('Update Available'), ), extra_headers={ 'X-Mailer': get_sw_name(), 'X-%s-Host' % get_sw_name(): socket.gethostname() }, text=_('''A new update is available for the %(train)s train. Version: %(version)s Changelog: %(changelog)s ''') % { 'train': updateobj.get_train(), 'version': update.Version(), 'changelog': changelog, }, )
async def download(self, job): train = (await self.get_trains())['selected'] location = await self.middleware.call('notifier.get_update_location') Update.DownloadUpdate( train, location, ) update = Update.CheckForUpdates(train=train, cache_dir=location) if not update: return False notified = False try: if await self.middleware.call('cache.has_key', 'update.notified'): notified = await self.middleware.call('cache.get', 'update.notified') except Exception: pass if not notified: await self.middleware.call('cache.put', 'update.notified', True) conf = Configuration.Configuration() sys_mani = conf.SystemManifest() if sys_mani: sequence = sys_mani.Sequence() else: sequence = '' changelog = get_changelog(train, start=sequence, end=update.Sequence()) hostname = socket.gethostname() try: # FIXME: Translation await self.middleware.call( 'mail.send', { 'subject': '{}: {}'.format(hostname, 'Update Available'), 'text': '''A new update is available for the %(train)s train. Version: %(version)s Changelog: %(changelog)s ''' % { 'train': train, 'version': update.Version(), 'changelog': changelog, }, }) except Exception: self.logger.warn('Failed to send email about new update', exc_info=True) return True
def download_impl(self, job, train, location, progress_proportion): job.set_progress(0, 'Retrieving update manifest') handler = UpdateHandler(self, job, progress_proportion) Update.DownloadUpdate( train, location, check_handler=handler.check_handler, get_handler=handler.get_handler, ) update = Update.CheckForUpdates(train=train, cache_dir=location) return bool(update)
def DoDownload(train, cache_dir, pkg_type, verbose): try: if not verbose: progress_bar = ProgressBar() handler = UpdateHandler(progress_bar.update) rv = Update.DownloadUpdate( train, cache_dir, get_handler=handler.get_handler, check_handler=handler.check_handler, pkg_type=pkg_type, ) if rv is False: progress_bar.update(message="No updates available") progress_bar.finish() else: rv = Update.DownloadUpdate(train, cache_dir, pkg_type=pkg_type) except Exceptions.ManifestInvalidSignature: log.error("Manifest has invalid signature") print("Manifest has invalid signature", file=sys.stderr) sys.exit(1) except Exceptions.UpdateBusyCacheException as e: log.error(str(e)) print("Download cache directory is busy", file=sys.stderr) sys.exit(1) except Exceptions.UpdateIncompleteCacheException: log.error(str(e)) print("Incomplete download cache, cannot update", file=sys.stderr) sys.exit(1) except BaseException as e: log.error(str(e)) print("Received exception during download phase, cannot update", file=sys.stderr) sys.exit(1) return rv
async def update(self, job, attrs=None): """ Downloads (if not already in cache) and apply an update. """ attrs = attrs or {} trains = await self.middleware.call('update.get_trains') train = attrs.get('train') or trains['selected'] if attrs.get('train'): await self.middleware.run_in_thread(self.__set_train, attrs.get('train'), trains) location = await self.middleware.call('update.get_update_location') job.set_progress(0, 'Retrieving update manifest') handler = UpdateHandler(self, job) update = Update.DownloadUpdate( train, location, check_handler=handler.check_handler, get_handler=handler.get_handler, ) if update is False: raise ValueError('No update available') new_manifest = Manifest.Manifest(require_signature=True) new_manifest.LoadPath('{}/MANIFEST'.format(location)) Update.ApplyUpdate( location, install_handler=handler.install_handler, ) await self.middleware.call('cache.put', 'update.applied', True) if ( await self.middleware.call('system.is_freenas') or ( await self.middleware.call('failover.licensed') and await self.middleware.call('failover.status') != 'BACKUP' ) ): await self.middleware.call('update.take_systemdataset_samba4_snapshot') if attrs.get('reboot'): await self.middleware.call('system.reboot', {'delay': 10}) return True
def download(self, job): train = self.middleware.call_sync('update.get_trains')['selected'] location = self.middleware.call_sync('update.get_update_location') job.set_progress(0, 'Retrieving update manifest') handler = UpdateHandler(self, job, 100) Update.DownloadUpdate( train, location, check_handler=handler.check_handler, get_handler=handler.get_handler, ) update = Update.CheckForUpdates(train=train, cache_dir=location) self.middleware.call_sync('alert.alert_source_clear_run', 'HasUpdate') return bool(update)
def main(handler, args): set_proc_name('updated') handler.pid = os.getpid() handler.dump() if args.download: log.debug('Starting DownloadUpdate') Update.DownloadUpdate( args.train, args.cache, check_handler=handler.get_handler, get_handler=handler.get_file_handler, ) log.debug('DownloadUpdate finished') if args.apply: log.debug('Starting ApplyUpdate') Update.ApplyUpdate( args.cache, install_handler=handler.install_handler, ) log.debug('ApplyUpdate finished')
def main(): global log def usage(): print >> sys.stderr, """Usage: %s [-C cache_dir] [-d] [-T train] [-v] <cmd>, where cmd is one of: check\tCheck for updates update\tDo an update""" % sys.argv[0] sys.exit(1) try: opts, args = getopt.getopt(sys.argv[1:], "C:dT:v") except getopt.GetoptError as err: print str(err) usage() verbose = False debug = 0 config = None cache_dir = None train = None for o, a in opts: if o == "-v": verbose = True elif o == "-d": debug += 1 elif o == '-C': cache_dir = a elif o == "-T": train = a elif o == '-c': cachedir = a else: assert False, "unhandled option %s" % o logging.config.dictConfig({ 'version': 1, 'disable_existing_loggers': True, 'formatters': { 'simple': { 'format': '[%(name)s:%(lineno)s] %(message)s', }, }, 'handlers': { 'std': { 'class': 'logging.StreamHandler', 'level': 'DEBUG', 'stream': 'ext://sys.stdout', }, }, 'loggers': { '': { 'handlers': ['std'], 'level': 'DEBUG', 'propagate': True, }, }, }) log = logging.getLogger('freenas-update') sys.path.append("/usr/local/lib") import freenasOS.Configuration as Configuration import freenasOS.Manifest as Manifest import freenasOS.Update as Update config = Configuration.Configuration() if train is None: train = config.SystemManifest().Train() if len(args) != 1: usage() if args[0] == "check": # To see if we have an update available, we # call Update.DownloadUpdate. If we have been # given a cache directory, we pass that in; otherwise, # we make a temporary directory and use that. We # have to clean up afterwards in that case. if cache_dir is None: download_dir = tempfile.mkdtemp(prefix="UpdateCheck-", dir=config.TemporaryDirectory()) if download_dir is None: print >> sys.stderr, "Unable to create temporary directory" sys.exit(1) else: download_dir = cache_dir rv = Update.DownloadUpdate(train, download_dir) if rv is False: if verbose: print "No updates available" if cache_dir is None: Update.RemoveUpdate(download_dir) sys.exit(1) else: if verbose: diffs = Update.PendingUpdates(download_dir) for (pkg, op, old) in diffs: if op == "delete": print >> sys.stderr, "Delete package %s" % pkg.Name() elif op == "install": print >> sys.stderr, "Install package %s-%s" % ( pkg.Name(), pkg.Version()) elif op == "upgrade": print >> sys.stderr, "Upgrade package %s %s->%s" % ( pkg.Name(), old.Version(), pkg.Version()) if cache_dir is None: Update.RemoveUpdate(download_dir) sys.exit(0) elif args[0] == "update": # This will attempt to apply an update. # If cache_dir is given, then we will only check that directory, # not force a download if it is already there. If cache_dir is not # given, however, then it downloads. (The reason is that you would # want to run "freenas-update -c /foo check" to look for an update, # and it will download the latest one as necessary, and then run # "freenas-update -c /foo update" if it said there was an update. if cache_dir is None: download_dir = tempfile.mkdtemp(prefix="UpdateUpdate-", dir=config.TemporaryDirectory()) if download_dir is None: print >> sys.stderr, "Unable to create temporary directory" sys.exit(1) rv = Update.DownloadUpdate(train, download_dir) if rv is False: if verbose or debug: print >> sys.stderr, "DownloadUpdate returned False" sys.exit(1) else: download_dir = cache_dir diffs = Update.PendingUpdates(download_dir) if diffs is None or diffs == {}: if verbose: print >> sys.stderr, "No updates to apply" else: if verbose: for (pkg, op, old) in diffs: if op == "delete": print >> sys.stderr, "Delete package %s" % pkg.Name() elif op == "install": print >> sys.stderr, "Install package %s-%s" % ( pkg.Name(), pkg.Version()) elif op == "upgrade": print >> sys.stderr, "Upgrade package %s %s -> %s" % ( pkg.Name(), old.Version(), pkg.Version()) rv = Update.ApplyUpdate(download_dir) if rv is False: if verbose: print >> sys.stderr, "ApplyUpdates failed" if cache_dir is None: Update.RemoveUpdate(download_dir) sys.exit(1) Update.RemoveUpdate(download_dir) # Change this if/when we can do an update without a reboot. print >> sys.stderr, "System should be rebooted now" sys.exit(0) else: usage()
def main(): global log logging.config.dictConfig({ 'version': 1, 'disable_existing_loggers': True, 'formatters': { 'simple': { 'format': '[%(name)s:%(lineno)s] %(message)s', }, }, 'handlers': { 'std': { 'class': 'logging.StreamHandler', 'level': 'DEBUG', 'stream': 'ext://sys.stderr', }, }, 'loggers': { '': { 'handlers': ['std'], 'level': 'DEBUG', 'propagate': True, }, }, }) log = logging.getLogger('freenas-update') sys.path.append("/usr/local/lib") import freenasOS.Configuration as Configuration import freenasOS.Manifest as Manifest import freenasOS.Update as Update def usage(): print >> sys.stderr, """Usage: %s [-C cache_dir] [-d] [-T train] [--no-delta] [-v] <cmd>, where cmd is one of: check\tCheck for updates update\tDo an update""" % sys.argv[0] sys.exit(1) try: short_opts = "C:dT:v" long_opts = ["cache=", "debug", "train=", "verbose", "no-delta"] opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts) except getopt.GetoptError as err: print str(err) usage() verbose = False debug = 0 config = None cache_dir = None train = None pkg_type = None for o, a in opts: if o in ("-v", "--verbose"): verbose = True elif o in ("-d", "--debug"): debug += 1 elif o in ('-C', "--cache"): cache_dir = a elif o in ("-T", "--train"): train = a elif o in ("--no-delta"): pkg_type = Update.PkgFileFullOnly else: assert False, "unhandled option %s" % o config = Configuration.Configuration() if train is None: train = config.SystemManifest().Train() if len(args) != 1: usage() if args[0] == "check": # To see if we have an update available, we # call Update.DownloadUpdate. If we have been # given a cache directory, we pass that in; otherwise, # we make a temporary directory and use that. We # have to clean up afterwards in that case. if cache_dir is None: download_dir = tempfile.mkdtemp(prefix="UpdateCheck-", dir=config.TemporaryDirectory()) if download_dir is None: print >> sys.stderr, "Unable to create temporary directory" sys.exit(1) else: download_dir = cache_dir rv = Update.DownloadUpdate(train, download_dir, pkg_type=pkg_type) if rv is False: if verbose: print "No updates available" if cache_dir is None: Update.RemoveUpdate(download_dir) sys.exit(1) else: diffs = Update.PendingUpdatesChanges(download_dir) if diffs is None or len(diffs) == 0: print >> sys.stderr, "Strangely, DownloadUpdate says there updates, but PendingUpdates says otherwise" sys.exit(1) PrintDifferences(diffs) if cache_dir is None: Update.RemoveUpdate(download_dir) sys.exit(0) elif args[0] == "update": # This will attempt to apply an update. # If cache_dir is given, then we will only check that directory, # not force a download if it is already there. If cache_dir is not # given, however, then it downloads. (The reason is that you would # want to run "freenas-update -c /foo check" to look for an update, # and it will download the latest one as necessary, and then run # "freenas-update -c /foo update" if it said there was an update. try: update_opts, update_args = getopt.getopt(args[1:], "R", "--reboot") except getopt.GetoptError as err: print str(err) usage() force_reboot = False for o, a in update_opts: if o in ("-R", "--reboot"): force_reboot = True else: assert False, "Unhandled option %s" % o if cache_dir is None: download_dir = tempfile.mkdtemp(prefix="UpdateUpdate-", dir=config.TemporaryDirectory()) if download_dir is None: print >> sys.stderr, "Unable to create temporary directory" sys.exit(1) rv = Update.DownloadUpdate(train, download_dir, pkg_type=pkg_type) if rv is False: if verbose or debug: print >> sys.stderr, "DownloadUpdate returned False" sys.exit(1) else: download_dir = cache_dir diffs = Update.PendingUpdatesChanges(download_dir) if diffs is None or diffs == {}: if verbose: print >> sys.stderr, "No updates to apply" else: if verbose: PrintDifferences(diffs) try: rv = Update.ApplyUpdate(download_dir, force_reboot=force_reboot) except BaseException as e: print >> sys.stderr, "Unable to apply update: %s" % str(e) sys.exit(1) if cache_dir is None: Update.RemoveUpdate(download_dir) if rv: print >> sys.stderr, "System should be rebooted now" sys.exit(0) else: usage()
async def update(self, job, attrs=None): """ Downloads (if not already in cache) and apply an update. """ attrs = attrs or {} trains = await self.middleware.call('update.get_trains') train = attrs.get('train') or trains['selected'] try: result = compare_trains(trains['current'], train) except Exception: self.logger.warning("Failed to compare trains %r and %r", trains['current'], train, exc_info=True) else: errors = { CompareTrainsResult.NIGHTLY_DOWNGRADE: textwrap.dedent("""\ You're not allowed to change away from the nightly train, it is considered a downgrade. If you have an existing boot environment that uses that train, boot into it in order to upgrade that train. """), CompareTrainsResult.MINOR_DOWNGRADE: textwrap.dedent("""\ Changing minor version is considered a downgrade, thus not a supported operation. If you have an existing boot environment that uses that train, boot into it in order to upgrade that train. """), CompareTrainsResult.MAJOR_DOWNGRADE: textwrap.dedent("""\ Changing major version is considered a downgrade, thus not a supported operation. If you have an existing boot environment that uses that train, boot into it in order to upgrade that train. """), } if result in errors: raise CallError(errors[result]) location = await self.middleware.call('update.get_update_location') job.set_progress(0, 'Retrieving update manifest') handler = UpdateHandler(self, job) update = Update.DownloadUpdate( train, location, check_handler=handler.check_handler, get_handler=handler.get_handler, ) if update is False: raise ValueError('No update available') new_manifest = Manifest.Manifest(require_signature=True) new_manifest.LoadPath('{}/MANIFEST'.format(location)) Update.ApplyUpdate( location, install_handler=handler.install_handler, ) await self.middleware.call('cache.put', 'update.applied', True) if attrs.get('reboot'): await self.middleware.call('system.reboot', {'delay': 10}) return True