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.router import RouterConfig
21 from snaps.openstack.create_instance import (
22 VmInstanceSettings, FloatingIpSettings)
23 from snaps.openstack.create_network import (
24 PortSettings, SubnetSettings, NetworkSettings)
25 from snaps.openstack.create_security_group import (
26 SecurityGroupSettings, SecurityGroupRuleSettings)
27 from snaps.openstack.create_volume import VolumeSettings
28 from snaps.openstack.create_volume_type import (
29 VolumeTypeSettings, VolumeTypeEncryptionSettings, ControlLocation)
30 from snaps.openstack.utils import (
31 neutron_utils, nova_utils, heat_utils, glance_utils)
34 def create_network_settings(neutron, network):
36 Returns a NetworkSettings object
37 :param neutron: the neutron client
38 :param network: a SNAPS-OO Network domain object
41 return NetworkSettings(
42 name=network.name, network_type=network.type,
43 subnet_settings=create_subnet_settings(neutron, network))
46 def create_security_group_settings(neutron, security_group):
48 Returns a NetworkSettings object
49 :param neutron: the neutron client
50 :param security_group: a SNAPS-OO SecurityGroup domain object
53 rules = neutron_utils.get_rules_by_security_group(neutron, security_group)
55 rule_settings = list()
57 rule_settings.append(SecurityGroupRuleSettings(
58 sec_grp_name=security_group.name, description=rule.description,
59 direction=rule.direction, ethertype=rule.ethertype,
60 port_range_min=rule.port_range_min,
61 port_range_max=rule.port_range_max, protocol=rule.protocol,
62 remote_group_id=rule.remote_group_id,
63 remote_ip_prefix=rule.remote_ip_prefix))
65 return SecurityGroupSettings(
66 name=security_group.name, description=security_group.description,
67 rule_settings=rule_settings)
70 def create_subnet_settings(neutron, network):
72 Returns a list of SubnetSettings objects for a given network
73 :param neutron: the OpenStack neutron client
74 :param network: the SNAPS-OO Network domain object
79 subnets = neutron_utils.get_subnets_by_network(neutron, network)
80 for subnet in subnets:
82 kwargs['cidr'] = subnet.cidr
83 kwargs['ip_version'] = subnet.ip_version
84 kwargs['name'] = subnet.name
85 kwargs['start'] = subnet.start
86 kwargs['end'] = subnet.end
87 kwargs['gateway_ip'] = subnet.gateway_ip
88 kwargs['enable_dhcp'] = subnet.enable_dhcp
89 kwargs['dns_nameservers'] = subnet.dns_nameservers
90 kwargs['host_routes'] = subnet.host_routes
91 kwargs['ipv6_ra_mode'] = subnet.ipv6_ra_mode
92 kwargs['ipv6_address_mode'] = subnet.ipv6_address_mode
93 out.append(SubnetSettings(**kwargs))
97 def create_router_settings(neutron, router):
99 Returns a RouterConfig object
100 :param neutron: the neutron client
101 :param router: a SNAPS-OO Router domain object
106 if router.external_network_id:
107 network = neutron_utils.get_network_by_id(
108 neutron, router.external_network_id)
110 ext_net_name = network.name
112 ports_tuple_list = list()
113 if router.port_subnets:
114 for port, subnets in router.port_subnets:
115 network = neutron_utils.get_network_by_id(
116 neutron, port.network_id)
119 if network and router.external_fixed_ips:
120 for ext_fixed_ips in router.external_fixed_ips:
121 for subnet in subnets:
122 if ext_fixed_ips['subnet_id'] == subnet.id:
123 ip_addrs.append(ext_fixed_ips['ip_address'])
129 if len(ip_addrs) > 0:
130 for ip_addr in ip_addrs:
131 if isinstance(ip_addr, dict):
132 ip_list.append(ip_addr['ip_address'])
134 ip_list.append(ip_addr)
136 ports_tuple_list.append((network, ip_list))
138 port_settings = __create_port_settings(neutron, ports_tuple_list)
140 filtered_settings = list()
141 for port_setting in port_settings:
142 if port_setting.network_name != ext_net_name:
143 filtered_settings.append(port_setting)
146 name=router.name, external_gateway=ext_net_name,
147 admin_state_up=router.admin_state_up,
148 port_settings=filtered_settings)
151 def create_volume_settings(volume):
153 Returns a VolumeSettings object
154 :param volume: a SNAPS-OO Volume object
157 return VolumeSettings(
158 name=volume.name, description=volume.description,
159 size=volume.size, type_name=volume.type,
160 availability_zone=volume.availability_zone,
161 multi_attach=volume.multi_attach)
164 def create_volume_type_settings(volume_type):
166 Returns a VolumeTypeSettings object
167 :param volume_type: a SNAPS-OO VolumeType object
171 if volume_type.encryption:
172 if (volume_type.encryption.control_location
173 == ControlLocation.front_end.value):
174 control = ControlLocation.front_end
176 control = ControlLocation.back_end
178 encrypt_settings = VolumeTypeEncryptionSettings(
179 name=volume_type.encryption.__class__,
180 provider_class=volume_type.encryption.provider,
181 control_location=control,
182 cipher=volume_type.encryption.cipher,
183 key_size=volume_type.encryption.key_size)
186 if volume_type.qos_spec:
187 qos_spec_name = volume_type.qos_spec.name
189 return VolumeTypeSettings(
190 name=volume_type.name, encryption=encrypt_settings,
191 qos_spec_name=qos_spec_name, public=volume_type.public)
194 def create_flavor_config(flavor):
196 Returns a VolumeSettings object
197 :param flavor: a SNAPS-OO Volume object
200 name=flavor.name, flavor_id=flavor.id, ram=flavor.ram,
201 disk=flavor.disk, vcpus=flavor.vcpus, ephemeral=flavor.ephemeral,
202 swap=flavor.swap, rxtx_factor=flavor.rxtx_factor,
203 is_public=flavor.is_public)
206 def create_keypair_settings(heat_cli, stack, keypair, pk_output_key):
208 Instantiates a KeypairConfig object from a Keypair domain objects
209 :param heat_cli: the heat client
210 :param stack: the Stack domain object
211 :param keypair: the Keypair SNAPS domain object
212 :param pk_output_key: the key to the heat template's outputs for retrieval
213 of the private key file
214 :return: a KeypairConfig object
217 outputs = heat_utils.get_outputs(heat_cli, stack)
218 for output in outputs:
219 if output.key == pk_output_key:
222 key_file = file_utils.save_string_to_file(
223 output.value, str(guid), 0o400)
225 # Use outputs, file and resources for the KeypairConfig
226 return KeypairConfig(
227 name=keypair.name, private_filepath=key_file.name)
229 return KeypairConfig(name=keypair.name)
232 def create_vm_inst_settings(nova, neutron, server):
234 Returns a NetworkSettings object
235 :param nova: the nova client
236 :param neutron: the neutron client
237 :param server: a SNAPS-OO VmInst domain object
241 flavor_name = nova_utils.get_flavor_by_id(nova, server.flavor_id)
244 kwargs['name'] = server.name
245 kwargs['flavor'] = flavor_name
248 for net_name, ips in server.networks.items():
249 network = neutron_utils.get_network(neutron, network_name=net_name)
251 net_tuples.append((network, ips))
253 kwargs['port_settings'] = __create_port_settings(
255 kwargs['security_group_names'] = server.sec_grp_names
256 kwargs['floating_ip_settings'] = __create_floatingip_settings(
257 neutron, kwargs['port_settings'])
259 return VmInstanceSettings(**kwargs)
262 def __create_port_settings(neutron, networks):
264 Returns a list of port settings based on the networks parameter
265 :param neutron: the neutron client
266 :param networks: a list of tuples where #1 is the SNAPS Network domain
267 object and #2 is a list of IP addresses
272 for network, ips in networks:
273 ports = neutron_utils.get_ports(neutron, network, ips)
275 if port.device_owner != 'network:dhcp':
277 for ip_dict in port.ips:
278 subnet = neutron_utils.get_subnet_by_id(
279 neutron, ip_dict['subnet_id'])
280 ip_addrs.append({'subnet_name': subnet.name,
281 'ip': ip_dict['ip_address']})
285 kwargs['name'] = port.name
286 kwargs['network_name'] = network.name
287 kwargs['mac_address'] = port.mac_address
288 kwargs['allowed_address_pairs'] = port.allowed_address_pairs
289 kwargs['admin_state_up'] = port.admin_state_up
290 kwargs['ip_addrs'] = ip_addrs
291 out.append(PortSettings(**kwargs))
296 def __create_floatingip_settings(neutron, port_settings):
298 Returns a list of FloatingIPSettings objects as they pertain to an
299 existing deployed server instance
300 :param neutron: the neutron client
301 :param port_settings: list of SNAPS-OO PortSettings objects
302 :return: a list of FloatingIPSettings objects or an empty list if no
303 floating IPs have been created
305 base_fip_name = 'fip-'
310 for port_setting in port_settings:
311 setting_port = neutron_utils.get_port(neutron, port_setting)
313 network = neutron_utils.get_network(
314 neutron, network_name=port_setting.network_name)
315 network_ports = neutron_utils.get_ports(neutron, network)
317 for setting_port in network_ports:
318 if port_setting.mac_address == setting_port.mac_address:
319 fip_ports.append((port_setting.name, setting_port))
322 floating_ips = neutron_utils.get_floating_ips(neutron, fip_ports)
324 for port_id, floating_ip in floating_ips:
325 router = neutron_utils.get_router_by_id(neutron, floating_ip.router_id)
326 setting_port = neutron_utils.get_port_by_id(
327 neutron, floating_ip.port_id)
329 kwargs['name'] = base_fip_name + str(fip_ctr)
330 kwargs['port_name'] = setting_port.name
331 kwargs['port_id'] = setting_port.id
332 kwargs['router_name'] = router.name
335 for ip_dict in setting_port.ips:
336 if ('ip_address' in ip_dict and
337 'subnet_id' in ip_dict and
338 ip_dict['ip_address'] == floating_ip.fixed_ip_address):
339 subnet = neutron_utils.get_subnet_by_id(
340 neutron, ip_dict['subnet_id'])
342 kwargs['subnet_name'] = subnet.name
344 out.append(FloatingIpSettings(**kwargs))
351 def determine_image_config(glance, server, image_settings):
353 Returns a ImageConfig object from the list that matches the name in one
354 of the image_settings parameter
355 :param glance: the glance client
356 :param server: a SNAPS-OO VmInst domain object
357 :param image_settings: list of ImageConfig objects
358 :return: ImageConfig or None
361 for image_setting in image_settings:
362 image = glance_utils.get_image_by_id(glance, server.image_id)
363 if image and image.name == image_setting.name:
367 def determine_keypair_config(heat_cli, stack, server, keypair_settings=None,
370 Returns a KeypairConfig object from the list that matches the
371 server.keypair_name value in the keypair_settings parameter if not None,
372 else if the output_key is not None, the output's value when contains the
373 string 'BEGIN RSA PRIVATE KEY', this value will be stored into a file and
374 encoded into the KeypairConfig object returned
375 :param heat_cli: the OpenStack heat client
376 :param stack: a SNAPS-OO Stack domain object
377 :param server: a SNAPS-OO VmInst domain object
378 :param keypair_settings: list of KeypairConfig objects
379 :param priv_key_key: the stack options that holds the private key value
380 :return: KeypairConfig or None
382 # Existing keypair being used by Heat Template
384 for keypair_setting in keypair_settings:
385 if server.keypair_name == keypair_setting.name:
386 return keypair_setting
388 # Keypair created by Heat template
390 outputs = heat_utils.get_outputs(heat_cli, stack)
391 for output in outputs:
392 if output.key == priv_key_key:
395 key_file = file_utils.save_string_to_file(
396 output.value, str(guid), 0o400)
398 # Use outputs, file and resources for the KeypairConfig
399 return KeypairConfig(
400 name=server.keypair_name, private_filepath=key_file.name)