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):
try:
cloudinit.log.info("looking at %s/user-data.raw" % self.cachedir)
udf = open(self.cachedir + "/user-data.raw")
self.userdata_raw = udf.read()
udf.close()
@ -132,7 +133,7 @@ class DataSourceEc2(DataSource.DataSource):
(time.strftime("%H:%M:%S"), x+1, sleeps, reason))
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))
return False

View File

@ -26,7 +26,8 @@ starts_with_mappings={
'#!' : 'text/x-shellscript',
'#cloud-config' : 'text/cloud-config',
'#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

View File

@ -25,6 +25,7 @@ cachedir = datadir + '/cache'
userdata_raw = datadir + '/user-data.txt'
userdata = datadir + '/user-data.txt.i'
user_scripts_dir = datadir + "/scripts"
boothooks_dir = datadir + "/boothooks"
cloud_config = datadir + '/cloud-config.txt'
#cloud_config = '/tmp/cloud-config.txt'
data_source_cache = cachedir + '/obj.pkl'
@ -174,7 +175,8 @@ class CloudInit:
'text/x-shellscript' : self.handle_user_script,
'text/cloud-config' : self.handle_cloud_config,
'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.cfg=self.read_cfg()
@ -412,6 +414,39 @@ class CloudInit:
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):
return(self.datasource.get_public_ssh_keys())

View File

@ -25,7 +25,8 @@ starts_with_mappings={
'#!' : 'text/x-shellscript',
'#cloud-config' : 'text/cloud-config',
'#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):