Added method to OpenStackHeatStack to return OpenStackFlavor objects.
[snaps.git] / snaps / openstack / utils / settings_utils.py
1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
3 #
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:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
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.
15 import uuid
16
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_volume import VolumeSettings
25 from snaps.openstack.create_volume_type import (
26     VolumeTypeSettings, VolumeTypeEncryptionSettings, ControlLocation)
27 from snaps.openstack.utils import (
28     neutron_utils, nova_utils, heat_utils, glance_utils)
29
30
31 def create_network_settings(neutron, network):
32     """
33     Returns a NetworkSettings object
34     :param neutron: the neutron client
35     :param network: a SNAPS-OO Network domain object
36     :return:
37     """
38     return NetworkSettings(
39         name=network.name, network_type=network.type,
40         subnet_settings=create_subnet_settings(neutron, network))
41
42
43 def create_subnet_settings(neutron, network):
44     """
45     Returns a list of SubnetSettings objects for a given network
46     :param neutron: the OpenStack neutron client
47     :param network: the SNAPS-OO Network domain object
48     :return: a list
49     """
50     out = list()
51
52     subnets = neutron_utils.get_subnets_by_network(neutron, network)
53     for subnet in subnets:
54         kwargs = dict()
55         kwargs['cidr'] = subnet.cidr
56         kwargs['ip_version'] = subnet.ip_version
57         kwargs['name'] = subnet.name
58         kwargs['start'] = subnet.start
59         kwargs['end'] = subnet.end
60         kwargs['gateway_ip'] = subnet.gateway_ip
61         kwargs['enable_dhcp'] = subnet.enable_dhcp
62         kwargs['dns_nameservers'] = subnet.dns_nameservers
63         kwargs['host_routes'] = subnet.host_routes
64         kwargs['ipv6_ra_mode'] = subnet.ipv6_ra_mode
65         kwargs['ipv6_address_mode'] = subnet.ipv6_address_mode
66         out.append(SubnetSettings(**kwargs))
67     return out
68
69
70 def create_volume_settings(volume):
71     """
72     Returns a VolumeSettings object
73     :param volume: a SNAPS-OO Volume object
74     """
75
76     return VolumeSettings(
77         name=volume.name, description=volume.description,
78         size=volume.size, type_name=volume.type,
79         availability_zone=volume.availability_zone,
80         multi_attach=volume.multi_attach)
81
82
83 def create_volume_type_settings(volume_type):
84     """
85     Returns a VolumeTypeSettings object
86     :param volume_type: a SNAPS-OO VolumeType object
87     """
88
89     control = None
90     if volume_type.encryption:
91         if (volume_type.encryption.control_location
92                 == ControlLocation.front_end.value):
93             control = ControlLocation.front_end
94         else:
95             control = ControlLocation.back_end
96
97     encrypt_settings = VolumeTypeEncryptionSettings(
98         name=volume_type.encryption.__class__,
99         provider_class=volume_type.encryption.provider,
100         control_location=control,
101         cipher=volume_type.encryption.cipher,
102         key_size=volume_type.encryption.key_size)
103
104     qos_spec_name = None
105     if volume_type.qos_spec:
106         qos_spec_name = volume_type.qos_spec.name
107
108     return VolumeTypeSettings(
109         name=volume_type.name, encryption=encrypt_settings,
110         qos_spec_name=qos_spec_name, public=volume_type.public)
111
112
113 def create_flavor_settings(flavor):
114     """
115     Returns a VolumeSettings object
116     :param flavor: a SNAPS-OO Volume object
117     """
118     return FlavorSettings(
119         name=flavor.name, flavor_id=flavor.id, ram=flavor.ram,
120         disk=flavor.disk, vcpus=flavor.vcpus, ephemeral=flavor.ephemeral,
121         swap=flavor.swap, rxtx_factor=flavor.rxtx_factor,
122         is_public=flavor.is_public)
123
124
125 def create_keypair_settings(heat_cli, stack, keypair, pk_output_key):
126     """
127     Instantiates a KeypairSettings object from a Keypair domain objects
128     :param heat_cli: the heat client
129     :param stack: the Stack domain object
130     :param keypair: the Keypair SNAPS domain object
131     :param pk_output_key: the key to the heat template's outputs for retrieval
132                           of the private key file
133     :return: a KeypairSettings object
134     """
135     if pk_output_key:
136         outputs = heat_utils.get_outputs(heat_cli, stack)
137         for output in outputs:
138             if output.key == pk_output_key:
139                 # Save to file
140                 guid = uuid.uuid4()
141                 key_file = file_utils.save_string_to_file(
142                     output.value, str(guid), 0o400)
143
144                 # Use outputs, file and resources for the KeypairSettings
145                 return KeypairSettings(
146                     name=keypair.name, private_filepath=key_file.name)
147
148     return KeypairSettings(name=keypair.name)
149
150
151 def create_vm_inst_settings(nova, neutron, server):
152     """
153     Returns a NetworkSettings object
154     :param nova: the nova client
155     :param neutron: the neutron client
156     :param server: a SNAPS-OO VmInst domain object
157     :return:
158     """
159
160     flavor_name = nova_utils.get_flavor_by_id(nova, server.flavor_id)
161
162     kwargs = dict()
163     kwargs['name'] = server.name
164     kwargs['flavor'] = flavor_name
165     kwargs['port_settings'] = __create_port_settings(
166         neutron, server.networks)
167     kwargs['security_group_names'] = server.sec_grp_names
168     kwargs['floating_ip_settings'] = __create_floatingip_settings(
169         neutron, kwargs['port_settings'])
170
171     return VmInstanceSettings(**kwargs)
172
173
174 def __create_port_settings(neutron, networks):
175     """
176     Returns a list of port settings based on the networks parameter
177     :param neutron: the neutron client
178     :param networks: a dict where the key is the network name and the value
179                      is a list of IP addresses
180     :return:
181     """
182     out = list()
183
184     for net_name, ips in networks.items():
185         network = neutron_utils.get_network(neutron, network_name=net_name)
186         ports = neutron_utils.get_ports(neutron, network, ips)
187         for port in ports:
188             kwargs = dict()
189             if port.name:
190                 kwargs['name'] = port.name
191             kwargs['network_name'] = network.name
192             kwargs['mac_address'] = port.mac_address
193             kwargs['allowed_address_pairs'] = port.allowed_address_pairs
194             kwargs['admin_state_up'] = port.admin_state_up
195             out.append(PortSettings(**kwargs))
196
197     return out
198
199
200 def __create_floatingip_settings(neutron, port_settings):
201     """
202     Returns a list of FloatingIPSettings objects as they pertain to an
203     existing deployed server instance
204     :param neutron: the neutron client
205     :param port_settings: list of SNAPS-OO PortSettings objects
206     :return: a list of FloatingIPSettings objects or an empty list if no
207              floating IPs have been created
208     """
209     base_fip_name = 'fip-'
210     fip_ctr = 1
211     out = list()
212
213     fip_ports = list()
214     for port_setting in port_settings:
215         setting_port = neutron_utils.get_port(neutron, port_setting)
216         if setting_port:
217             network = neutron_utils.get_network(
218                 neutron, network_name=port_setting.network_name)
219             network_ports = neutron_utils.get_ports(neutron, network)
220             if network_ports:
221                 for setting_port in network_ports:
222                     if port_setting.mac_address == setting_port.mac_address:
223                         fip_ports.append((port_setting.name, setting_port))
224                         break
225
226     floating_ips = neutron_utils.get_floating_ips(neutron, fip_ports)
227
228     for port_id, floating_ip in floating_ips:
229         router = neutron_utils.get_router_by_id(neutron, floating_ip.router_id)
230         setting_port = neutron_utils.get_port_by_id(
231             neutron, floating_ip.port_id)
232         kwargs = dict()
233         kwargs['name'] = base_fip_name + str(fip_ctr)
234         kwargs['port_name'] = setting_port.name
235         kwargs['port_id'] = setting_port.id
236         kwargs['router_name'] = router.name
237
238         if setting_port:
239             for ip_dict in setting_port.ips:
240                 if ('ip_address' in ip_dict and
241                         'subnet_id' in ip_dict and
242                         ip_dict['ip_address'] == floating_ip.fixed_ip_address):
243                     subnet = neutron_utils.get_subnet_by_id(
244                         neutron, ip_dict['subnet_id'])
245                     if subnet:
246                         kwargs['subnet_name'] = subnet.name
247
248         out.append(FloatingIpSettings(**kwargs))
249
250         fip_ctr += 1
251
252     return out
253
254
255 def determine_image_settings(glance, server, image_settings):
256     """
257     Returns a ImageSettings object from the list that matches the name in one
258     of the image_settings parameter
259     :param glance: the glance client
260     :param server: a SNAPS-OO VmInst domain object
261     :param image_settings: list of ImageSettings objects
262     :return: ImageSettings or None
263     """
264     if image_settings:
265         for image_setting in image_settings:
266             image = glance_utils.get_image_by_id(glance, server.image_id)
267             if image and image.name == image_setting.name:
268                 return image_setting
269
270
271 def determine_keypair_settings(heat_cli, stack, server, keypair_settings=None,
272                                priv_key_key=None):
273     """
274     Returns a KeypairSettings object from the list that matches the
275     server.keypair_name value in the keypair_settings parameter if not None,
276     else if the output_key is not None, the output's value when contains the
277     string 'BEGIN RSA PRIVATE KEY', this value will be stored into a file and
278     encoded into the KeypairSettings object returned
279     :param heat_cli: the OpenStack heat client
280     :param stack: a SNAPS-OO Stack domain object
281     :param server: a SNAPS-OO VmInst domain object
282     :param keypair_settings: list of KeypairSettings objects
283     :param priv_key_key: the stack options that holds the private key value
284     :return: KeypairSettings or None
285     """
286     # Existing keypair being used by Heat Template
287     if keypair_settings:
288         for keypair_setting in keypair_settings:
289             if server.keypair_name == keypair_setting.name:
290                 return keypair_setting
291
292     # Keypair created by Heat template
293     if priv_key_key:
294         outputs = heat_utils.get_outputs(heat_cli, stack)
295         for output in outputs:
296             if output.key == priv_key_key:
297                 # Save to file
298                 guid = uuid.uuid4()
299                 key_file = file_utils.save_string_to_file(
300                     output.value, str(guid), 0o400)
301
302                 # Use outputs, file and resources for the KeypairSettings
303                 return KeypairSettings(
304                     name=server.keypair_name, private_filepath=key_file.name)