1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 # and others. All rights reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 from snaps import file_utils
18 from snaps.config.flavor import FlavorConfig
19 from snaps.config.keypair import KeypairConfig
20 from snaps.config.network import SubnetConfig, PortConfig, NetworkConfig
21 from snaps.config.router import RouterConfig
22 from snaps.config.volume import VolumeConfig
23 from snaps.config.volume_type import (
24 ControlLocation, VolumeTypeEncryptionConfig, VolumeTypeConfig)
25 from snaps.openstack.create_instance import (
26 VmInstanceSettings, FloatingIpSettings)
27 from snaps.openstack.create_security_group import (
28 SecurityGroupSettings, SecurityGroupRuleSettings)
29 from snaps.openstack.utils import (
30 neutron_utils, nova_utils, heat_utils, glance_utils)
33 def create_network_config(neutron, network):
35 Returns a NetworkConfig object
36 :param neutron: the neutron client
37 :param network: a SNAPS-OO Network domain object
41 name=network.name, network_type=network.type,
42 subnet_settings=create_subnet_config(neutron, network))
45 def create_security_group_settings(neutron, security_group):
47 Returns a NetworkConfig object
48 :param neutron: the neutron client
49 :param security_group: a SNAPS-OO SecurityGroup domain object
52 rules = neutron_utils.get_rules_by_security_group(neutron, security_group)
54 rule_settings = list()
56 rule_settings.append(SecurityGroupRuleSettings(
57 sec_grp_name=security_group.name, description=rule.description,
58 direction=rule.direction, ethertype=rule.ethertype,
59 port_range_min=rule.port_range_min,
60 port_range_max=rule.port_range_max, protocol=rule.protocol,
61 remote_group_id=rule.remote_group_id,
62 remote_ip_prefix=rule.remote_ip_prefix))
64 return SecurityGroupSettings(
65 name=security_group.name, description=security_group.description,
66 rule_settings=rule_settings)
69 def create_subnet_config(neutron, network):
71 Returns a list of SubnetConfig objects for a given network
72 :param neutron: the OpenStack neutron client
73 :param network: the SNAPS-OO Network domain object
78 subnets = neutron_utils.get_subnets_by_network(neutron, network)
79 for subnet in subnets:
81 kwargs['cidr'] = subnet.cidr
82 kwargs['ip_version'] = subnet.ip_version
83 kwargs['name'] = subnet.name
84 kwargs['start'] = subnet.start
85 kwargs['end'] = subnet.end
86 kwargs['gateway_ip'] = subnet.gateway_ip
87 kwargs['enable_dhcp'] = subnet.enable_dhcp
88 kwargs['dns_nameservers'] = subnet.dns_nameservers
89 kwargs['host_routes'] = subnet.host_routes
90 kwargs['ipv6_ra_mode'] = subnet.ipv6_ra_mode
91 kwargs['ipv6_address_mode'] = subnet.ipv6_address_mode
92 out.append(SubnetConfig(**kwargs))
96 def create_router_settings(neutron, router):
98 Returns a RouterConfig object
99 :param neutron: the neutron client
100 :param router: a SNAPS-OO Router domain object
105 if router.external_network_id:
106 network = neutron_utils.get_network_by_id(
107 neutron, router.external_network_id)
109 ext_net_name = network.name
111 ports_tuple_list = list()
112 if router.port_subnets:
113 for port, subnets in router.port_subnets:
114 network = neutron_utils.get_network_by_id(
115 neutron, port.network_id)
118 if network and router.external_fixed_ips:
119 for ext_fixed_ips in router.external_fixed_ips:
120 for subnet in subnets:
121 if ext_fixed_ips['subnet_id'] == subnet.id:
122 ip_addrs.append(ext_fixed_ips['ip_address'])
128 if len(ip_addrs) > 0:
129 for ip_addr in ip_addrs:
130 if isinstance(ip_addr, dict):
131 ip_list.append(ip_addr['ip_address'])
133 ip_list.append(ip_addr)
135 ports_tuple_list.append((network, ip_list))
137 port_settings = __create_port_config(neutron, ports_tuple_list)
139 filtered_settings = list()
140 for port_setting in port_settings:
141 if port_setting.network_name != ext_net_name:
142 filtered_settings.append(port_setting)
145 name=router.name, external_gateway=ext_net_name,
146 admin_state_up=router.admin_state_up,
147 port_settings=filtered_settings)
150 def create_volume_config(volume):
152 Returns a VolumeSettings object
153 :param volume: a SNAPS-OO Volume object
157 name=volume.name, description=volume.description,
158 size=volume.size, type_name=volume.type,
159 availability_zone=volume.availability_zone,
160 multi_attach=volume.multi_attach)
163 def create_volume_type_config(volume_type):
165 Returns a VolumeTypeSettings object
166 :param volume_type: a SNAPS-OO VolumeType object
170 if volume_type.encryption:
171 if (volume_type.encryption.control_location
172 == ControlLocation.front_end.value):
173 control = ControlLocation.front_end
175 control = ControlLocation.back_end
177 encrypt_settings = VolumeTypeEncryptionConfig(
178 name=volume_type.encryption.__class__,
179 provider_class=volume_type.encryption.provider,
180 control_location=control,
181 cipher=volume_type.encryption.cipher,
182 key_size=volume_type.encryption.key_size)
185 if volume_type.qos_spec:
186 qos_spec_name = volume_type.qos_spec.name
188 return VolumeTypeConfig(
189 name=volume_type.name, encryption=encrypt_settings,
190 qos_spec_name=qos_spec_name, public=volume_type.public)
193 def create_flavor_config(flavor):
195 Returns a VolumeSettings object
196 :param flavor: a SNAPS-OO Volume object
199 name=flavor.name, flavor_id=flavor.id, ram=flavor.ram,
200 disk=flavor.disk, vcpus=flavor.vcpus, ephemeral=flavor.ephemeral,
201 swap=flavor.swap, rxtx_factor=flavor.rxtx_factor,
202 is_public=flavor.is_public)
205 def create_keypair_settings(heat_cli, stack, keypair, pk_output_key):
207 Instantiates a KeypairConfig object from a Keypair domain objects
208 :param heat_cli: the heat client
209 :param stack: the Stack domain object
210 :param keypair: the Keypair SNAPS domain object
211 :param pk_output_key: the key to the heat template's outputs for retrieval
212 of the private key file
213 :return: a KeypairConfig object
216 outputs = heat_utils.get_outputs(heat_cli, stack)
217 for output in outputs:
218 if output.key == pk_output_key:
221 key_file = file_utils.save_string_to_file(
222 output.value, str(guid), 0o400)
224 # Use outputs, file and resources for the KeypairConfig
225 return KeypairConfig(
226 name=keypair.name, private_filepath=key_file.name)
228 return KeypairConfig(name=keypair.name)
231 def create_vm_inst_settings(nova, neutron, server):
233 Returns a NetworkConfig object
234 :param nova: the nova client
235 :param neutron: the neutron client
236 :param server: a SNAPS-OO VmInst domain object
240 flavor_name = nova_utils.get_flavor_by_id(nova, server.flavor_id)
243 kwargs['name'] = server.name
244 kwargs['flavor'] = flavor_name
247 for net_name, ips in server.networks.items():
248 network = neutron_utils.get_network(neutron, network_name=net_name)
250 net_tuples.append((network, ips))
252 kwargs['port_settings'] = __create_port_config(
254 kwargs['security_group_names'] = server.sec_grp_names
255 kwargs['floating_ip_settings'] = __create_floatingip_settings(
256 neutron, kwargs['port_settings'])
258 return VmInstanceSettings(**kwargs)
261 def __create_port_config(neutron, networks):
263 Returns a list of port settings based on the networks parameter
264 :param neutron: the neutron client
265 :param networks: a list of tuples where #1 is the SNAPS Network domain
266 object and #2 is a list of IP addresses
271 for network, ips in networks:
272 ports = neutron_utils.get_ports(neutron, network, ips)
274 if port.device_owner != 'network:dhcp':
276 for ip_dict in port.ips:
277 subnet = neutron_utils.get_subnet_by_id(
278 neutron, ip_dict['subnet_id'])
279 ip_addrs.append({'subnet_name': subnet.name,
280 'ip': ip_dict['ip_address']})
284 kwargs['name'] = port.name
285 kwargs['network_name'] = network.name
286 kwargs['mac_address'] = port.mac_address
287 kwargs['allowed_address_pairs'] = port.allowed_address_pairs
288 kwargs['admin_state_up'] = port.admin_state_up
289 kwargs['ip_addrs'] = ip_addrs
290 out.append(PortConfig(**kwargs))
295 def __create_floatingip_settings(neutron, port_settings):
297 Returns a list of FloatingIPSettings objects as they pertain to an
298 existing deployed server instance
299 :param neutron: the neutron client
300 :param port_settings: list of SNAPS-OO PortConfig objects
301 :return: a list of FloatingIPSettings objects or an empty list if no
302 floating IPs have been created
304 base_fip_name = 'fip-'
309 for port_setting in port_settings:
310 setting_port = neutron_utils.get_port(neutron, port_setting)
312 network = neutron_utils.get_network(
313 neutron, network_name=port_setting.network_name)
314 network_ports = neutron_utils.get_ports(neutron, network)
316 for setting_port in network_ports:
317 if port_setting.mac_address == setting_port.mac_address:
318 fip_ports.append((port_setting.name, setting_port))
321 floating_ips = neutron_utils.get_floating_ips(neutron, fip_ports)
323 for port_id, floating_ip in floating_ips:
324 router = neutron_utils.get_router_by_id(neutron, floating_ip.router_id)
325 setting_port = neutron_utils.get_port_by_id(
326 neutron, floating_ip.port_id)
328 kwargs['name'] = base_fip_name + str(fip_ctr)
329 kwargs['port_name'] = setting_port.name
330 kwargs['port_id'] = setting_port.id
331 kwargs['router_name'] = router.name
334 for ip_dict in setting_port.ips:
335 if ('ip_address' in ip_dict and
336 'subnet_id' in ip_dict and
337 ip_dict['ip_address'] == floating_ip.fixed_ip_address):
338 subnet = neutron_utils.get_subnet_by_id(
339 neutron, ip_dict['subnet_id'])
341 kwargs['subnet_name'] = subnet.name
343 out.append(FloatingIpSettings(**kwargs))
350 def determine_image_config(glance, server, image_settings):
352 Returns a ImageConfig object from the list that matches the name in one
353 of the image_settings parameter
354 :param glance: the glance client
355 :param server: a SNAPS-OO VmInst domain object
356 :param image_settings: list of ImageConfig objects
357 :return: ImageConfig or None
360 for image_setting in image_settings:
361 image = glance_utils.get_image_by_id(glance, server.image_id)
362 if image and image.name == image_setting.name:
366 def determine_keypair_config(heat_cli, stack, server, keypair_settings=None,
369 Returns a KeypairConfig object from the list that matches the
370 server.keypair_name value in the keypair_settings parameter if not None,
371 else if the output_key is not None, the output's value when contains the
372 string 'BEGIN RSA PRIVATE KEY', this value will be stored into a file and
373 encoded into the KeypairConfig object returned
374 :param heat_cli: the OpenStack heat client
375 :param stack: a SNAPS-OO Stack domain object
376 :param server: a SNAPS-OO VmInst domain object
377 :param keypair_settings: list of KeypairConfig objects
378 :param priv_key_key: the stack options that holds the private key value
379 :return: KeypairConfig or None
381 # Existing keypair being used by Heat Template
383 for keypair_setting in keypair_settings:
384 if server.keypair_name == keypair_setting.name:
385 return keypair_setting
387 # Keypair created by Heat template
389 outputs = heat_utils.get_outputs(heat_cli, stack)
390 for output in outputs:
391 if output.key == priv_key_key:
394 key_file = file_utils.save_string_to_file(
395 output.value, str(guid), 0o400)
397 # Use outputs, file and resources for the KeypairConfig
398 return KeypairConfig(
399 name=server.keypair_name, private_filepath=key_file.name)