Merge pull request #4 from enovance/master

Refactored the TemplateGenerator class
This commit is contained in:
Ala Rezmerita 2014-09-23 16:26:33 +02:00
commit de8f156835
8 changed files with 712 additions and 556 deletions

View File

@ -22,6 +22,23 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
def template_configuration(allow_insecure=False, exclude_servers=False, from flameclient.flame import TemplateGenerator # noqa
exclude_volumes=False, generate_stack_data=False):
raise NotImplementedError()
class Client(object):
def __init__(self, api_version, **kwargs):
username = kwargs.get('username')
password = kwargs.get('password')
tenant_name = kwargs.get('tenant_name')
auth_url = kwargs.get('auth_url')
insecure = kwargs.get('insecure')
self.template_generator = TemplateGenerator(username, password,
tenant_name, auth_url,
insecure)
def generate(self, include_networks, include_instances, include_volumes):
return self.template_generator.generate(include_networks,
include_instances,
include_volumes)

View File

@ -22,13 +22,15 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import print_function
import argparse import argparse
import os import os
from flame import TemplateGenerator from flame import TemplateGenerator
def main(): def main(args=None):
desc = "Heat template and data file generator" desc = "Heat template and data file generator"
parser = argparse.ArgumentParser(description=desc) parser = argparse.ArgumentParser(description=desc)
parser.add_argument("--username", type=str, parser.add_argument("--username", type=str,
@ -65,9 +67,13 @@ def main():
"stack data file.") "stack data file.")
args = parser.parse_args() args = parser.parse_args()
arguments = (args.username, args.password, args.project, args.auth_url, template = TemplateGenerator(args.username, args.password, args.project,
args.insecure) args.auth_url, args.insecure)
TemplateGenerator(args.exclude_servers, template.extract_vm_details(args.exclude_servers, args.exclude_volumes,
args.exclude_volumes, args.generate_stack_data)
args.generate_stack_data, template.extract_data()
*arguments).run() print("### Heat Template ###")
print(template.heat_template())
if args.generate_stack_data:
print("### Stack Data ###")
print(template.stack_data_template())

View File

@ -30,7 +30,6 @@ import yaml
from flameclient import managers from flameclient import managers
logging.basicConfig(level=logging.ERROR) logging.basicConfig(level=logging.ERROR)
template_skeleton = ''' template_skeleton = '''
@ -48,26 +47,38 @@ resources:
class TemplateGenerator(object): class TemplateGenerator(object):
template = None
stack_data = None
neutron_manager = managers.NeutronManager def __init__(self, username, password, tenant_name, auth_url, insecure):
nova_manager = managers.NovaManager self.generate_data = False
cinder_manager = managers.CinderManager self._setup_templates()
self._setup_managers(username, password, tenant_name, auth_url,
def __init__(self, exclude_servers, exclude_volumes, insecure)
generate_data, *arguments):
self.exclude_servers = exclude_servers
self.exclude_volumes = exclude_volumes
self.generate_data = generate_data
def _setup_templates(self):
self.template = yaml.load(template_skeleton) self.template = yaml.load(template_skeleton)
self.template['resources'] = {} self.template['resources'] = {}
self.template['parameters'] = {} self.template['parameters'] = {}
if self.generate_data: self.stack_data = yaml.load(stack_data_skeleton)
self.stack_data = yaml.load(stack_data_skeleton) self.stack_data['resources'] = {}
self.stack_data['resources'] = {}
def _setup_managers(self, username, password, tenant_name, auth_url,
insecure):
self.neutron = managers.NeutronManager(username, password, tenant_name,
auth_url, insecure)
self.nova = managers.NovaManager(username, password, tenant_name,
auth_url, insecure)
self.cinder = managers.CinderManager(username, password, tenant_name,
auth_url, insecure)
def extract_vm_details(self, exclude_servers, exclude_volumes,
generate_data):
self.exclude_servers = exclude_servers
self.exclude_volumes = exclude_volumes
self.generate_data = generate_data
self.neutron = self.neutron_manager(*arguments)
self.subnets = self.build_data(self.neutron.subnet_list()) self.subnets = self.build_data(self.neutron.subnet_list())
self.networks = self.build_data(self.neutron.network_list()) self.networks = self.build_data(self.neutron.network_list())
self.routers = self.neutron.router_list() self.routers = self.neutron.router_list()
@ -76,18 +87,16 @@ class TemplateGenerator(object):
self.ports = self.build_data(self.neutron.port_list()) self.ports = self.build_data(self.neutron.port_list())
self.external_networks = [] self.external_networks = []
self.nova = self.nova_manager(*arguments)
self.keys = dict( self.keys = dict(
(key.name, (index, key)) (key.name, (index, key))
for index, key in enumerate(self.nova.keypair_list())) for index, key in enumerate(self.nova.keypair_list()))
if not self.exclude_servers: if not exclude_servers:
self.flavors = self.build_data(self.nova.flavor_list()) self.flavors = self.build_data(self.nova.flavor_list())
self.servers = self.build_data(self.nova.server_list()) self.servers = self.build_data(self.nova.server_list())
if (not self.exclude_volumes or if (not exclude_volumes or
(self.exclude_volumes and not self.exclude_servers)): (exclude_volumes and not exclude_servers)):
self.cinder = self.cinder_manager(*arguments)
self.volumes = self.build_data(self.cinder.volume_list()) self.volumes = self.build_data(self.cinder.volume_list())
def build_data(self, data): def build_data(self, data):
@ -101,9 +110,9 @@ class TemplateGenerator(object):
return dict((element.id, (index, element)) return dict((element.id, (index, element))
for index, element in enumerate(data)) for index, element in enumerate(data))
def print_generated(self, file, message): @staticmethod
print("########## %s ##########" % message) def print_generated(filename):
print(yaml.safe_dump(file, default_flow_style=False)) print(yaml.safe_dump(filename, default_flow_style=False))
def add_resource(self, name, status, resource_id, resource_type): def add_resource(self, name, status, resource_id, resource_type):
resource = { resource = {
@ -191,7 +200,7 @@ class TemplateGenerator(object):
} }
self.template['resources'].update(resource) self.template['resources'].update(resource)
def extract_routers(self): def _extract_routers(self):
for n, router in enumerate(self.routers): for n, router in enumerate(self.routers):
router_resource_name = "router_%d" % n router_resource_name = "router_%d" % n
resource_type = 'OS::Neutron::Router' resource_type = 'OS::Neutron::Router'
@ -219,7 +228,7 @@ class TemplateGenerator(object):
self.add_router_gateway_resource(router_resource_name, self.add_router_gateway_resource(router_resource_name,
router) router)
def extract_networks(self): def _extract_networks(self):
for n, network in self.networks.itervalues(): for n, network in self.networks.itervalues():
if network['router:external']: if network['router:external']:
self.external_networks.append(network['id']) self.external_networks.append(network['id'])
@ -245,13 +254,13 @@ class TemplateGenerator(object):
} }
self.template['resources'].update(resource) self.template['resources'].update(resource)
def get_network_resource_name(self, id): def get_network_resource_name(self, network_id):
return "network_%d" % self.networks[id][0] return "network_%d" % self.networks[network_id][0]
def get_subnet_resource_name(self, id): def get_subnet_resource_name(self, subnet_id):
return "subnet_%d" % self.subnets[id][0] return "subnet_%d" % self.subnets[subnet_id][0]
def extract_subnets(self): def _extract_subnets(self):
for n, subnet in self.subnets.itervalues(): for n, subnet in self.subnets.itervalues():
if subnet['network_id'] in self.external_networks: if subnet['network_id'] in self.external_networks:
continue continue
@ -301,7 +310,7 @@ class TemplateGenerator(object):
brules.append(rule) brules.append(rule)
return brules return brules
def extract_secgroups(self): def _extract_secgroups(self):
for n, secgroup in self.secgroups.itervalues(): for n, secgroup in self.secgroups.itervalues():
resource_name = "security_group_%d" % n resource_name = "security_group_%d" % n
@ -330,7 +339,7 @@ class TemplateGenerator(object):
} }
self.template['resources'].update(resource) self.template['resources'].update(resource)
def extract_keys(self): def _extract_keys(self):
for n, key in self.keys.itervalues(): for n, key in self.keys.itervalues():
key_resource_name = "key_%d" % n key_resource_name = "key_%d" % n
resource_type = 'OS::Nova::KeyPair' resource_type = 'OS::Nova::KeyPair'
@ -390,7 +399,7 @@ class TemplateGenerator(object):
networks.append({'network': {'get_resource': net}}) networks.append({'network': {'get_resource': net}})
return networks return networks
def extract_servers(self): def _extract_servers(self):
for n, server in self.servers.itervalues(): for n, server in self.servers.itervalues():
resource_name = "server_%d" % n resource_name = "server_%d" % n
resource_type = 'OS::Nova::Server' resource_type = 'OS::Nova::Server'
@ -475,7 +484,7 @@ class TemplateGenerator(object):
} }
self.template['resources'].update(resource) self.template['resources'].update(resource)
def extract_floating(self): def _extract_floating(self):
for n, ip in enumerate(self.floatingips): for n, ip in enumerate(self.floatingips):
ip_resource_name = "floatingip_%d" % n ip_resource_name = "floatingip_%d" % n
net_param_name = "external_network_for_floating_ip_%d" % n net_param_name = "external_network_for_floating_ip_%d" % n
@ -523,7 +532,7 @@ class TemplateGenerator(object):
self.template['resources'].update(resource) self.template['resources'].update(resource)
self.template['resources'].update(floating_resource) self.template['resources'].update(floating_resource)
def extract_volumes(self): def _extract_volumes(self):
for n, volume in self.volumes.itervalues(): for n, volume in self.volumes.itervalues():
resource_name = "volume_%d" % n resource_name = "volume_%d" % n
resource_type = 'OS::Cinder::Volume' resource_type = 'OS::Cinder::Volume'
@ -582,21 +591,20 @@ class TemplateGenerator(object):
} }
self.template['resources'].update(resource) self.template['resources'].update(resource)
def run(self): def extract_data(self):
self.extract_routers() self._extract_routers()
self.extract_networks() self._extract_networks()
self.extract_subnets() self._extract_subnets()
self.extract_secgroups() self._extract_secgroups()
self.extract_floating() self._extract_floating()
self.extract_keys() self._extract_keys()
if not self.exclude_servers: if not self.exclude_servers:
self.extract_servers() self._extract_servers()
if not self.exclude_volumes: if not self.exclude_volumes:
self.extract_volumes() self._extract_volumes()
self.print_generated(self.template, "Heat Template") def heat_template(self):
return self.print_generated(self.template)
if self.generate_data: def stack_data_template(self):
self.print_generated(self.stack_data, "Heat Stack Data") return self.print_generated(self.stack_data)

View File

@ -30,108 +30,171 @@ from novaclient.v1_1 import client as nova_client
class KeystoneManager(object): class KeystoneManager(object):
"""Manages Keystone queries.""" """Manages Keystone queries."""
_client = None
def __init__(self, username, password, project, auth_url, insecure): def __init__(self, username, password, project, auth_url, insecure):
self.client = keystone_client.Client( self.username = username
username=username, password=password, self.password = password
tenant_name=project, auth_url=auth_url, insecure=insecure) self.project = project
self.auth_url = auth_url
self.insecure = insecure
def client(self):
if not self._client:
self._client = keystone_client.Client(username=self.username,
password=self.password,
tenant_name=self.project,
auth_url=self.auth_url,
insecure=self.insecure)
return self._client
def set_client(client):
self._client = client
def get_token(self): def get_token(self):
return self.client.auth_token return self.client().auth_token
def get_endpoint(self, service_type, endpoint_type="publicURL"): def get_endpoint(self, service_type, endpoint_type="publicURL"):
catalog = self.client.service_catalog.get_endpoints() catalog = self.client().service_catalog.get_endpoints()
return catalog[service_type][0][endpoint_type] return catalog[service_type][0][endpoint_type]
def get_project_id(self): def get_project_id(self):
return self.client.tenant_id return self.client().tenant_id
class NeutronManager(object): class NeutronManager(object):
_client = None
_project_id = None
def __init__(self, username, password, project, auth_url, insecure): def __init__(self, username, password, project, auth_url, insecure):
self.client = neutron_client.Client( self.username = username
username=username, password=password, self.password = password
tenant_name=project, auth_url=auth_url, self.project = project
insecure=insecure) self.auth_url = auth_url
keystone_mgr = KeystoneManager(username, password, project, self.insecure = insecure
auth_url, insecure)
self.project_id = keystone_mgr.get_project_id() def client(self):
if not self._client:
self._client = neutron_client.Client(username=self.username,
password=self.password,
tenant_name=self.project,
auth_url=self.auth_url,
insecure=self.insecure)
if not self._project_id:
keystone_mgr = KeystoneManager(self.username, self.password,
self.project, self.auth_url,
self.insecure)
self._project_id = keystone_mgr.get_project_id()
return self._client
def set_client(self, client):
self._client = client
def set_project_id(self, project_id):
self._project_id = project_id
def router_list(self): def router_list(self):
return filter(self._owned_resource, return filter(self._owned_resource,
self.client.list_routers()['routers']) self.client().list_routers()['routers'])
def router_interfaces_list(self, router): def router_interfaces_list(self, router):
return self.client.list_ports(device_id=router['id'])['ports'] return self._client.list_ports(device_id=router['id'])['ports']
def port_list(self): def port_list(self):
return self.client.list_ports()['ports'] return self.client().list_ports()['ports']
def network_list(self): def network_list(self):
return filter(self._owned_resource, return filter(self._owned_resource,
self.client.list_networks()['networks']) self.client().list_networks()['networks'])
def secgroup_list(self): def secgroup_list(self):
return filter(self._owned_resource, return filter(self._owned_resource,
self.client.list_security_groups()['security_groups']) self.client().list_security_groups()['security_groups'])
def floatingip_list(self): def floatingip_list(self):
return filter(self._owned_resource, return filter(self._owned_resource,
self.client.list_floatingips()['floatingips']) self.client().list_floatingips()['floatingips'])
def subnet_list(self): def subnet_list(self):
return filter(self._owned_resource, return filter(self._owned_resource,
self.client.list_subnets()['subnets']) self.client().list_subnets()['subnets'])
def _owned_resource(self, res): def _owned_resource(self, res):
# Only considering resources owned by project # Only considering resources owned by project
return res['tenant_id'] == self.project_id return res['tenant_id'] == self._project_id
class NovaManager(object): class NovaManager(object):
"""Manage nova resources.""" """Manage nova resources."""
_client = None
def __init__(self, username, password, project, auth_url, insecure): def __init__(self, username, password, project, auth_url, insecure):
self.client = nova_client.Client(username, password, project, self.username = username
auth_url, insecure=insecure) self.password = password
self.project = project
self.auth_url = auth_url
self.insecure = insecure
def client(self):
if not self._client:
self._client = nova_client.Client(self.username, self.password,
self.project, self.auth_url,
insecure=self.insecure)
return self._client
def set_client(self, client):
self._client = client
def server_list(self): def server_list(self):
return self.client.servers.list() return self.client().servers.list()
def floating_ip_list(self): def floating_ip_list(self):
return self.client.floating_ips.list() return self.client().floating_ips.list()
def flavor_list(self): def flavor_list(self):
return self.client.flavors.list() return self.client().flavors.list()
def flavor_get(self, id): def flavor_get(self, id):
return self.client.flavors.get(id) return self.client().flavors.get(id)
def keypair_list(self): def keypair_list(self):
return self.client.keypairs.list() return self.client().keypairs.list()
def keypair_show(self, keypair): def keypair_show(self, keypair):
return self.client.keypairs.get(keypair) return self.client().keypairs.get(keypair)
def server_security_group_list(self, server): def server_security_group_list(self, server):
return self.client.servers.list_security_group(server) return self.client().servers.list_security_group(server)
class CinderManager(object): class CinderManager(object):
"""Manage Cinder resources.""" """Manage Cinder resources."""
_client = None
def __init__(self, username, password, project, auth_url, insecure): def __init__(self, username, password, project, auth_url, insecure):
self.client = cinder_client.Client(username, self.username = username
password, self.password = password
project, self.project = project
auth_url, self.auth_url = auth_url
insecure=insecure) self.insecure = insecure
def client(self):
if not self._client:
self._client = cinder_client.Client(self.username,
self.password,
self.project,
self.auth_url,
insecure=self.insecure)
return self._client
def set_client(self, client):
self._client = client
def volume_list(self): def volume_list(self):
volumes = [] volumes = []
for vol in self.client.volumes.list(): for vol in self.client().volumes.list():
volumes.append(self.client.volumes.get(vol.id)) volumes.append(self.client().volumes.get(vol.id))
return volumes return volumes
def snapshot_list(self): def snapshot_list(self):
return self.client.volume_snapshots.list() return self.client().volume_snapshots.list()

View File

@ -50,4 +50,4 @@ class TestCase(testtools.TestCase):
stderr = self.useFixture(fixtures.StringStream('stderr')).stream stderr = self.useFixture(fixtures.StringStream('stderr')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
self.log_fixture = self.useFixture(fixtures.FakeLogger()) self.log_fixture = self.useFixture(fixtures.FakeLogger())

File diff suppressed because it is too large Load Diff

View File

@ -3,9 +3,9 @@ name = python-flameclient
summary = Automatic Heat template generation summary = Automatic Heat template generation
description-file = description-file =
README.rst README.rst
author = OpenStack author = CloudWatt
author-email = openstack-dev@lists.openstack.org author-email = info@cloudwatt.com
home-page = http://www.openstack.org/ home-page = http://www.cloudwatt.com/
classifier = classifier =
Environment :: OpenStack Environment :: OpenStack
Intended Audience :: Information Technology Intended Audience :: Information Technology
@ -16,8 +16,6 @@ classifier =
Programming Language :: Python :: 2 Programming Language :: Python :: 2
Programming Language :: Python :: 2.7 Programming Language :: Python :: 2.7
Programming Language :: Python :: 2.6 Programming Language :: Python :: 2.6
Programming Language :: Python :: 3
Programming Language :: Python :: 3.3
[files] [files]
packages = packages =
@ -27,6 +25,10 @@ packages =
setup-hooks = setup-hooks =
pbr.hooks.setup_hook pbr.hooks.setup_hook
[entry_points]
console_scripts =
flame = flameclient.cmd:main
[build_sphinx] [build_sphinx]
source-dir = doc/source source-dir = doc/source
build-dir = doc/build build-dir = doc/build
@ -49,9 +51,5 @@ keywords = _ gettext ngettext l_ lazy_gettext
mapping_file = babel.cfg mapping_file = babel.cfg
output_file = flameclient/locale/python-flameclient.pot output_file = flameclient/locale/python-flameclient.pot
[entry_points]
console_scripts =
flame = flameclient.cmd:main
[wheel] [wheel]
universal = 1 universal = 1

View File

@ -2,10 +2,11 @@ hacking>=0.9.2,<0.10
coverage>=3.6 coverage>=3.6
discover discover
mock>=1.0
fixtures>=0.3.14 fixtures>=0.3.14
python-subunit python-subunit
sphinx>=1.1.2 sphinx>=1.1.2
oslosphinx oslosphinx
testrepository>=0.0.18 testrepository>=0.0.18
testscenarios>=0.4 testscenarios>=0.4
testtools>=0.9.34 testtools>=0.9.34