heat/contrib/rackspace/rackspace/tests/test_rackspace_dns.py

325 lines
12 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.
import uuid
import mock
from heat.common import exception
from heat.common import template_format
from heat.engine import environment
from heat.engine import resource
from heat.engine import rsrc_defn
from heat.engine import scheduler
from heat.engine import stack as parser
from heat.engine import template
from heat.tests import common
from heat.tests import utils
from ..resources import cloud_dns # noqa
domain_only_template = '''
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Dns instance running on Rackspace cloud",
"Parameters" : {
"UnittestDomain" : {
"Description" : "Domain for unit tests",
"Type" : "String",
"Default" : 'dnsheatunittest.com'
},
"dnsttl" : {
"Description" : "TTL for the domain",
"Type" : "Number",
"MinValue" : '301',
"Default" : '301'
},
"name": {
"Description" : "The cloud dns instance name",
"Type": "String",
"Default": "CloudDNS"
}
},
"Resources" : {
"domain" : {
"Type": "Rackspace::Cloud::DNS",
"Properties" : {
"name" : "dnsheatunittest.com",
"emailAddress" : "admin@dnsheatunittest.com",
"ttl" : 3600,
"comment" : "Testing Cloud DNS integration with Heat"
}
}
}
}
'''
class FakeDnsInstance(object):
def __init__(self):
self.id = 4
self.resource_id = 4
def get(self):
pass
def delete(self):
pass
class RackspaceDnsTest(common.HeatTestCase):
def setUp(self):
super(RackspaceDnsTest, self).setUp()
# Test environment may not have pyrax client library installed and if
# pyrax is not installed resource class would not be registered.
# So register resource provider class explicitly for unit testing.
resource._register_class("Rackspace::Cloud::DNS", cloud_dns.CloudDns)
self.create_domain_only_args = {
"name": 'dnsheatunittest.com',
"emailAddress": 'admin@dnsheatunittest.com',
"ttl": 3600,
"comment": 'Testing Cloud DNS integration with Heat',
"records": None
}
self.update_domain_only_args = {
"emailAddress": 'updatedEmail@example.com',
"ttl": 5555,
"comment": 'updated comment'
}
def _setup_test_cloud_dns_instance(self, name, parsed_t):
stack_name = '%s_stack' % name
t = parsed_t
templ = template.Template(
t, env=environment.Environment({'name': 'test'}))
self.stack = parser.Stack(utils.dummy_context(),
stack_name,
templ,
stack_id=str(uuid.uuid4()))
instance = cloud_dns.CloudDns(
'%s_name' % name,
templ.resource_definitions(self.stack)['domain'],
self.stack)
return instance
def _stubout_create(self, instance, fake_dnsinstance, **create_args):
mock_client = self.m.CreateMockAnything()
self.m.StubOutWithMock(instance, 'cloud_dns')
instance.cloud_dns().AndReturn(mock_client)
self.m.StubOutWithMock(mock_client, "create")
mock_client.create(**create_args).AndReturn(fake_dnsinstance)
self.m.ReplayAll()
def _stubout_update(
self,
instance,
fake_dnsinstance,
updateRecords=None,
**update_args):
mock_client = self.m.CreateMockAnything()
self.m.StubOutWithMock(instance, 'cloud_dns')
instance.cloud_dns().AndReturn(mock_client)
self.m.StubOutWithMock(mock_client, "get")
mock_domain = self.m.CreateMockAnything()
mock_client.get(fake_dnsinstance.resource_id).AndReturn(mock_domain)
self.m.StubOutWithMock(mock_domain, "update")
mock_domain.update(**update_args).AndReturn(fake_dnsinstance)
if updateRecords:
fake_records = list()
mock_domain.list_records().AndReturn(fake_records)
mock_domain.add_records([{
'comment': None,
'priority': None,
'type': 'A',
'name': 'ftp.example.com',
'data': '192.0.2.8',
'ttl': 3600}])
self.m.ReplayAll()
def _get_create_args_with_comments(self, record):
record_with_comment = [dict(record[0])]
record_with_comment[0]["comment"] = None
create_record_args = dict()
create_record_args['records'] = record_with_comment
create_args = dict(
list(self.create_domain_only_args.items()) +
list(create_record_args.items()))
return create_args
def test_create_domain_only(self):
"""
Test domain create only without any records.
"""
fake_dns_instance = FakeDnsInstance()
t = template_format.parse(domain_only_template)
instance = self._setup_test_cloud_dns_instance('dnsinstance_create', t)
create_args = self.create_domain_only_args
self._stubout_create(instance, fake_dns_instance, **create_args)
scheduler.TaskRunner(instance.create)()
self.assertEqual((instance.CREATE, instance.COMPLETE), instance.state)
self.m.VerifyAll()
def test_create_domain_with_a_record(self):
"""
Test domain create with an A record. This should not have a
priority field.
"""
fake_dns_instance = FakeDnsInstance()
t = template_format.parse(domain_only_template)
a_record = [{
"type": "A",
"name": "ftp.example.com",
"data": "192.0.2.8",
"ttl": 3600
}]
t['Resources']['domain']['Properties']['records'] = a_record
instance = self._setup_test_cloud_dns_instance('dnsinstance_create', t)
create_args = self._get_create_args_with_comments(a_record)
self._stubout_create(instance, fake_dns_instance, **create_args)
scheduler.TaskRunner(instance.create)()
self.assertEqual((instance.CREATE, instance.COMPLETE), instance.state)
self.m.VerifyAll()
def test_create_domain_with_mx_record(self):
"""
Test domain create with an MX record. This should have a
priority field.
"""
fake_dns_instance = FakeDnsInstance()
t = template_format.parse(domain_only_template)
mx_record = [{
"type": "MX",
"name": "example.com",
"data": "mail.example.com",
"priority": 5,
"ttl": 3600
}]
t['Resources']['domain']['Properties']['records'] = mx_record
instance = self._setup_test_cloud_dns_instance('dnsinstance_create', t)
create_args = self._get_create_args_with_comments(mx_record)
self._stubout_create(instance, fake_dns_instance, **create_args)
scheduler.TaskRunner(instance.create)()
self.assertEqual((instance.CREATE, instance.COMPLETE), instance.state)
self.m.VerifyAll()
def test_check(self):
t = template_format.parse(domain_only_template)
instance = self._setup_test_cloud_dns_instance('dnsinstance_create', t)
mock_get = mock.Mock()
instance.cloud_dns = mock.Mock()
instance.cloud_dns.return_value.get = mock_get
scheduler.TaskRunner(instance.check)()
self.assertEqual('CHECK', instance.action)
self.assertEqual('COMPLETE', instance.status)
mock_get.side_effect = cloud_dns.NotFound('boom')
exc = self.assertRaises(exception.ResourceFailure,
scheduler.TaskRunner(instance.check))
self.assertEqual('CHECK', instance.action)
self.assertEqual('FAILED', instance.status)
self.assertIn('boom', str(exc))
def test_update(self, updateRecords=None):
"""
Helper function for testing domain updates.
"""
fake_dns_instance = FakeDnsInstance()
t = template_format.parse(domain_only_template)
instance = self._setup_test_cloud_dns_instance('dnsinstance_update', t)
instance.resource_id = 4
update_args = self.update_domain_only_args
self._stubout_update(
instance,
fake_dns_instance,
updateRecords,
**update_args)
uprops = dict(instance.properties)
uprops.update({
'emailAddress': 'updatedEmail@example.com',
'ttl': 5555,
'comment': 'updated comment',
})
if updateRecords:
uprops['records'] = updateRecords
ut = rsrc_defn.ResourceDefinition(instance.name,
instance.type(),
uprops)
instance.state_set(instance.CREATE, instance.COMPLETE)
scheduler.TaskRunner(instance.update, ut)()
self.assertEqual((instance.UPDATE, instance.COMPLETE), instance.state)
self.m.VerifyAll()
def test_update_domain_only(self):
"""
Test domain update without any records.
"""
self.test_update()
def test_update_domain_with_a_record(self):
"""
Test domain update with an A record.
"""
a_record = [{'type': 'A',
'name': 'ftp.example.com',
'data': '192.0.2.8',
'ttl': 3600}]
self.test_update(updateRecords=a_record)
def test_update_record_only(self):
"""Helper function for testing domain updates."""
fake_dns_instance = FakeDnsInstance()
t = template_format.parse(domain_only_template)
instance = self._setup_test_cloud_dns_instance('dnsinstance_update', t)
instance.resource_id = 4
update_records = [{'type': 'A',
'name': 'ftp.example.com',
'data': '192.0.2.8',
'ttl': 3600}]
mock_client = self.m.CreateMockAnything()
self.m.StubOutWithMock(instance, 'cloud_dns')
instance.cloud_dns().AndReturn(mock_client)
self.m.StubOutWithMock(mock_client, "get")
mock_domain = self.m.CreateMockAnything()
mock_client.get(fake_dns_instance.resource_id).AndReturn(mock_domain)
# mock_domain.update shouldn't be called in this scenario, so
# stub it out but don't record a call to it
self.m.StubOutWithMock(mock_domain, "update")
fake_records = list()
mock_domain.list_records().AndReturn(fake_records)
mock_domain.add_records([{
'comment': None,
'priority': None,
'type': 'A',
'name': 'ftp.example.com',
'data': '192.0.2.8',
'ttl': 3600}])
self.m.ReplayAll()
uprops = dict(instance.properties)
uprops['records'] = update_records
ut = rsrc_defn.ResourceDefinition(instance.name,
instance.type(),
uprops)
instance.state_set(instance.CREATE, instance.COMPLETE)
scheduler.TaskRunner(instance.update, ut)()
self.assertEqual((instance.UPDATE, instance.COMPLETE), instance.state)
self.m.VerifyAll()