
Introduce a configuration option for a directory on the guest where the taskmanager should inject configuration files. During instance creation inject the guest_info and trove-guestagent conf files to the 'injected_config_location'. The default location is /etc/trove/conf.d. Also: - Change the default value for 'guest_config' to remove the risk of overwriting a guest image's conf file with the sample. - Add trove-guestagent.conf injection to heat template. - Add new 'guest_info' option that defaults to "guest_info.conf". Depends-On: I1dffd373da722af55bdea41fead8456bb60c82b2 Co-Authored-By: Denis Makogon <dmakogon@mirantis.com> Co-Authored-By: Duk Loi <duk@tesora.com> DocImpact: This change introduces a new option with a default that affects existing guest images. The guestagent init script for any existing guest image will need to be modified to read the conf files from /etc/trove/conf.d. For backwards compatibility set the injected_config_location to /etc/trove and guest_info to /etc/guest_info. Closes-Bug: 1309030 Change-Id: I1057f4a1b6232332ed4b520dbc7b3bbb04145f73
191 lines
7.8 KiB
Python
191 lines
7.8 KiB
Python
#Licensed under the Apache License, Version 2.0 (the "License");
|
|
#you may not use this file except in compliance with the License.
|
|
#You may obtain a copy of the License at
|
|
#
|
|
#http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
#Unless required by applicable law or agreed to in writing, software
|
|
#distributed under the License is distributed on an "AS IS" BASIS,
|
|
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
#See the License for the specific language governing permissions and
|
|
#limitations under the License.
|
|
|
|
|
|
from mock import Mock
|
|
import testtools
|
|
import re
|
|
|
|
from trove.common import exception
|
|
from trove.common import template
|
|
from trove.common import utils
|
|
from trove.datastore.models import DatastoreVersion
|
|
from trove.tests.unittests.util import util
|
|
|
|
|
|
class TemplateTest(testtools.TestCase):
|
|
def setUp(self):
|
|
super(TemplateTest, self).setUp()
|
|
util.init_db()
|
|
self.env = template.ENV
|
|
self.template = self.env.get_template("mysql/config.template")
|
|
self.flavor_dict = {'ram': 1024, 'name': 'small', 'id': '55'}
|
|
self.server_id = "180b5ed1-3e57-4459-b7a3-2aeee4ac012a"
|
|
|
|
def tearDown(self):
|
|
super(TemplateTest, self).tearDown()
|
|
|
|
def _find_in_template(self, contents, teststr):
|
|
found_group = None
|
|
for line in contents.split('\n'):
|
|
m = re.search('^%s.*' % teststr, line)
|
|
if m:
|
|
found_group = m.group(0)
|
|
return found_group
|
|
|
|
def validate_template(self, contents, teststr, test_flavor, server_id):
|
|
# expected query_cache_size = {{ 8 * flavor_multiplier }}M
|
|
flavor_multiplier = test_flavor['ram'] / 512
|
|
found_group = self._find_in_template(contents, teststr)
|
|
if not found_group:
|
|
raise "Could not find text in template"
|
|
# Check that the last group has been rendered
|
|
memsize = found_group.split(" ")[2]
|
|
self.assertEqual("%sM" % (8 * flavor_multiplier), memsize)
|
|
self.assertIsNotNone(server_id)
|
|
self.assertTrue(server_id > 1)
|
|
|
|
def test_rendering(self):
|
|
rendered = self.template.render(flavor=self.flavor_dict,
|
|
server_id=self.server_id)
|
|
self.validate_template(rendered,
|
|
"query_cache_size",
|
|
self.flavor_dict,
|
|
self.server_id)
|
|
|
|
def test_single_instance_config_rendering(self):
|
|
datastore = Mock(spec=DatastoreVersion)
|
|
datastore.datastore_name = 'MySql'
|
|
datastore.name = 'mysql-5.6'
|
|
datastore.manager = 'mysql'
|
|
config = template.SingleInstanceConfigTemplate(datastore,
|
|
self.flavor_dict,
|
|
self.server_id)
|
|
self.validate_template(config.render(), "query_cache_size",
|
|
self.flavor_dict, self.server_id)
|
|
|
|
def test_renderer_discovers_special_config(self):
|
|
"""Finds our special config file for the version 'mysql-test'."""
|
|
datastore = Mock(spec=DatastoreVersion)
|
|
datastore.datastore_name = 'mysql'
|
|
datastore.name = 'mysql-test'
|
|
datastore.manager = 'mysql'
|
|
config = template.SingleInstanceConfigTemplate(datastore,
|
|
self.flavor_dict,
|
|
self.server_id)
|
|
self.validate_template(config.render(), "hyper",
|
|
{'ram': 0}, self.server_id)
|
|
|
|
def test_replica_source_config_rendering(self):
|
|
datastore = Mock(spec=DatastoreVersion)
|
|
datastore.datastore_name = 'MySql'
|
|
datastore.name = 'mysql-5.6'
|
|
datastore.manager = 'mysql'
|
|
config = template.ReplicaSourceConfigTemplate(datastore,
|
|
self.flavor_dict,
|
|
self.server_id)
|
|
self.assertTrue(self._find_in_template(config.render(), "log_bin"))
|
|
|
|
def test_replica_config_rendering(self):
|
|
datastore = Mock(spec=DatastoreVersion)
|
|
datastore.datastore_name = 'MySql'
|
|
datastore.name = 'mysql-5.6'
|
|
datastore.manager = 'mysql'
|
|
config = template.ReplicaConfigTemplate(datastore,
|
|
self.flavor_dict,
|
|
self.server_id)
|
|
self.assertTrue(self._find_in_template(config.render(), "relay_log"))
|
|
|
|
|
|
class HeatTemplateLoadTest(testtools.TestCase):
|
|
|
|
class FakeTemplate():
|
|
def __init__(self):
|
|
self.name = 'mysql/heat.template'
|
|
|
|
def setUp(self):
|
|
self.default = 'default.heat.template'
|
|
self.orig_1 = utils.ENV.list_templates
|
|
self.orig_2 = utils.ENV.get_template
|
|
super(HeatTemplateLoadTest, self).setUp()
|
|
|
|
def tearDown(self):
|
|
utils.ENV.list_templates = self.orig_1
|
|
utils.ENV.get_template = self.orig_2
|
|
super(HeatTemplateLoadTest, self).tearDown()
|
|
|
|
def test_heat_template_load_with_invalid_datastore(self):
|
|
invalid_datastore = 'mysql-blah'
|
|
self.assertRaises(exception.InvalidDatastoreManager,
|
|
template.load_heat_template,
|
|
invalid_datastore)
|
|
|
|
def test_heat_template_load_non_default(self):
|
|
orig = utils.ENV._load_template
|
|
utils.ENV._load_template = Mock(return_value=self.FakeTemplate())
|
|
mysql_tmpl = template.load_heat_template('mysql')
|
|
self.assertNotEqual(mysql_tmpl.name, self.default)
|
|
utils.ENV._load_template = orig
|
|
|
|
def test_heat_template_load_success(self):
|
|
mysql_tmpl = template.load_heat_template('mysql')
|
|
redis_tmpl = template.load_heat_template('redis')
|
|
cassandra_tmpl = template.load_heat_template('cassandra')
|
|
mongo_tmpl = template.load_heat_template('mongodb')
|
|
percona_tmpl = template.load_heat_template('percona')
|
|
couchbase_tmpl = template.load_heat_template('couchbase')
|
|
self.assertIsNotNone(mysql_tmpl)
|
|
self.assertIsNotNone(redis_tmpl)
|
|
self.assertIsNotNone(cassandra_tmpl)
|
|
self.assertIsNotNone(mongo_tmpl)
|
|
self.assertIsNotNone(percona_tmpl)
|
|
self.assertIsNotNone(couchbase_tmpl)
|
|
self.assertEqual(self.default, mysql_tmpl.name)
|
|
self.assertEqual(self.default, redis_tmpl.name)
|
|
self.assertEqual(self.default, cassandra_tmpl.name)
|
|
self.assertEqual(self.default, mongo_tmpl.name)
|
|
self.assertEqual(self.default, percona_tmpl.name)
|
|
self.assertEqual(self.default, couchbase_tmpl.name)
|
|
|
|
def test_render_templates_with_ports_from_config(self):
|
|
mysql_tmpl = template.load_heat_template('mysql')
|
|
tcp_rules = [{'cidr': "0.0.0.0/0",
|
|
'from_': 3306,
|
|
'to_': 3309},
|
|
{'cidr': "0.0.0.0/0",
|
|
'from_': 3320,
|
|
'to_': 33022}]
|
|
output = mysql_tmpl.render(
|
|
volume_support=True,
|
|
ifaces=[], ports=[],
|
|
tcp_rules=tcp_rules,
|
|
udp_rules=[],
|
|
files={})
|
|
self.assertIsNotNone(output)
|
|
self.assertIn('FromPort: "3306"', output)
|
|
self.assertIn('ToPort: "3309"', output)
|
|
self.assertIn('CidrIp: "0.0.0.0/0"', output)
|
|
self.assertIn('FromPort: "3320"', output)
|
|
self.assertIn('ToPort: "33022"', output)
|
|
|
|
def test_no_rules_if_no_ports(self):
|
|
mysql_tmpl = template.load_heat_template('mysql')
|
|
output = mysql_tmpl.render(
|
|
volume_support=True,
|
|
ifaces=[], ports=[],
|
|
tcp_rules=[],
|
|
udp_rules=[],
|
|
files={})
|
|
self.assertIsNotNone(output)
|
|
self.assertNotIn('- IpProtocol: "tcp"', output)
|
|
self.assertNotIn('- IpProtocol: "udp"', output)
|