Skip to content

Instantly share code, notes, and snippets.

@pshchelo
Created May 5, 2017 12:11
Show Gist options
  • Save pshchelo/378f3c4e7d18441878b9652e9478233f to your computer and use it in GitHub Desktop.
Save pshchelo/378f3c4e7d18441878b9652e9478233f to your computer and use it in GitHub Desktop.
Generate configdrive suitable for ironic in pure Python
#!/usr/bin/env python
import base64
import contextlib
import gzip
import os
import sys
import StringIO
import pycdlib # GNU LGPL v2.1 - not possible to include in Apache 2.0-licensed code :(
"""Generate configdrive from prepared on-disk directory."""
# This should be possible to generalize and populate the iso from filenames and their content
# w/o reading them from disk, purely from Python data structure of lists/dicts/strings
def populate_iso(dirname, iso):
for root, dirs, files in os.walk(dirname, topdown=True):
relroot = os.path.relpath(root, dirname)
if relroot == '.':
relroot = ''
for d in dirs:
iso.add_directory('/%s' % os.path.join(relroot, d),
rr_name=d,
joliet_path='/%s' % os.path.join(relroot, d))
for f in files:
iso.add_file(os.path.join(root, f),
'/%s.;1' % os.path.join(relroot, f),
rr_name=f,
joliet_path='/%s' % os.path.join(relroot, f))
def create_iso(dirname, fileobj):
with contextlib.closing(pycdlib.PyCdlib()) as iso:
# these settings are mostly copied from 'genisoimage' arguments OpenStack Nova uses
# to create the configdrive ISO
# maximum interchange_level is choosen to hopefully accomodate for some of those options
# (leading dots etc).
# Volume label is what configdrive is expected to have by cloud-init,
# but currently mounting this shows volume label padded with some symbols.
iso.new(interchange_level=4,
joliet=True,
rock_ridge='1.09',
vol_ident='config-2')
populate_iso(dirname, iso)
iso.write_fp(fileobj)
def create_configdrive(dirname, outfile):
"""Create a configdrive from directory.
The resulting file is written in base64-encoded gzipped ISO format
suitable to paste into instance_info of ironic node or
to serving it from HTTP for the same sake.
"""
with contextlib.closing(StringIO.StringIO()) as gzip_fp:
with gzip.GzipFile(fileobj=gzip_fp, mode='w') as g:
with contextlib.closing(StringIO.StringIO()) as iso_fp:
create_iso(dirname, iso_fp)
g.write(iso_fp.getvalue())
with open(outfile, 'w') as out:
out.write(base64.b64encode(gzip_fp.getvalue()))
def main():
if len(sys.argv) != 3:
print('Usage: %s <DIRNAME> <OUTPUT-FILE-NAME>' % sys.argv[0])
exit(1)
create_configdrive(*sys.argv[1:])
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment