Merge "Inject guest conf files to configurable location"
This commit is contained in:
commit
ee4b194a53
@ -1,4 +1,4 @@
|
|||||||
These conf files are read and used by the guest to provide extra
|
These conf files are read and used by the guest to provide extra
|
||||||
information to the guest. The first example of this is the
|
information to the guest. The first example of this is the
|
||||||
guest_info which will have the uuid of the instance so that
|
guest_info.conf which will have the uuid of the instance so that
|
||||||
the guest can report back things to the infra.
|
the guest can report back things to the infra.
|
||||||
|
@ -1 +0,0 @@
|
|||||||
# Arbitrary information that the guest needs to work
|
|
1
etc/trove/conf.d/guest_info.conf
Normal file
1
etc/trove/conf.d/guest_info.conf
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Guest-specific information injected by the taskmanager
|
@ -194,7 +194,11 @@ pydev_debug = disabled
|
|||||||
#pydev_path = <path>
|
#pydev_path = <path>
|
||||||
|
|
||||||
# ================= Guestagent related ========================
|
# ================= Guestagent related ========================
|
||||||
#guest_config = $pybasedir/etc/trove/trove-guestagent.conf.sample
|
#guest_config = /etc/trove/trove-guestagent.conf
|
||||||
|
# Use 'guest_info = /etc/guest_info' for pre-Kilo compatibility
|
||||||
|
#guest_info = guest_info.conf
|
||||||
|
# Use 'injected_config_location = /etc/trove' for pre-Kilo compatibility
|
||||||
|
#injected_config_location = /etc/trove/conf.d
|
||||||
#cloudinit_location = /etc/trove/cloudinit
|
#cloudinit_location = /etc/trove/cloudinit
|
||||||
|
|
||||||
# ================= Security groups related ========================
|
# ================= Security groups related ========================
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright 2011 OpenStack Foundation
|
# copyright 2011 OpenStack Foundation
|
||||||
# Copyright 2014 Rackspace Hosting
|
# Copyright 2014 Rackspace Hosting
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
@ -342,9 +342,18 @@ common_opts = [
|
|||||||
'expression.'),
|
'expression.'),
|
||||||
cfg.StrOpt('cloudinit_location', default='/etc/trove/cloudinit',
|
cfg.StrOpt('cloudinit_location', default='/etc/trove/cloudinit',
|
||||||
help='Path to folder with cloudinit scripts.'),
|
help='Path to folder with cloudinit scripts.'),
|
||||||
|
cfg.StrOpt('injected_config_location', default='/etc/trove/conf.d',
|
||||||
|
help='Path to folder on the Guest where config files will be '
|
||||||
|
'injected during instance creation.'),
|
||||||
cfg.StrOpt('guest_config',
|
cfg.StrOpt('guest_config',
|
||||||
default='$pybasedir/etc/trove/trove-guestagent.conf.sample',
|
default='/etc/trove/trove-guestagent.conf',
|
||||||
help='Path to the Guest Agent config file.'),
|
help='Path to the Guest Agent config file to be injected '
|
||||||
|
'during instance creation.'),
|
||||||
|
cfg.StrOpt('guest_info',
|
||||||
|
default='guest_info.conf',
|
||||||
|
help='The guest info filename found in the injected config '
|
||||||
|
'location. If a full path is specified then it will '
|
||||||
|
'be used as the path to the guest info file'),
|
||||||
cfg.DictOpt('datastore_registry_ext', default=dict(),
|
cfg.DictOpt('datastore_registry_ext', default=dict(),
|
||||||
help='Extension for default datastore managers. '
|
help='Extension for default datastore managers. '
|
||||||
'Allows the use of custom managers for each of '
|
'Allows the use of custom managers for each of '
|
||||||
|
@ -217,6 +217,32 @@ class ClusterTasks(Cluster):
|
|||||||
|
|
||||||
|
|
||||||
class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
||||||
|
def _get_injected_files(self, datastore_manager):
|
||||||
|
injected_config_location = CONF.get('injected_config_location')
|
||||||
|
guest_info = CONF.get('guest_info')
|
||||||
|
|
||||||
|
if ('/' in guest_info):
|
||||||
|
# Set guest_info_file to exactly guest_info from the conf file.
|
||||||
|
# This should be /etc/guest_info for pre-Kilo compatibility.
|
||||||
|
guest_info_file = guest_info
|
||||||
|
else:
|
||||||
|
guest_info_file = os.path.join(injected_config_location,
|
||||||
|
guest_info)
|
||||||
|
|
||||||
|
files = {guest_info_file: (
|
||||||
|
"[DEFAULT]\n"
|
||||||
|
"guest_id=%s\n"
|
||||||
|
"datastore_manager=%s\n"
|
||||||
|
"tenant_id=%s\n"
|
||||||
|
% (self.id, datastore_manager, self.tenant_id))}
|
||||||
|
|
||||||
|
if os.path.isfile(CONF.get('guest_config')):
|
||||||
|
with open(CONF.get('guest_config'), "r") as f:
|
||||||
|
files[os.path.join(injected_config_location,
|
||||||
|
"trove-guestagent.conf")] = f.read()
|
||||||
|
|
||||||
|
return files
|
||||||
|
|
||||||
def create_instance(self, flavor, image_id, databases, users,
|
def create_instance(self, flavor, image_id, databases, users,
|
||||||
datastore_manager, packages, volume_size,
|
datastore_manager, packages, volume_size,
|
||||||
backup_id, availability_zone, root_password, nics,
|
backup_id, availability_zone, root_password, nics,
|
||||||
@ -242,6 +268,8 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
|||||||
LOG.debug("Successfully created security group for "
|
LOG.debug("Successfully created security group for "
|
||||||
"instance: %s" % self.id)
|
"instance: %s" % self.id)
|
||||||
|
|
||||||
|
files = self._get_injected_files(datastore_manager)
|
||||||
|
|
||||||
if use_heat:
|
if use_heat:
|
||||||
volume_info = self._create_server_volume_heat(
|
volume_info = self._create_server_volume_heat(
|
||||||
flavor,
|
flavor,
|
||||||
@ -249,7 +277,8 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
|||||||
datastore_manager,
|
datastore_manager,
|
||||||
volume_size,
|
volume_size,
|
||||||
availability_zone,
|
availability_zone,
|
||||||
nics)
|
nics,
|
||||||
|
files)
|
||||||
elif use_nova_server_volume:
|
elif use_nova_server_volume:
|
||||||
volume_info = self._create_server_volume(
|
volume_info = self._create_server_volume(
|
||||||
flavor['id'],
|
flavor['id'],
|
||||||
@ -258,7 +287,8 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
|||||||
datastore_manager,
|
datastore_manager,
|
||||||
volume_size,
|
volume_size,
|
||||||
availability_zone,
|
availability_zone,
|
||||||
nics)
|
nics,
|
||||||
|
files)
|
||||||
else:
|
else:
|
||||||
volume_info = self._create_server_volume_individually(
|
volume_info = self._create_server_volume_individually(
|
||||||
flavor['id'],
|
flavor['id'],
|
||||||
@ -267,7 +297,8 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
|||||||
datastore_manager,
|
datastore_manager,
|
||||||
volume_size,
|
volume_size,
|
||||||
availability_zone,
|
availability_zone,
|
||||||
nics)
|
nics,
|
||||||
|
files)
|
||||||
|
|
||||||
config = self._render_config(flavor)
|
config = self._render_config(flavor)
|
||||||
config_overrides = self._render_override_config(flavor,
|
config_overrides = self._render_override_config(flavor,
|
||||||
@ -454,11 +485,10 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
|||||||
|
|
||||||
def _create_server_volume(self, flavor_id, image_id, security_groups,
|
def _create_server_volume(self, flavor_id, image_id, security_groups,
|
||||||
datastore_manager, volume_size,
|
datastore_manager, volume_size,
|
||||||
availability_zone, nics):
|
availability_zone, nics, files):
|
||||||
LOG.debug("Begin _create_server_volume for id: %s" % self.id)
|
LOG.debug("Begin _create_server_volume for id: %s" % self.id)
|
||||||
try:
|
try:
|
||||||
files, userdata = self._prepare_file_and_userdata(
|
userdata = self._prepare_userdata(datastore_manager)
|
||||||
datastore_manager)
|
|
||||||
name = self.hostname or self.name
|
name = self.hostname or self.name
|
||||||
volume_desc = ("datastore volume for %s" % self.id)
|
volume_desc = ("datastore volume for %s" % self.id)
|
||||||
volume_name = ("datastore-%s" % self.id)
|
volume_name = ("datastore-%s" % self.id)
|
||||||
@ -508,10 +538,9 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
|||||||
return final
|
return final
|
||||||
|
|
||||||
def _create_server_volume_heat(self, flavor, image_id,
|
def _create_server_volume_heat(self, flavor, image_id,
|
||||||
datastore_manager,
|
datastore_manager, volume_size,
|
||||||
volume_size, availability_zone,
|
availability_zone, nics, files):
|
||||||
nics):
|
LOG.debug("Begin _create_server_volume_heat for id: %s" % self.id)
|
||||||
LOG.debug("begin _create_server_volume_heat for id: %s" % self.id)
|
|
||||||
try:
|
try:
|
||||||
client = create_heat_client(self.context)
|
client = create_heat_client(self.context)
|
||||||
tcp_rules_mapping_list = self._build_sg_rules_mapping(CONF.get(
|
tcp_rules_mapping_list = self._build_sg_rules_mapping(CONF.get(
|
||||||
@ -526,7 +555,8 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
|||||||
ifaces=ifaces, ports=ports,
|
ifaces=ifaces, ports=ports,
|
||||||
tcp_rules=tcp_rules_mapping_list,
|
tcp_rules=tcp_rules_mapping_list,
|
||||||
udp_rules=udp_ports_mapping_list,
|
udp_rules=udp_ports_mapping_list,
|
||||||
datastore_manager=datastore_manager)
|
datastore_manager=datastore_manager,
|
||||||
|
files=files)
|
||||||
try:
|
try:
|
||||||
heat_template = heat_template_unicode.encode('utf-8')
|
heat_template = heat_template_unicode.encode('utf-8')
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
@ -604,8 +634,8 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
|||||||
|
|
||||||
def _create_server_volume_individually(self, flavor_id, image_id,
|
def _create_server_volume_individually(self, flavor_id, image_id,
|
||||||
security_groups, datastore_manager,
|
security_groups, datastore_manager,
|
||||||
volume_size,
|
volume_size, availability_zone,
|
||||||
availability_zone, nics):
|
nics, files):
|
||||||
LOG.debug("Begin _create_server_volume_individually for id: %s" %
|
LOG.debug("Begin _create_server_volume_individually for id: %s" %
|
||||||
self.id)
|
self.id)
|
||||||
server = None
|
server = None
|
||||||
@ -616,7 +646,7 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
|||||||
server = self._create_server(flavor_id, image_id, security_groups,
|
server = self._create_server(flavor_id, image_id, security_groups,
|
||||||
datastore_manager,
|
datastore_manager,
|
||||||
block_device_mapping,
|
block_device_mapping,
|
||||||
availability_zone, nics)
|
availability_zone, nics, files)
|
||||||
server_id = server.id
|
server_id = server.id
|
||||||
# Save server ID.
|
# Save server ID.
|
||||||
self.update_db(compute_instance_id=server_id)
|
self.update_db(compute_instance_id=server_id)
|
||||||
@ -707,28 +737,19 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
|||||||
'volumes': created_volumes}
|
'volumes': created_volumes}
|
||||||
return volume_info
|
return volume_info
|
||||||
|
|
||||||
def _prepare_file_and_userdata(self, datastore_manager):
|
def _prepare_userdata(self, datastore_manager):
|
||||||
files = {"/etc/guest_info": ("[DEFAULT]\nguest_id=%s\n"
|
|
||||||
"datastore_manager=%s\n"
|
|
||||||
"tenant_id=%s\n" %
|
|
||||||
(self.id, datastore_manager,
|
|
||||||
self.tenant_id))}
|
|
||||||
if os.path.isfile(CONF.get('guest_config')):
|
|
||||||
with open(CONF.get('guest_config'), "r") as f:
|
|
||||||
files["/etc/trove-guestagent.conf"] = f.read()
|
|
||||||
userdata = None
|
userdata = None
|
||||||
cloudinit = os.path.join(CONF.get('cloudinit_location'),
|
cloudinit = os.path.join(CONF.get('cloudinit_location'),
|
||||||
"%s.cloudinit" % datastore_manager)
|
"%s.cloudinit" % datastore_manager)
|
||||||
if os.path.isfile(cloudinit):
|
if os.path.isfile(cloudinit):
|
||||||
with open(cloudinit, "r") as f:
|
with open(cloudinit, "r") as f:
|
||||||
userdata = f.read()
|
userdata = f.read()
|
||||||
return files, userdata
|
return userdata
|
||||||
|
|
||||||
def _create_server(self, flavor_id, image_id, security_groups,
|
def _create_server(self, flavor_id, image_id, security_groups,
|
||||||
datastore_manager, block_device_mapping,
|
datastore_manager, block_device_mapping,
|
||||||
availability_zone, nics):
|
availability_zone, nics, files={}):
|
||||||
files, userdata = self._prepare_file_and_userdata(
|
userdata = self._prepare_userdata(datastore_manager)
|
||||||
datastore_manager)
|
|
||||||
name = self.hostname or self.name
|
name = self.hostname or self.name
|
||||||
bdmap = block_device_mapping
|
bdmap = block_device_mapping
|
||||||
config_drive = CONF.use_nova_server_config_drive
|
config_drive = CONF.use_nova_server_config_drive
|
||||||
|
@ -34,16 +34,14 @@ Resources:
|
|||||||
AWS::CloudFormation::Init:
|
AWS::CloudFormation::Init:
|
||||||
config:
|
config:
|
||||||
files:
|
files:
|
||||||
/etc/guest_info:
|
{% for file, content in files.iteritems() %}
|
||||||
content:
|
{{ file }}:
|
||||||
Fn::Join:
|
content: |
|
||||||
- ''
|
{{ content | indent(16) }}
|
||||||
- ["[DEFAULT]\nguest_id=", {Ref: InstanceId},
|
|
||||||
"\ndatastore_manager=", {Ref: DatastoreManager},
|
|
||||||
"\ntenant_id=", {Ref: TenantId}]
|
|
||||||
mode: '000644'
|
mode: '000644'
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
|
{% endfor %}
|
||||||
Properties:
|
Properties:
|
||||||
ImageId: {Ref: ImageId}
|
ImageId: {Ref: ImageId}
|
||||||
InstanceType: {Ref: Flavor}
|
InstanceType: {Ref: Flavor}
|
||||||
|
@ -168,7 +168,8 @@ class HeatTemplateLoadTest(testtools.TestCase):
|
|||||||
volume_support=True,
|
volume_support=True,
|
||||||
ifaces=[], ports=[],
|
ifaces=[], ports=[],
|
||||||
tcp_rules=tcp_rules,
|
tcp_rules=tcp_rules,
|
||||||
udp_rules=[])
|
udp_rules=[],
|
||||||
|
files={})
|
||||||
self.assertIsNotNone(output)
|
self.assertIsNotNone(output)
|
||||||
self.assertIn('FromPort: "3306"', output)
|
self.assertIn('FromPort: "3306"', output)
|
||||||
self.assertIn('ToPort: "3309"', output)
|
self.assertIn('ToPort: "3309"', output)
|
||||||
@ -182,7 +183,8 @@ class HeatTemplateLoadTest(testtools.TestCase):
|
|||||||
volume_support=True,
|
volume_support=True,
|
||||||
ifaces=[], ports=[],
|
ifaces=[], ports=[],
|
||||||
tcp_rules=[],
|
tcp_rules=[],
|
||||||
udp_rules=[])
|
udp_rules=[],
|
||||||
|
files={})
|
||||||
self.assertIsNotNone(output)
|
self.assertIsNotNone(output)
|
||||||
self.assertNotIn('- IpProtocol: "tcp"', output)
|
self.assertNotIn('- IpProtocol: "tcp"', output)
|
||||||
self.assertNotIn('- IpProtocol: "udp"', output)
|
self.assertNotIn('- IpProtocol: "udp"', output)
|
||||||
|
@ -226,16 +226,48 @@ class FreshInstanceTasksTest(testtools.TestCase):
|
|||||||
def fake_conf_getter(*args, **kwargs):
|
def fake_conf_getter(*args, **kwargs):
|
||||||
if args[0] == 'guest_config':
|
if args[0] == 'guest_config':
|
||||||
return self.guestconfig
|
return self.guestconfig
|
||||||
|
if args[0] == 'guest_info':
|
||||||
|
return 'guest_info.conf'
|
||||||
|
if args[0] == 'injected_config_location':
|
||||||
|
return '/etc/trove/conf.d'
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
mock_conf.get.side_effect = fake_conf_getter
|
mock_conf.get.side_effect = fake_conf_getter
|
||||||
# execute
|
# execute
|
||||||
server = self.freshinstancetasks._create_server(
|
files = self.freshinstancetasks._get_injected_files("test")
|
||||||
None, None, None, "test", None, None, None)
|
|
||||||
# verify
|
# verify
|
||||||
self.assertTrue('/etc/trove-guestagent.conf' in server.files)
|
self.assertTrue(
|
||||||
self.assertEqual(server.files['/etc/trove-guestagent.conf'],
|
'/etc/trove/conf.d/guest_info.conf' in files)
|
||||||
self.guestconfig_content)
|
self.assertTrue(
|
||||||
|
'/etc/trove/conf.d/trove-guestagent.conf' in files)
|
||||||
|
self.assertEqual(
|
||||||
|
files['/etc/trove/conf.d/trove-guestagent.conf'],
|
||||||
|
self.guestconfig_content)
|
||||||
|
|
||||||
|
@patch('trove.taskmanager.models.CONF')
|
||||||
|
def test_create_instance_guestconfig_compat(self, mock_conf):
|
||||||
|
def fake_conf_getter(*args, **kwargs):
|
||||||
|
if args[0] == 'guest_config':
|
||||||
|
return self.guestconfig
|
||||||
|
if args[0] == 'guest_info':
|
||||||
|
return '/etc/guest_info'
|
||||||
|
if args[0] == 'injected_config_location':
|
||||||
|
return '/etc'
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
mock_conf.get.side_effect = fake_conf_getter
|
||||||
|
# execute
|
||||||
|
files = self.freshinstancetasks._get_injected_files("test")
|
||||||
|
# verify
|
||||||
|
self.assertTrue(
|
||||||
|
'/etc/guest_info' in files)
|
||||||
|
self.assertTrue(
|
||||||
|
'/etc/trove-guestagent.conf' in files)
|
||||||
|
self.assertEqual(
|
||||||
|
files['/etc/trove-guestagent.conf'],
|
||||||
|
self.guestconfig_content)
|
||||||
|
|
||||||
@patch('trove.taskmanager.models.CONF')
|
@patch('trove.taskmanager.models.CONF')
|
||||||
def test_create_instance_with_az_kwarg(self, mock_conf):
|
def test_create_instance_with_az_kwarg(self, mock_conf):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user