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.openstack.create_flavor import FlavorSettings
19 from snaps.openstack.create_instance import (
20 VmInstanceSettings, FloatingIpSettings)
21 from snaps.openstack.create_keypairs import KeypairSettings
22 from snaps.openstack.create_network import (
23 PortSettings, SubnetSettings, NetworkSettings)
24 from snaps.openstack.create_router import RouterSettings
25 from snaps.openstack.create_volume import VolumeSettings
26 from snaps.openstack.create_volume_type import (
27 VolumeTypeSettings, VolumeTypeEncryptionSettings, ControlLocation)
28 from snaps.openstack.utils import (
29 neutron_utils, nova_utils, heat_utils, glance_utils)
32 def create_network_settings(neutron, network):
34 Returns a NetworkSettings object
35 :param neutron: the neutron client
36 :param network: a SNAPS-OO Network domain object
39 return NetworkSettings(
40 name=network.name, network_type=network.type,
41 subnet_settings=create_subnet_settings(neutron, network))
44 def create_subnet_settings(neutron, network):
46 Returns a list of SubnetSettings objects for a given network
47 :param neutron: the OpenStack neutron client
48 :param network: the SNAPS-OO Network domain object
53 subnets = neutron_utils.get_subnets_by_network(neutron, network)
54 for subnet in subnets:
56 kwargs['cidr'] = subnet.cidr
57 kwargs['ip_version'] = subnet.ip_version
58 kwargs['name'] = subnet.name
59 kwargs['start'] = subnet.start
60 kwargs['end'] = subnet.end
61 kwargs['gateway_ip'] = subnet.gateway_ip
62 kwargs['enable_dhcp'] = subnet.enable_dhcp
63 kwargs['dns_nameservers'] = subnet.dns_nameservers
64 kwargs['host_routes'] = subnet.host_routes
65 kwargs['ipv6_ra_mode'] = subnet.ipv6_ra_mode
66 kwargs['ipv6_address_mode'] = subnet.ipv6_address_mode
67 out.append(SubnetSettings(**kwargs))
71 def create_router_settings(neutron, router):
73 Returns a RouterSettings object
74 :param neutron: the neutron client
75 :param router: a SNAPS-OO Router domain object
80 if router.external_network_id:
81 network = neutron_utils.get_network_by_id(
82 neutron, router.external_network_id)
84 ext_net_name = network.name
86 ports_tuple_list = list()
87 if router.port_subnets:
88 for port, subnets in router.port_subnets:
89 network = neutron_utils.get_network_by_id(
90 neutron, port.network_id)
93 if network and router.external_fixed_ips:
94 for ext_fixed_ips in router.external_fixed_ips:
95 for subnet in subnets:
96 if ext_fixed_ips['subnet_id'] == subnet.id:
97 ip_addrs.append(ext_fixed_ips['ip_address'])
103 if len(ip_addrs) > 0:
104 for ip_addr in ip_addrs:
105 if isinstance(ip_addr, dict):
106 ip_list.append(ip_addr['ip_address'])
108 ip_list.append(ip_addr)
110 ports_tuple_list.append((network, ip_list))
112 port_settings = __create_port_settings(neutron, ports_tuple_list)
114 filtered_settings = list()
115 for port_setting in port_settings:
116 if port_setting.network_name != ext_net_name:
117 filtered_settings.append(port_setting)
119 return RouterSettings(
120 name=router.name, external_gateway=ext_net_name,
121 admin_state_up=router.admin_state_up,
122 port_settings=filtered_settings)
125 def create_volume_settings(volume):
127 Returns a VolumeSettings object
128 :param volume: a SNAPS-OO Volume object
131 return VolumeSettings(
132 name=volume.name, description=volume.description,
133 size=volume.size, type_name=volume.type,
134 availability_zone=volume.availability_zone,
135 multi_attach=volume.multi_attach)
138 def create_volume_type_settings(volume_type):
140 Returns a VolumeTypeSettings object
141 :param volume_type: a SNAPS-OO VolumeType object
145 if volume_type.encryption:
146 if (volume_type.encryption.control_location
147 == ControlLocation.front_end.value):
148 control = ControlLocation.front_end
150 control = ControlLocation.back_end
152 encrypt_settings = VolumeTypeEncryptionSettings(
153 name=volume_type.encryption.__class__,
154 provider_class=volume_type.encryption.provider,
155 control_location=control,
156 cipher=volume_type.encryption.cipher,
157 key_size=volume_type.encryption.key_size)
160 if volume_type.qos_spec:
161 qos_spec_name = volume_type.qos_spec.name
163 return VolumeTypeSettings(
164 name=volume_type.name, encryption=encrypt_settings,
165 qos_spec_name=qos_spec_name, public=volume_type.public)
168 def create_flavor_settings(flavor):
170 Returns a VolumeSettings object
171 :param flavor: a SNAPS-OO Volume object
173 return FlavorSettings(
174 name=flavor.name, flavor_id=flavor.id, ram=flavor.ram,
175 disk=flavor.disk, vcpus=flavor.vcpus, ephemeral=flavor.ephemeral,
176 swap=flavor.swap, rxtx_factor=flavor.rxtx_factor,
177 is_public=flavor.is_public)
180 def create_keypair_settings(heat_cli, stack, keypair, pk_output_key):
182 Instantiates a KeypairSettings object from a Keypair domain objects
183 :param heat_cli: the heat client
184 :param stack: the Stack domain object
185 :param keypair: the Keypair SNAPS domain object
186 :param pk_output_key: the key to the heat template's outputs for retrieval
187 of the private key file
188 :return: a KeypairSettings object
191 outputs = heat_utils.get_outputs(heat_cli, stack)
192 for output in outputs:
193 if output.key == pk_output_key:
196 key_file = file_utils.save_string_to_file(
197 output.value, str(guid), 0o400)
199 # Use outputs, file and resources for the KeypairSettings
200 return KeypairSettings(
201 name=keypair.name, private_filepath=key_file.name)
203 return KeypairSettings(name=keypair.name)
206 def create_vm_inst_settings(nova, neutron, server):
208 Returns a NetworkSettings object
209 :param nova: the nova client
210 :param neutron: the neutron client
211 :param server: a SNAPS-OO VmInst domain object
215 flavor_name = nova_utils.get_flavor_by_id(nova, server.flavor_id)
218 kwargs['name'] = server.name
219 kwargs['flavor'] = flavor_name
222 for net_name, ips in server.networks.items():
223 network = neutron_utils.get_network(neutron, network_name=net_name)
225 net_tuples.append((network, ips))
227 kwargs['port_settings'] = __create_port_settings(
229 kwargs['security_group_names'] = server.sec_grp_names
230 kwargs['floating_ip_settings'] = __create_floatingip_settings(
231 neutron, kwargs['port_settings'])
233 return VmInstanceSettings(**kwargs)
236 def __create_port_settings(neutron, networks):
238 Returns a list of port settings based on the networks parameter
239 :param neutron: the neutron client
240 :param networks: a list of tuples where #1 is the SNAPS Network domain
241 object and #2 is a list of IP addresses
246 for network, ips in networks:
247 ports = neutron_utils.get_ports(neutron, network, ips)
249 if port.device_owner != 'network:dhcp':
251 for ip_dict in port.ips:
252 subnet = neutron_utils.get_subnet_by_id(
253 neutron, ip_dict['subnet_id'])
254 ip_addrs.append({'subnet_name': subnet.name,
255 'ip': ip_dict['ip_address']})
259 kwargs['name'] = port.name
260 kwargs['network_name'] = network.name
261 kwargs['mac_address'] = port.mac_address
262 kwargs['allowed_address_pairs'] = port.allowed_address_pairs
263 kwargs['admin_state_up'] = port.admin_state_up
264 kwargs['ip_addrs'] = ip_addrs
265 out.append(PortSettings(**kwargs))
270 def __create_floatingip_settings(neutron, port_settings):
272 Returns a list of FloatingIPSettings objects as they pertain to an
273 existing deployed server instance
274 :param neutron: the neutron client
275 :param port_settings: list of SNAPS-OO PortSettings objects
276 :return: a list of FloatingIPSettings objects or an empty list if no
277 floating IPs have been created
279 base_fip_name = 'fip-'
284 for port_setting in port_settings:
285 setting_port = neutron_utils.get_port(neutron, port_setting)
287 network = neutron_utils.get_network(
288 neutron, network_name=port_setting.network_name)
289 network_ports = neutron_utils.get_ports(neutron, network)
291 for setting_port in network_ports:
292 if port_setting.mac_address == setting_port.mac_address:
293 fip_ports.append((port_setting.name, setting_port))
296 floating_ips = neutron_utils.get_floating_ips(neutron, fip_ports)
298 for port_id, floating_ip in floating_ips:
299 router = neutron_utils.get_router_by_id(neutron, floating_ip.router_id)
300 setting_port = neutron_utils.get_port_by_id(
301 neutron, floating_ip.port_id)
303 kwargs['name'] = base_fip_name + str(fip_ctr)
304 kwargs['port_name'] = setting_port.name
305 kwargs['port_id'] = setting_port.id
306 kwargs['router_name'] = router.name
309 for ip_dict in setting_port.ips:
310 if ('ip_address' in ip_dict and
311 'subnet_id' in ip_dict and
312 ip_dict['ip_address'] == floating_ip.fixed_ip_address):
313 subnet = neutron_utils.get_subnet_by_id(
314 neutron, ip_dict['subnet_id'])
316 kwargs['subnet_name'] = subnet.name
318 out.append(FloatingIpSettings(**kwargs))
325 def determine_image_settings(glance, server, image_settings):
327 Returns a ImageSettings object from the list that matches the name in one
328 of the image_settings parameter
329 :param glance: the glance client
330 :param server: a SNAPS-OO VmInst domain object
331 :param image_settings: list of ImageSettings objects
332 :return: ImageSettings or None
335 for image_setting in image_settings:
336 image = glance_utils.get_image_by_id(glance, server.image_id)
337 if image and image.name == image_setting.name:
341 def determine_keypair_settings(heat_cli, stack, server, keypair_settings=None,
344 Returns a KeypairSettings object from the list that matches the
345 server.keypair_name value in the keypair_settings parameter if not None,
346 else if the output_key is not None, the output's value when contains the
347 string 'BEGIN RSA PRIVATE KEY', this value will be stored into a file and
348 encoded into the KeypairSettings object returned
349 :param heat_cli: the OpenStack heat client
350 :param stack: a SNAPS-OO Stack domain object
351 :param server: a SNAPS-OO VmInst domain object
352 :param keypair_settings: list of KeypairSettings objects
353 :param priv_key_key: the stack options that holds the private key value
354 :return: KeypairSettings or None
356 # Existing keypair being used by Heat Template
358 for keypair_setting in keypair_settings:
359 if server.keypair_name == keypair_setting.name:
360 return keypair_setting
362 # Keypair created by Heat template
364 outputs = heat_utils.get_outputs(heat_cli, stack)
365 for output in outputs:
366 if output.key == priv_key_key:
369 key_file = file_utils.save_string_to_file(
370 output.value, str(guid), 0o400)
372 # Use outputs, file and resources for the KeypairSettings
373 return KeypairSettings(
374 name=server.keypair_name, private_filepath=key_file.name)