Make SmartOS script handling self-contained in datasource.
This commit is contained in:
parent
c8d4265b08
commit
b77cde544d
@ -36,6 +36,7 @@ from cloudinit import util
|
|||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import serial
|
import serial
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -166,8 +167,8 @@ class DataSourceSmartOS(sources.DataSource):
|
|||||||
u_script = md.get('user-script')
|
u_script = md.get('user-script')
|
||||||
u_script_f = "%s/99_user_script" % self.user_script_d
|
u_script_f = "%s/99_user_script" % self.user_script_d
|
||||||
u_script_l = "%s/user-script" % LEGACY_USER_D
|
u_script_l = "%s/user-script" % LEGACY_USER_D
|
||||||
util.write_content(u_script, u_script_f, link=u_script_l,
|
write_boot_content(u_script, u_script_f, link=u_script_l, shebang=True,
|
||||||
executable=True)
|
mode=0700)
|
||||||
|
|
||||||
# @datadictionary: This key has no defined format, but its value
|
# @datadictionary: This key has no defined format, but its value
|
||||||
# is written to the file /var/db/mdata-user-data on each boot prior
|
# is written to the file /var/db/mdata-user-data on each boot prior
|
||||||
@ -176,7 +177,7 @@ class DataSourceSmartOS(sources.DataSource):
|
|||||||
# the machine to be consumed by the user-script when it runs.
|
# the machine to be consumed by the user-script when it runs.
|
||||||
u_data = md.get('legacy-user-data')
|
u_data = md.get('legacy-user-data')
|
||||||
u_data_f = "%s/mdata-user-data" % LEGACY_USER_D
|
u_data_f = "%s/mdata-user-data" % LEGACY_USER_D
|
||||||
util.write_content(u_data, u_data_f)
|
write_boot_content(u_data, u_data_f)
|
||||||
|
|
||||||
# Handle the cloud-init regular meta
|
# Handle the cloud-init regular meta
|
||||||
if not md['local-hostname']:
|
if not md['local-hostname']:
|
||||||
@ -312,6 +313,62 @@ def dmi_data():
|
|||||||
return (sys_uuid.lower().strip(), sys_type.strip())
|
return (sys_uuid.lower().strip(), sys_type.strip())
|
||||||
|
|
||||||
|
|
||||||
|
def write_boot_content(content, content_f, link=None, shebang=False, mode=0400):
|
||||||
|
"""
|
||||||
|
Write the content to content_f. Under the following rules:
|
||||||
|
1. If no content, remove the file
|
||||||
|
2. Write the content
|
||||||
|
3. If executable and no file magic, add it
|
||||||
|
4. If there is a link, create it
|
||||||
|
|
||||||
|
@param content: what to write
|
||||||
|
@param content_f: the file name
|
||||||
|
@param backup_d: the directory to save the backup at
|
||||||
|
@param link: if defined, location to create a symlink to
|
||||||
|
@param shebang: if no file magic, set shebang
|
||||||
|
@param mode: file mode
|
||||||
|
|
||||||
|
Becuase of the way that Cloud-init executes scripts (no shell),
|
||||||
|
a script will fail to execute if does not have a magic bit (shebang) set
|
||||||
|
for the file. If shebang=True, then the script will be checked for a magic
|
||||||
|
bit and to the SmartOS default of assuming that bash.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not content and os.path.exists(content_f):
|
||||||
|
os.unlink(content_f)
|
||||||
|
if link and os.path.islink(link):
|
||||||
|
os.unlink(link)
|
||||||
|
if not content:
|
||||||
|
return
|
||||||
|
|
||||||
|
util.write_file(content_f, content, mode=mode)
|
||||||
|
|
||||||
|
if shebang:
|
||||||
|
try:
|
||||||
|
cmd = ["file", "--brief", "--mime-type", content_f]
|
||||||
|
(f_type, _err) = util.subp(cmd)
|
||||||
|
LOG.debug("script %s mime type is %s" % (content_f, f_type))
|
||||||
|
line_one = content.splitlines()[0]
|
||||||
|
if f_type.strip() == "text/plain" and "#!" not in line_one:
|
||||||
|
new_content = "\n".join(["#!/bin/bash", content])
|
||||||
|
util.write_file(content_f, new_content, mode=mode)
|
||||||
|
LOG.debug("added shebang to file %s" % content_f)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
util.logexc(LOG, ("Failed to identify script type for %s" %
|
||||||
|
content_f, e))
|
||||||
|
|
||||||
|
if link:
|
||||||
|
try:
|
||||||
|
if os.path.islink(link):
|
||||||
|
os.unlink(link)
|
||||||
|
if content and os.path.exists(content_f):
|
||||||
|
util.ensure_dir(os.path.dirname(link))
|
||||||
|
os.symlink(content_f, link)
|
||||||
|
except IOError as e:
|
||||||
|
util.logexc(LOG, "failed establishing content link", e)
|
||||||
|
|
||||||
|
|
||||||
# Used to match classes to dependencies
|
# Used to match classes to dependencies
|
||||||
datasources = [
|
datasources = [
|
||||||
(DataSourceSmartOS, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
|
(DataSourceSmartOS, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
|
||||||
|
@ -1907,75 +1907,3 @@ def expand_dotted_devname(dotted):
|
|||||||
return toks
|
return toks
|
||||||
else:
|
else:
|
||||||
return (dotted, None)
|
return (dotted, None)
|
||||||
|
|
||||||
|
|
||||||
def write_executable_content(script, script_f):
|
|
||||||
"""
|
|
||||||
This writes executable content and ensures that the shebang
|
|
||||||
exists.
|
|
||||||
"""
|
|
||||||
write_file(script_f, script, mode=0700)
|
|
||||||
try:
|
|
||||||
cmd = ["file", "--brief", "--mime-type", script_f]
|
|
||||||
(f_type, _err) = subp(cmd)
|
|
||||||
|
|
||||||
LOG.debug("script %s mime type is %s" % (script_f, f_type))
|
|
||||||
|
|
||||||
# if the magic is text/plain, re-write with the shebang
|
|
||||||
if f_type.strip() == "text/plain":
|
|
||||||
with open(script_f, 'w') as f:
|
|
||||||
f.write("#!/bin/bash\n")
|
|
||||||
f.write(script)
|
|
||||||
LOG.debug("added shebang to file %s" % script_f)
|
|
||||||
|
|
||||||
except ProcessExecutionError as e:
|
|
||||||
logexc(LOG, "Failed to identify script type for %s" % script_f, e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
except IOError as e:
|
|
||||||
logexc(LOG, "Failed to add shebang to file %s" % script_f, e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def write_content(content, content_f, link=None,
|
|
||||||
executable=False):
|
|
||||||
"""
|
|
||||||
Write the content to content_f. Under the following rules:
|
|
||||||
1. Backup previous content_f
|
|
||||||
2. Write the contente
|
|
||||||
3. If no content, remove the file
|
|
||||||
4. If there is a link, create it
|
|
||||||
|
|
||||||
@param content: what to write
|
|
||||||
@param content_f: the file name
|
|
||||||
@param backup_d: the directory to save the backup at
|
|
||||||
@param link: if defined, location to create a symlink to
|
|
||||||
@param executable: is the file executable
|
|
||||||
"""
|
|
||||||
|
|
||||||
if content:
|
|
||||||
if not executable:
|
|
||||||
write_file(content_f, content, mode=0400)
|
|
||||||
else:
|
|
||||||
w = write_executable_content(content, content_f)
|
|
||||||
if not w:
|
|
||||||
LOG.debug("failed to write file to %s" % content_f)
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not content and os.path.exists(content_f):
|
|
||||||
os.unlink(content_f)
|
|
||||||
|
|
||||||
if link:
|
|
||||||
try:
|
|
||||||
if os.path.islink(link):
|
|
||||||
os.unlink(link)
|
|
||||||
if content and os.path.exists(content_f):
|
|
||||||
ensure_dir(os.path.dirname(link))
|
|
||||||
os.symlink(content_f, link)
|
|
||||||
except IOError as e:
|
|
||||||
logexc(LOG, "failed establishing content link", e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user