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.
16 from cryptography.hazmat.primitives import serialization
17 from cryptography.hazmat.primitives.asymmetric import rsa
18 from cryptography.hazmat.backends import default_backend
22 from snaps.openstack.utils import keystone_utils
24 from novaclient.client import Client
25 from novaclient.exceptions import NotFound
27 __author__ = 'spisarski'
29 logger = logging.getLogger('nova_utils')
32 Utilities for basic OpenStack Nova API calls
36 def nova_client(os_creds):
38 Instantiates and returns a client for communications with OpenStack's Nova server
39 :param os_creds: The connection credentials to the OpenStack API
40 :return: the client object
42 logger.debug('Retrieving Nova Client')
43 return Client(os_creds.compute_api_version, session=keystone_utils.keystone_session(os_creds))
46 def get_servers_by_name(nova, name):
48 Returns a list of servers with a given name
49 :param nova: the Nova client
50 :param name: the server name
51 :return: the list of servers
53 return nova.servers.list(search_opts={'name': name})
56 def get_latest_server_object(nova, server):
58 Returns a server with a given id
59 :param nova: the Nova client
60 :param server: the old server object
61 :return: the list of servers or None if not found
63 return nova.servers.get(server)
66 def create_keys(key_size=2048):
68 Generates public and private keys
69 :param key_size: the number of bytes for the key size
70 :return: the cryptography keys
72 return rsa.generate_private_key(backend=default_backend(), public_exponent=65537,
76 def public_key_openssh(keys):
78 Returns the public key for OpenSSH
79 :param keys: the keys generated by create_keys() from cryptography
80 :return: the OpenSSH public key
82 return keys.public_key().public_bytes(serialization.Encoding.OpenSSH, serialization.PublicFormat.OpenSSH)
85 def save_keys_to_files(keys=None, pub_file_path=None, priv_file_path=None):
87 Saves the generated RSA generated keys to the filesystem
88 :param keys: the keys to save generated by cryptography
89 :param pub_file_path: the path to the public keys
90 :param priv_file_path: the path to the private keys
95 pub_dir = os.path.dirname(pub_file_path)
96 if not os.path.isdir(pub_dir):
98 public_handle = open(pub_file_path, 'wb')
99 public_bytes = keys.public_key().public_bytes(
100 serialization.Encoding.OpenSSH, serialization.PublicFormat.OpenSSH)
101 public_handle.write(public_bytes)
102 public_handle.close()
103 os.chmod(pub_file_path, 0o400)
104 logger.info("Saved public key to - " + pub_file_path)
106 priv_dir = os.path.dirname(priv_file_path)
107 if not os.path.isdir(priv_dir):
109 private_handle = open(priv_file_path, 'wb')
110 private_handle.write(keys.private_bytes(encoding=serialization.Encoding.PEM,
111 format=serialization.PrivateFormat.TraditionalOpenSSL,
112 encryption_algorithm=serialization.NoEncryption()))
113 private_handle.close()
114 os.chmod(priv_file_path, 0o400)
115 logger.info("Saved private key to - " + priv_file_path)
118 def upload_keypair_file(nova, name, file_path):
120 Uploads a public key from a file
121 :param nova: the Nova client
122 :param name: the keypair name
123 :param file_path: the path to the public key file
124 :return: the keypair object
126 with open(os.path.expanduser(file_path), 'rb') as fpubkey:
127 logger.info('Saving keypair to - ' + file_path)
128 return upload_keypair(nova, name, fpubkey.read())
131 def upload_keypair(nova, name, key):
133 Uploads a public key from a file
134 :param nova: the Nova client
135 :param name: the keypair name
136 :param key: the public key object
137 :return: the keypair object
139 logger.info('Creating keypair with name - ' + name)
140 return nova.keypairs.create(name=name, public_key=key.decode('utf-8'))
143 def keypair_exists(nova, keypair_obj):
145 Returns a copy of the keypair object if found
146 :param nova: the Nova client
147 :param keypair_obj: the keypair object
148 :return: the keypair object or None if not found
151 return nova.keypairs.get(keypair_obj)
156 def get_keypair_by_name(nova, name):
158 Returns a list of all available keypairs
159 :param nova: the Nova client
160 :param name: the name of the keypair to lookup
161 :return: the keypair object or None if not found
163 keypairs = nova.keypairs.list()
165 for keypair in keypairs:
166 if keypair.name == name:
172 def delete_keypair(nova, key):
174 Deletes a keypair object from OpenStack
175 :param nova: the Nova client
176 :param key: the keypair object to delete
178 logger.debug('Deleting keypair - ' + key.name)
179 nova.keypairs.delete(key)
182 def get_floating_ip_pools(nova):
184 Returns all of the available floating IP pools
185 :param nova: the Nova client
186 :return: a list of pools
188 return nova.floating_ip_pools.list()
191 def get_floating_ips(nova):
193 Returns all of the floating IPs
194 :param nova: the Nova client
195 :return: a list of floating IPs
197 return nova.floating_ips.list()
200 def create_floating_ip(nova, ext_net_name):
202 Returns the floating IP object that was created with this call
203 :param nova: the Nova client
204 :param ext_net_name: the name of the external network on which to apply the floating IP address
205 :return: the floating IP object
207 logger.info('Creating floating ip to external network - ' + ext_net_name)
208 return nova.floating_ips.create(ext_net_name)
211 def get_floating_ip(nova, floating_ip):
213 Returns a floating IP object that should be identical to the floating_ip parameter
214 :param nova: the Nova client
215 :param floating_ip: the floating IP object to lookup
216 :return: hopefully the same floating IP object input
218 logger.debug('Attempting to retrieve existing floating ip with IP - ' + floating_ip.ip)
219 return nova.floating_ips.get(floating_ip)
222 def delete_floating_ip(nova, floating_ip):
224 Responsible for deleting a floating IP
225 :param nova: the Nova client
226 :param floating_ip: the floating IP object to delete
229 logger.debug('Attempting to delete existing floating ip with IP - ' + floating_ip.ip)
230 return nova.floating_ips.delete(floating_ip)
233 def get_nova_availability_zones(nova):
235 Returns the names of all nova compute servers
236 :param nova: the Nova client
237 :return: a list of compute server names
240 zones = nova.availability_zones.list()
242 if zone.zoneName == 'nova':
243 for key, host in zone.hosts.items():
244 out.append(zone.zoneName + ':' + key)
249 def delete_vm_instance(nova, vm_inst):
251 Deletes a VM instance
252 :param nova: the nova client
253 :param vm_inst: the OpenStack instance object to delete
255 nova.servers.delete(vm_inst)
258 def get_flavor_by_name(nova, name):
260 Returns a flavor by name
261 :param nova: the Nova client
262 :param name: the flavor name to return
263 :return: the OpenStack flavor object or None if not exists
266 return nova.flavors.find(name=name)
271 def create_flavor(nova, flavor_settings):
273 Creates and returns and OpenStack flavor object
274 :param nova: the Nova client
275 :param flavor_settings: the flavor settings
278 return nova.flavors.create(name=flavor_settings.name, flavorid=flavor_settings.flavor_id, ram=flavor_settings.ram,
279 vcpus=flavor_settings.vcpus, disk=flavor_settings.disk,
280 ephemeral=flavor_settings.ephemeral, swap=flavor_settings.swap,
281 rxtx_factor=flavor_settings.rxtx_factor, is_public=flavor_settings.is_public)
284 def delete_flavor(nova, flavor):
287 :param nova: the Nova client
288 :param flavor: the OpenStack flavor object
290 nova.flavors.delete(flavor)
293 def add_security_group(nova, vm, security_group_name):
295 Adds a security group to an existing VM
296 :param nova: the nova client
297 :param vm: the OpenStack server object (VM) to alter
298 :param security_group_name: the name of the security group to add
300 nova.servers.add_security_group(str(vm.id), security_group_name)
303 def remove_security_group(nova, vm, security_group):
305 Removes a security group from an existing VM
306 :param nova: the nova client
307 :param vm: the OpenStack server object (VM) to alter
308 :param security_group: the OpenStack security group object to add
310 nova.servers.remove_security_group(str(vm.id), security_group['security_group']['name'])