move cloud-run-user-script.conf to cloud-final, use cloud-cfg for invoking
This moves what was done as cloud-run-user-script.conf to 'cloud-final' and makes that re-use the cloud-init-cfg code, but simply with a different set of default configs. Also, adds keys_to_console and final_message cloud-config modules
This commit is contained in:
parent
07f91c1b87
commit
54326d76e8
11
ChangeLog
11
ChangeLog
@ -16,3 +16,14 @@
|
||||
- the semaphore name for 'set_hostname' and 'update_hostname'
|
||||
changes to 'config_set_hostname' and 'config_update_hostname'
|
||||
- added cloud-config option 'hostname' for setting hostname
|
||||
- moved upstart/cloud-run-user-script.conf to upstart/cloud-final.conf
|
||||
- cloud-final.conf now runs runs cloud-config modules similar
|
||||
to cloud-config and cloud-init.
|
||||
- LP: #653271
|
||||
- added writing of "boot-finished" to /var/lib/cloud/instance/boot-finished
|
||||
this is the last thing done, indicating cloud-init is finished booting
|
||||
- writes message to console with timestamp and uptime
|
||||
- write ssh keys to console as one of the last things done
|
||||
this is to ensure they don't get run off the 'get-console-ouptut' buffer
|
||||
- user_scripts run via cloud-final and thus semaphore renamed from
|
||||
user_scripts to config_user_scripts
|
||||
|
@ -68,8 +68,8 @@ def main():
|
||||
module_list = [ ]
|
||||
if name == "all":
|
||||
modlist_cfg_name = "%s_modules" % modlist
|
||||
modules_list = CC.read_cc_modules(cc.cfg,modlist_cfg_name)
|
||||
if not len(modules_list):
|
||||
module_list = CC.read_cc_modules(cc.cfg,modlist_cfg_name)
|
||||
if not len(module_list):
|
||||
err("no modules to run in cloud_config [%s]" % modlist,log)
|
||||
sys.exit(0)
|
||||
else:
|
||||
|
@ -98,7 +98,7 @@ def run_cc_modules(cc,module_list,log):
|
||||
cc.handle(name, run_args, freq=freq)
|
||||
except:
|
||||
log.warn(traceback.format_exc())
|
||||
log.err("config handling of %s, %s, %s failed\n" %
|
||||
log.error("config handling of %s, %s, %s failed\n" %
|
||||
(name,freq,run_args))
|
||||
failures.append(name)
|
||||
|
||||
|
55
cloudinit/CloudConfig/cc_final_message.py
Normal file
55
cloudinit/CloudConfig/cc_final_message.py
Normal file
@ -0,0 +1,55 @@
|
||||
# vi: ts=4 expandtab
|
||||
#
|
||||
# Copyright (C) 2011 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/>.
|
||||
from cloudinit.CloudConfig import per_instance
|
||||
import sys
|
||||
from cloudinit import util, boot_finished
|
||||
|
||||
frequency = per_instance
|
||||
|
||||
final_message = "cloud-init boot finished at $TIMESTAMP. Up $UPTIME seconds"
|
||||
|
||||
def handle(name,cfg,cloud,log,args):
|
||||
if len(args) != 0:
|
||||
msg_in = args[0]
|
||||
else:
|
||||
msg_in = util.get_cfg_option_str(cfg,"final_message",final_message)
|
||||
|
||||
try:
|
||||
uptimef=open("/proc/uptime")
|
||||
uptime=uptimef.read().split(" ")[0]
|
||||
uptimef.close()
|
||||
except IOError as e:
|
||||
log.warn("unable to open /proc/uptime\n")
|
||||
uptime = "na"
|
||||
|
||||
|
||||
try:
|
||||
from datetime import datetime
|
||||
ts = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S +0000')
|
||||
except:
|
||||
ts = "na"
|
||||
|
||||
try:
|
||||
subs = { 'UPTIME' : uptime, 'TIMESTAMP' : ts }
|
||||
sys.stdout.write(util.render_string(msg_in, subs))
|
||||
except Exception as e:
|
||||
log.warn("failed to render string to stdout: %s" % e)
|
||||
|
||||
fp = open(boot_finished, "wb")
|
||||
fp.write(uptime + "\n")
|
||||
fp.close()
|
31
cloudinit/CloudConfig/cc_keys_to_console.py
Normal file
31
cloudinit/CloudConfig/cc_keys_to_console.py
Normal file
@ -0,0 +1,31 @@
|
||||
# vi: ts=4 expandtab
|
||||
#
|
||||
# Copyright (C) 2011 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/>.
|
||||
from cloudinit.CloudConfig import per_instance
|
||||
import subprocess
|
||||
|
||||
frequency = per_instance
|
||||
|
||||
def handle(name,cfg,cloud,log,args):
|
||||
write_ssh_prog='/usr/lib/cloud-init/write-ssh-key-fingerprints'
|
||||
try:
|
||||
confp = open('/dev/console',"wb")
|
||||
subprocess.call(write_ssh_prog,stdout=confp)
|
||||
confp.close()
|
||||
except:
|
||||
log.warn("writing keys to console value")
|
||||
raise
|
39
cloudinit/CloudConfig/cc_phone_home.py
Normal file
39
cloudinit/CloudConfig/cc_phone_home.py
Normal file
@ -0,0 +1,39 @@
|
||||
# vi: ts=4 expandtab
|
||||
#
|
||||
# Copyright (C) 2011 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/>.
|
||||
from cloudinit.CloudConfig import per_instance
|
||||
import cloudinit.util as util
|
||||
frequency = per_instance
|
||||
|
||||
def handle(name,cfg,cloud,log,args):
|
||||
if len(args) != 0:
|
||||
value = args[0]
|
||||
else:
|
||||
value = util.get_cfg_option_str(cfg,"phone_home_url",False)
|
||||
|
||||
if not value:
|
||||
return
|
||||
|
||||
# TODO:
|
||||
# implement phone_home
|
||||
# pass to it
|
||||
# - ssh key fingerprints
|
||||
# - mac addr ?
|
||||
# - ip address
|
||||
#
|
||||
log.warn("TODO: write cc_phone_home")
|
||||
return
|
30
cloudinit/CloudConfig/cc_scripts_per_boot.py
Normal file
30
cloudinit/CloudConfig/cc_scripts_per_boot.py
Normal file
@ -0,0 +1,30 @@
|
||||
# vi: ts=4 expandtab
|
||||
#
|
||||
# Copyright (C) 2011 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
|
||||
from cloudinit.CloudConfig import per_once, per_always, per_instance
|
||||
from cloudinit import get_cpath, get_ipath_cur
|
||||
|
||||
frequency = per_always
|
||||
runparts_path = "%s/%s" % (get_cpath(), "scripts/per-boot")
|
||||
|
||||
def handle(name,cfg,cloud,log,args):
|
||||
try:
|
||||
util.runparts(runparts_path)
|
||||
except:
|
||||
log.warn("failed to run-parts in %s" % runparts_path)
|
||||
raise
|
30
cloudinit/CloudConfig/cc_scripts_per_instance.py
Normal file
30
cloudinit/CloudConfig/cc_scripts_per_instance.py
Normal file
@ -0,0 +1,30 @@
|
||||
# vi: ts=4 expandtab
|
||||
#
|
||||
# Copyright (C) 2011 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
|
||||
from cloudinit.CloudConfig import per_once, per_always, per_instance
|
||||
from cloudinit import get_cpath, get_ipath_cur
|
||||
|
||||
frequency = per_instance
|
||||
runparts_path = "%s/%s" % (get_cpath(), "scripts/per-instance")
|
||||
|
||||
def handle(name,cfg,cloud,log,args):
|
||||
try:
|
||||
util.runparts(runparts_path)
|
||||
except:
|
||||
log.warn("failed to run-parts in %s" % runparts_path)
|
||||
raise
|
30
cloudinit/CloudConfig/cc_scripts_per_once.py
Normal file
30
cloudinit/CloudConfig/cc_scripts_per_once.py
Normal file
@ -0,0 +1,30 @@
|
||||
# vi: ts=4 expandtab
|
||||
#
|
||||
# Copyright (C) 2011 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
|
||||
from cloudinit.CloudConfig import per_once, per_always, per_instance
|
||||
from cloudinit import get_cpath, get_ipath_cur
|
||||
|
||||
frequency = per_once
|
||||
runparts_path = "%s/%s" % (get_cpath(), "scripts/per-once")
|
||||
|
||||
def handle(name,cfg,cloud,log,args):
|
||||
try:
|
||||
util.runparts(runparts_path)
|
||||
except:
|
||||
log.warn("failed to run-parts in %s" % runparts_path)
|
||||
raise
|
30
cloudinit/CloudConfig/cc_scripts_user.py
Normal file
30
cloudinit/CloudConfig/cc_scripts_user.py
Normal file
@ -0,0 +1,30 @@
|
||||
# vi: ts=4 expandtab
|
||||
#
|
||||
# Copyright (C) 2011 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
|
||||
from cloudinit.CloudConfig import per_once, per_always, per_instance
|
||||
from cloudinit import get_cpath, get_ipath_cur
|
||||
|
||||
frequency = per_instance
|
||||
runparts_path = "%s/%s" % (get_ipath_cur(), "scripts")
|
||||
|
||||
def handle(name,cfg,cloud,log,args):
|
||||
try:
|
||||
util.runparts(runparts_path)
|
||||
except:
|
||||
log.warn("failed to run-parts in %s" % runparts_path)
|
||||
raise
|
@ -20,6 +20,7 @@
|
||||
|
||||
varlibdir = '/var/lib/cloud'
|
||||
cur_instance_link = varlibdir + "/instance"
|
||||
boot_finished = cur_instance_link + "/boot-finished"
|
||||
system_config = '/etc/cloud/cloud.cfg'
|
||||
seeddir = varlibdir + "/seed"
|
||||
cfg_env_name = "CLOUD_CFG"
|
||||
@ -509,10 +510,13 @@ def initfs():
|
||||
util.chownbyname(log_file, u, g)
|
||||
|
||||
def purge_cache():
|
||||
rmlist = ( boot_finished , cur_instance_link )
|
||||
for f in rmlist:
|
||||
try:
|
||||
os.unlink(cur_instance_link)
|
||||
os.unlink(f)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT: return(False)
|
||||
if e.errno == errno.ENOENT: continue
|
||||
return(False)
|
||||
except:
|
||||
return(False)
|
||||
return(True)
|
||||
|
@ -127,6 +127,16 @@ def getkeybyid(keyid,keyserver):
|
||||
args=['sh', '-c', shcmd, "export-gpg-keyid", keyid, keyserver]
|
||||
return(subp(args)[0])
|
||||
|
||||
def runparts(dirp, skip_no_exist=True):
|
||||
if skip_no_exist and not os.path.isdir(dirp): return
|
||||
|
||||
cmd = [ 'run-parts', '--regex', '.*', dirp ]
|
||||
sp = subprocess.Popen(cmd)
|
||||
sp.communicate()
|
||||
if sp.returncode is not 0:
|
||||
raise subprocess.CalledProcessError(sp.returncode,cmd)
|
||||
return
|
||||
|
||||
def subp(args, input=None):
|
||||
s_in = None
|
||||
if input is not None:
|
||||
|
@ -21,6 +21,15 @@ cloud_config_modules:
|
||||
- runcmd
|
||||
- byobu
|
||||
|
||||
cloud_final_modules:
|
||||
- scripts-per-once
|
||||
- scripts-per-boot
|
||||
- scripts-per-instance
|
||||
- scripts-user
|
||||
- keys-to-console
|
||||
- phone-home
|
||||
- final-message
|
||||
|
||||
## logging.cfg contains info on logging output for cloud-init
|
||||
#include logging.cfg
|
||||
|
||||
|
@ -286,3 +286,9 @@ resize_rootfs: True
|
||||
# appropriately to its value
|
||||
# if not set, it will set hostname from the cloud metadata
|
||||
# default: None
|
||||
|
||||
# final_message
|
||||
# default: cloud-init boot finished at $TIMESTAMP. Up $UPTIME seconds
|
||||
# this message is written by cloud-final when the system is finished
|
||||
# its first boot
|
||||
final_message: "The system is finally up, after $UPTIME seconds"
|
||||
|
@ -35,6 +35,9 @@
|
||||
obj.pkl
|
||||
handlers/
|
||||
data/ # just a per-instance data location to be used
|
||||
boot-finished
|
||||
# this file indicates when "boot" is finished
|
||||
# it is created by the 'final_message' cloud-config
|
||||
|
||||
- sem/
|
||||
scripts.once
|
||||
|
10
upstart/cloud-final.conf
Normal file
10
upstart/cloud-final.conf
Normal file
@ -0,0 +1,10 @@
|
||||
# cloud-final.conf - run "final" jobs
|
||||
# this runs around traditional "rc.local" time.
|
||||
# and after all cloud-config jobs are run
|
||||
description "execute cloud user/final scripts"
|
||||
|
||||
start on (stopped rc RUNLEVEL=[2345] and stopped cloud-config)
|
||||
console output
|
||||
task
|
||||
|
||||
exec cloud-init-cfg all cloud_final
|
@ -1,28 +0,0 @@
|
||||
# cloud-run-user-script - runs user scripts found in user-data, that are
|
||||
# stored in /var/lib/cloud/scripts by the initial cloudinit upstart job
|
||||
description "execute cloud user scripts"
|
||||
|
||||
start on (stopped rc RUNLEVEL=[2345] and stopped cloud-config)
|
||||
console output
|
||||
task
|
||||
|
||||
script
|
||||
bd=/var/lib/cloud
|
||||
toks="
|
||||
${bd}/scripts/per-once:once:cloud-scripts-per-once
|
||||
${bd}/scripts/per-boot:always:cloud-scripts-per-boot
|
||||
${bd}/scripts/per-instance:once-per-instance:cloud-scripts-per-instance
|
||||
${bd}/instance/scripts:once-per-instance:user-scripts
|
||||
"
|
||||
oifs=${IFS}
|
||||
errors=""
|
||||
for tok in ${toks}; do
|
||||
IFS=":"; set -- ${tok}; IFS=${oifs}
|
||||
dir=${1}; per=${2}; name=${3}
|
||||
[ -d "${dir}" ] || continue
|
||||
cloud-init-run-module "${per}" "${name}" execute \
|
||||
run-parts --regex '.*' "$dir" || errors="${errors} ${name}"
|
||||
done
|
||||
errors=${errors# }
|
||||
[ -z "${errors}" ] || { echo "errors executing ${errors}" 1>&2; exit 1; }
|
||||
end script
|
Loading…
x
Reference in New Issue
Block a user