diff --git a/flameclient/flame.py b/flameclient/flame.py index 6b24be9..2da3089 100644 --- a/flameclient/flame.py +++ b/flameclient/flame.py @@ -147,6 +147,7 @@ class TemplateGenerator(object): self.networks = self.build_data(self.neutron.network_list()) self.routers = self.neutron.router_list() self.secgroups = self.build_data(self.neutron.secgroup_list()) + self.servergroups = self.build_data(self.nova.servergroup_list()) self.floatingips = self.neutron.floatingip_list() self.ports = self.build_data(self.neutron.port_list()) self.external_networks = [] @@ -327,6 +328,16 @@ class TemplateGenerator(object): resources.append(resource) return resources + def _extract_servergroups(self): + resources = [] + for n, servergroup in self.servergroups.values(): + properties = {'name': servergroup.name, + 'policies': servergroup.policies} + resource = Resource("servergroup_%d" % n, 'OS::Nova::ServerGroup', + servergroup.id, properties) + resources.append(resource) + return resources + def _extract_keys(self): resources = [] for n, key in self.keys.values(): @@ -374,6 +385,9 @@ class TemplateGenerator(object): networks.append({'network': {'get_resource': net}}) return networks + def get_servergroup_resource_name(self, servergroup_id): + return "servergroup_%d" % self.servergroups[servergroup_id][0] + def _extract_servers(self): resources = [] for n, server in self.servers.values(): @@ -457,6 +471,15 @@ class TemplateGenerator(object): # block devices to an instance properties['block_device_mapping_v2'] = server_volumes + # server-group + for servergroup in self.servergroups.values(): + if server.id in servergroup[1].members: + hint = {'group': {'get_resource': + self.get_servergroup_resource_name + (servergroup[1].id)}} + properties['scheduler_hints'] = \ + hint + resources.append(resource) return resources @@ -551,6 +574,7 @@ class TemplateGenerator(object): resources += self._extract_subnets() resources += self._extract_secgroups() resources += self._extract_floating() + resources += self._extract_servergroups() if not self.exclude_keypairs: resources += self._extract_keys() diff --git a/flameclient/managers.py b/flameclient/managers.py index cbeca25..ab04ae4 100644 --- a/flameclient/managers.py +++ b/flameclient/managers.py @@ -176,6 +176,9 @@ class NovaManager(object): def server_security_group_list(self, server): return self.client().servers.list_security_group(server) + def servergroup_list(self): + return self.client().server_groups.list(True) + class CinderManager(object): """Manage Cinder resources.""" diff --git a/flameclient/tests/test_flame.py b/flameclient/tests/test_flame.py index 5906657..4e6c1c4 100644 --- a/flameclient/tests/test_flame.py +++ b/flameclient/tests/test_flame.py @@ -92,6 +92,13 @@ class FakeSecurityGroup(FakeBase): name = 'name' +class FakeServerGroup(FakeBase): + name = 'policy_group' + id = '1234' + policies = 'affinity' + members = ['12345'] + + class FakeNeutronManager(object): def __init__(self): @@ -141,6 +148,7 @@ class FakeNovaManager(object): self.groups = {} self.keypairs = [FakeKeypair(name='testkey', public_key='ssh-rsa XXXX')] + self.servergroups = [FakeServerGroup()] def keypair_list(self): return self.keypairs @@ -154,6 +162,9 @@ class FakeNovaManager(object): def server_security_group_list(self, server): return self.groups.get(server.name, []) + def servergroup_list(self): + return self.servergroups + class FakeCinderManager(object): @@ -640,6 +651,23 @@ class StackDataTests(BaseTestCase): } self.check_stackdata(generator._extract_servers(), expected) + def test_servergroup(self): + self.mock_nova.return_value = FakeNovaManager() + generator = self.get_generator(False, False, False, True) + + expected = { + 'servergroup_0': { + 'action': 'CREATE', + 'metadata': {}, + 'name': 'servergroup_0', + 'resource_data': {}, + 'resource_id': '1234', + 'status': 'COMPLETE', + 'type': 'OS::Nova::ServerGroup' + } + } + self.check_stackdata(generator._extract_servergroups(), expected) + class NetworkTests(BaseTestCase): @@ -1871,6 +1899,40 @@ class ServerTests(BaseTestCase): self.check_template(generator._extract_servers(), expected_resources, expected_parameters) + def test_servergroup(self): + self.fake.servers = [FakeServer()] + self.fake.servers[0].id = '12345' + generator = self.get_generator(False, False, False, True) + + expected_parameters = { + 'server_0_flavor': { + 'default': 'm1.small', + 'description': 'Flavor to use for server server_0', + 'type': 'string' + }, + 'server_0_image': { + 'description': 'Image to use to boot server server_0', + 'default': '3333', + 'type': 'string' + } + } + expected_resources = { + 'server_0': { + 'type': 'OS::Nova::Server', + 'properties': { + 'name': 'server1', + 'diskConfig': 'MANUAL', + 'flavor': {'get_param': 'server_0_flavor'}, + 'image': {'get_param': 'server_0_image'}, + 'key_name': {'get_resource': 'key_0'}, + 'scheduler_hints': {'group': + {'get_resource': 'servergroup_0'}} + } + } + } + self.check_template(generator._extract_servers(), expected_resources, + expected_parameters) + class GenerationTests(BaseTestCase): @@ -1934,6 +1996,12 @@ class GenerationTests(BaseTestCase): }, 'type': 'OS::Nova::Server' }, + 'servergroup_0': { + 'properties': { + 'name': 'policy_group', + 'policies': 'affinity'}, + 'type': 'OS::Nova::ServerGroup' + }, 'volume_0': { 'properties': { 'description': 'Description', @@ -1982,6 +2050,15 @@ class GenerationTests(BaseTestCase): 'status': 'COMPLETE', 'type': 'OS::Nova::Server' }, + 'servergroup_0': { + 'action': 'CREATE', + 'metadata': {}, + 'name': 'servergroup_0', + 'resource_data': {}, + 'resource_id': '1234', + 'status': 'COMPLETE', + 'type': 'OS::Nova::ServerGroup' + }, 'volume_0': { 'action': 'CREATE', 'metadata': {}, @@ -2032,6 +2109,13 @@ class GenerationTests(BaseTestCase): }, 'type': 'OS::Neutron::Router' }, + 'servergroup_0': { + 'properties': { + 'name': 'policy_group', + 'policies': 'affinity' + }, + 'type': 'OS::Nova::ServerGroup' + }, 'volume_0': { 'properties': { 'description': 'Description', @@ -2071,6 +2155,15 @@ class GenerationTests(BaseTestCase): 'status': 'COMPLETE', 'type': 'OS::Neutron::Router' }, + 'servergroup_0': { + 'action': 'CREATE', + 'metadata': {}, + 'name': 'servergroup_0', + 'resource_data': {}, + 'resource_id': '1234', + 'status': 'COMPLETE', + 'type': 'OS::Nova::ServerGroup' + }, 'volume_0': { 'action': 'CREATE', 'metadata': {}, @@ -2136,6 +2229,12 @@ class GenerationTests(BaseTestCase): }, 'type': 'OS::Nova::Server' }, + 'servergroup_0': { + 'properties': { + 'name': 'policy_group', + 'policies': 'affinity'}, + 'type': 'OS::Nova::ServerGroup' + } } expected_data = { @@ -2174,6 +2273,15 @@ class GenerationTests(BaseTestCase): 'resource_id': '1234', 'status': 'COMPLETE', 'type': 'OS::Nova::Server' + }, + 'servergroup_0': { + 'action': 'CREATE', + 'metadata': {}, + 'name': 'servergroup_0', + 'resource_data': {}, + 'resource_id': '1234', + 'status': 'COMPLETE', + 'type': 'OS::Nova::ServerGroup' } } @@ -2234,6 +2342,13 @@ class GenerationTests(BaseTestCase): }, 'type': 'OS::Nova::Server' }, + 'servergroup_0': { + 'properties': { + 'name': 'policy_group', + 'policies': 'affinity' + }, + 'type': 'OS::Nova::ServerGroup' + }, 'volume_0': { 'properties': { 'description': 'Description', @@ -2273,6 +2388,15 @@ class GenerationTests(BaseTestCase): 'status': 'COMPLETE', 'type': 'OS::Nova::Server' }, + 'servergroup_0': { + 'action': 'CREATE', + 'metadata': {}, + 'name': 'servergroup_0', + 'resource_data': {}, + 'resource_id': '1234', + 'status': 'COMPLETE', + 'type': 'OS::Nova::ServerGroup' + }, 'volume_0': { 'action': 'CREATE', 'metadata': {}, @@ -2317,6 +2441,13 @@ class GenerationTests(BaseTestCase): }, 'type': 'OS::Neutron::Router' }, + 'servergroup_0': { + 'properties': { + 'name': 'policy_group', + 'policies': 'affinity' + }, + 'type': 'OS::Nova::ServerGroup' + } } expected_data = { @@ -2346,6 +2477,15 @@ class GenerationTests(BaseTestCase): 'resource_id': '1234', 'status': 'COMPLETE', 'type': 'OS::Neutron::Router' + }, + 'servergroup_0': { + 'action': 'CREATE', + 'metadata': {}, + 'name': 'servergroup_0', + 'resource_data': {}, + 'resource_id': '1234', + 'status': 'COMPLETE', + 'type': 'OS::Nova::ServerGroup' } } generator.extract_data() @@ -2373,8 +2513,16 @@ class GenerationTests(BaseTestCase): 'name': 'myrouter' }, 'type': 'OS::Neutron::Router' + }, + 'servergroup_0': { + 'properties': { + 'name': 'policy_group', + 'policies': 'affinity' + }, + 'type': 'OS::Nova::ServerGroup' } } + expected_data = { 'network_0': { 'action': 'CREATE', @@ -2393,6 +2541,15 @@ class GenerationTests(BaseTestCase): 'resource_id': '1234', 'status': 'COMPLETE', 'type': 'OS::Neutron::Router' + }, + 'servergroup_0': { + 'action': 'CREATE', + 'metadata': {}, + 'name': 'servergroup_0', + 'resource_data': {}, + 'resource_id': '1234', + 'status': 'COMPLETE', + 'type': 'OS::Nova::ServerGroup' } }