cloud-init/cloudinit/CloudConfig/cc_apt_update_upgrade.py
Scott Moser c994d0c67e util.subp: do not attach stdin cloud-init's stdin to subprocesses (LP: 831505)
Fix issue where 'isatty' would return true for apt-add-repository.
It would get stdin which was attached to a terminal (/dev/console) and would
thus hang when running during boot.

This was done by changing all users of util.subp to have None input unless
input was given.  In that case, the input will be the string passed in.
2011-08-22 23:21:35 -04:00

165 lines
5.3 KiB
Python

# vi: ts=4 expandtab
#
# Copyright (C) 2009-2010 Canonical Ltd.
#
# Author: Scott Moser <scott.moser@canonical.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3, as
# published by the Free Software Foundation.
#
# 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, see <http://www.gnu.org/licenses/>.
import cloudinit.util as util
import subprocess
import traceback
import os
import glob
import cloudinit.CloudConfig as cc
def handle(name,cfg,cloud,log,args):
update = util.get_cfg_option_bool(cfg, 'apt_update', False)
upgrade = util.get_cfg_option_bool(cfg, 'apt_upgrade', False)
release = get_release()
if cfg.has_key("apt_mirror"):
mirror = cfg["apt_mirror"]
else:
mirror = cloud.get_mirror()
if not util.get_cfg_option_bool(cfg, \
'apt_preserve_sources_list', False):
generate_sources_list(release, mirror)
old_mir = util.get_cfg_option_str(cfg,'apt_old_mirror', \
"archive.ubuntu.com/ubuntu")
rename_apt_lists(old_mir, mirror)
# process 'apt_sources'
if cfg.has_key('apt_sources'):
errors = add_sources(cfg['apt_sources'],
{ 'MIRROR' : mirror, 'RELEASE' : release } )
for e in errors:
log.warn("Source Error: %s\n" % ':'.join(e))
dconf_sel = util.get_cfg_option_str(cfg, 'debconf_selections', False)
if dconf_sel:
log.debug("setting debconf selections per cloud config")
try:
util.subp(('debconf-set-selections', '-'), dconf_sel)
except:
log.error("Failed to run debconf-set-selections")
log.debug(traceback.format_exc())
pkglist = util.get_cfg_option_list_or_str(cfg,'packages',[])
errors = [ ]
if update or len(pkglist) or upgrade:
try:
cc.update_package_sources()
except subprocess.CalledProcessError as e:
log.warn("apt-get update failed")
log.debug(traceback.format_exc())
errors.append(e)
if upgrade:
try:
cc.apt_get("upgrade")
except subprocess.CalledProcessError as e:
log.warn("apt upgrade failed")
log.debug(traceback.format_exc())
errors.append(e)
if len(pkglist):
try:
cc.install_packages(pkglist)
except subprocess.CalledProcessError as e:
log.warn("Failed to install packages: %s " % pkglist)
log.debug(traceback.format_exc())
errors.append(e)
if len(errors):
raise errors[0]
return(True)
def mirror2lists_fileprefix(mirror):
file=mirror
# take of http:// or ftp://
if file.endswith("/"): file=file[0:-1]
pos=file.find("://")
if pos >= 0:
file=file[pos+3:]
file=file.replace("/","_")
return file
def rename_apt_lists(omirror,new_mirror,lists_d="/var/lib/apt/lists"):
oprefix="%s/%s" % (lists_d,mirror2lists_fileprefix(omirror))
nprefix="%s/%s" % (lists_d,mirror2lists_fileprefix(new_mirror))
if(oprefix==nprefix): return
olen=len(oprefix)
for file in glob.glob("%s_*" % oprefix):
os.rename(file,"%s%s" % (nprefix, file[olen:]))
def get_release():
stdout, stderr = subprocess.Popen(['lsb_release', '-cs'], stdout=subprocess.PIPE).communicate()
return(stdout.strip())
def generate_sources_list(codename, mirror):
util.render_to_file('sources.list', '/etc/apt/sources.list', \
{ 'mirror' : mirror, 'codename' : codename })
# srclist is a list of dictionaries,
# each entry must have: 'source'
# may have: key, ( keyid and keyserver)
def add_sources(srclist, searchList={ }):
elst = []
for ent in srclist:
if not ent.has_key('source'):
elst.append([ "", "missing source" ])
continue
source=ent['source']
if source.startswith("ppa:"):
try: util.subp(["add-apt-repository",source])
except:
elst.append([source, "add-apt-repository failed"])
continue
source = util.render_string(source, searchList)
if not ent.has_key('filename'):
ent['filename']='cloud_config_sources.list'
if not ent['filename'].startswith("/"):
ent['filename'] = "%s/%s" % \
("/etc/apt/sources.list.d/", ent['filename'])
if ( ent.has_key('keyid') and not ent.has_key('key') ):
ks = "keyserver.ubuntu.com"
if ent.has_key('keyserver'): ks = ent['keyserver']
try:
ent['key'] = util.getkeybyid(ent['keyid'], ks)
except:
elst.append([source,"failed to get key from %s" % ks])
continue
if ent.has_key('key'):
try: util.subp(('apt-key', 'add', '-'), ent['key'])
except:
elst.append([source, "failed add key"])
try: util.write_file(ent['filename'], source + "\n", omode="ab")
except:
elst.append([source, "failed write to file %s" % ent['filename']])
return(elst)