New version of salt-formula from Saltstack
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.3KB

  1. # -*- coding: utf-8 -*-
  2. import json
  3. import logging
  4. import os
  5. import shutil
  6. import six
  7. import tempfile
  8. import yaml
  9. from oslo_utils import uuidutils
  10. from oslo_utils import fileutils
  11. from oslo_concurrency import processutils
  12. class ConfigDriveBuilder(object):
  13. """Build config drives, optionally as a context manager."""
  14. def __init__(self, image_file):
  15. self.image_file = image_file
  16. self.mdfiles=[]
  17. def __enter__(self):
  18. fileutils.delete_if_exists(self.image_file)
  19. return self
  20. def __exit__(self, exctype, excval, exctb):
  21. self.make_drive()
  22. def add_file(self, path, data):
  23. self.mdfiles.append((path, data))
  24. def _add_file(self, basedir, path, data):
  25. filepath = os.path.join(basedir, path)
  26. dirname = os.path.dirname(filepath)
  27. fileutils.ensure_tree(dirname)
  28. with open(filepath, 'wb') as f:
  29. if isinstance(data, six.text_type):
  30. data = data.encode('utf-8')
  31. f.write(data)
  32. def _write_md_files(self, basedir):
  33. for data in self.mdfiles:
  34. self._add_file(basedir, data[0], data[1])
  35. def _make_iso9660(self, path, tmpdir):
  36. processutils.execute('mkisofs',
  37. '-o', path,
  38. '-ldots',
  39. '-allow-lowercase',
  40. '-allow-multidot',
  41. '-l',
  42. '-V', 'config-2',
  43. '-r',
  44. '-J',
  45. '-quiet',
  46. tmpdir,
  47. attempts=1,
  48. run_as_root=False)
  49. def make_drive(self):
  50. """Make the config drive.
  51. :raises ProcessExecuteError if a helper process has failed.
  52. """
  53. try:
  54. tmpdir = tempfile.mkdtemp()
  55. self._write_md_files(tmpdir)
  56. self._make_iso9660(self.image_file, tmpdir)
  57. finally:
  58. shutil.rmtree(tmpdir)
  59. def generate(
  60. dst,
  61. hostname,
  62. domainname,
  63. instance_id=None,
  64. user_data=None,
  65. network_data=None,
  66. saltconfig=None
  67. ):
  68. ''' Generate config drive
  69. :param dst: destination file to place config drive.
  70. :param hostname: hostname of Instance.
  71. :param domainname: instance domain.
  72. :param instance_id: UUID of the instance.
  73. :param user_data: custom user data dictionary. type: json
  74. :param network_data: custom network info dictionary. type: json
  75. :param saltconfig: salt minion configuration. type: json
  76. '''
  77. instance_md = {}
  78. instance_md['uuid'] = instance_id or uuidutils.generate_uuid()
  79. instance_md['hostname'] = '%s.%s' % (hostname, domainname)
  80. instance_md['name'] = hostname
  81. if user_data:
  82. user_data = '#cloud-config\n\n' + yaml.dump(yaml.load(user_data), default_flow_style=False)
  83. if saltconfig:
  84. user_data += yaml.dump(yaml.load(str(saltconfig)), default_flow_style=False)
  85. data = json.dumps(instance_md)
  86. with ConfigDriveBuilder(dst) as cfgdrive:
  87. cfgdrive.add_file('openstack/latest/meta_data.json', data)
  88. if user_data:
  89. cfgdrive.add_file('openstack/latest/user_data', user_data)
  90. if network_data:
  91. cfgdrive.add_file('openstack/latest/network_data.json', network_data)
  92. cfgdrive.add_file('openstack/latest/vendor_data.json', '{}')
  93. cfgdrive.add_file('openstack/latest/vendor_data2.json', '{}')