add 'cloud-boothook' type

if user data is of type text/cloud-boothook, or begins with
#cloud-boothook, then assume it to be code to be executed.

Boothooks are a very simple format.  Basically, its a one line header
('#cloud-config\n') and then executable payload.

The executable payload is written to a file, then that file is executed
at the time it is read.  The file is left in 
/var/lib/cloud/data/boothooks

There is no "first-time-only" protection.  If running only once is
desired, the boothook must handle that itself.
This commit is contained in:
Scott Moser 2010-06-18 00:23:25 -04:00
parent 22bb3adc5d
commit 99bbf6f217
4 changed files with 42 additions and 4 deletions

View File

@ -40,6 +40,7 @@ class DataSourceEc2(DataSource.DataSource):
def get_data(self): def get_data(self):
try: try:
cloudinit.log.info("looking at %s/user-data.raw" % self.cachedir)
udf = open(self.cachedir + "/user-data.raw") udf = open(self.cachedir + "/user-data.raw")
self.userdata_raw = udf.read() self.userdata_raw = udf.read()
udf.close() udf.close()
@ -132,7 +133,7 @@ class DataSourceEc2(DataSource.DataSource):
(time.strftime("%H:%M:%S"), x+1, sleeps, reason)) (time.strftime("%H:%M:%S"), x+1, sleeps, reason))
time.sleep(sleeptime) time.sleep(sleeptime)
log.critical("giving up on md after %i seconds\n" % cloudinit.log.critical("giving up on md after %i seconds\n" %
int(time.time()-starttime)) int(time.time()-starttime))
return False return False

View File

@ -26,7 +26,8 @@ starts_with_mappings={
'#!' : 'text/x-shellscript', '#!' : 'text/x-shellscript',
'#cloud-config' : 'text/cloud-config', '#cloud-config' : 'text/cloud-config',
'#upstart-job' : 'text/upstart-job', '#upstart-job' : 'text/upstart-job',
'#part-handler' : 'text/part-handler' '#part-handler' : 'text/part-handler',
'#cloud-boothook' : 'text/cloud-boothook'
} }
# if 'str' is compressed return decompressed otherwise return it # if 'str' is compressed return decompressed otherwise return it

View File

@ -25,6 +25,7 @@ cachedir = datadir + '/cache'
userdata_raw = datadir + '/user-data.txt' userdata_raw = datadir + '/user-data.txt'
userdata = datadir + '/user-data.txt.i' userdata = datadir + '/user-data.txt.i'
user_scripts_dir = datadir + "/scripts" user_scripts_dir = datadir + "/scripts"
boothooks_dir = datadir + "/boothooks"
cloud_config = datadir + '/cloud-config.txt' cloud_config = datadir + '/cloud-config.txt'
#cloud_config = '/tmp/cloud-config.txt' #cloud_config = '/tmp/cloud-config.txt'
data_source_cache = cachedir + '/obj.pkl' data_source_cache = cachedir + '/obj.pkl'
@ -174,7 +175,8 @@ class CloudInit:
'text/x-shellscript' : self.handle_user_script, 'text/x-shellscript' : self.handle_user_script,
'text/cloud-config' : self.handle_cloud_config, 'text/cloud-config' : self.handle_cloud_config,
'text/upstart-job' : self.handle_upstart_job, 'text/upstart-job' : self.handle_upstart_job,
'text/part-handler' : self.handle_handler 'text/part-handler' : self.handle_handler,
'text/cloud-boothook' : self.handle_cloud_boothook
} }
self.sysconfig=sysconfig self.sysconfig=sysconfig
self.cfg=self.read_cfg() self.cfg=self.read_cfg()
@ -412,6 +414,39 @@ class CloudInit:
self.cloud_config_str+="\n#%s\n%s" % (filename,payload) self.cloud_config_str+="\n#%s\n%s" % (filename,payload)
def handle_cloud_boothook(self,data,ctype,filename,payload):
if ctype == "__end__": return
if ctype == "__begin__": return
filename=filename.replace(os.sep,'_')
prefix="#cloud-boothooks"
dos=False
start = 0
if payload.startswith(prefix):
start = len(prefix)+1
if payload[start] == '\r':
start=start+1
dos = True
else:
if payload.find('\r\n',0,100) >= 0:
dos = True
if dos:
payload=payload[start:].replace('\r\n','\n')
elif start != 0:
payload=payload[start:]
filepath = "%s/%s" % (boothooks_dir,filename)
util.write_file(filepath, payload, 0700)
try:
ret = subprocess.check_call([filepath])
except subprocess.CalledProcessError as e:
log.error("boothooks script %s returned %i" %
(filepath,e.returncode))
except Exception as e:
log.error("boothooks unknown exception %s when running %s" %
(e,filepath))
def get_public_ssh_keys(self): def get_public_ssh_keys(self):
return(self.datasource.get_public_ssh_keys()) return(self.datasource.get_public_ssh_keys())

View File

@ -25,7 +25,8 @@ starts_with_mappings={
'#!' : 'text/x-shellscript', '#!' : 'text/x-shellscript',
'#cloud-config' : 'text/cloud-config', '#cloud-config' : 'text/cloud-config',
'#upstart-job' : 'text/upstart-job', '#upstart-job' : 'text/upstart-job',
'#part-handler' : 'text/part-handler' '#part-handler' : 'text/part-handler',
'#cloud-boothook' : 'text/cloud-boothook'
} }
def get_type(fname,deftype): def get_type(fname,deftype):