16374ad9db8169673dcffed4bf9465e080c673a7
[snaps.git] / snaps / openstack / create_keypairs.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 logging
16
17 import os
18 from neutronclient.common.utils import str2bool
19 from novaclient.exceptions import NotFound
20
21 from snaps import file_utils
22 from snaps.openstack.utils import nova_utils
23
24 __author__ = 'spisarski'
25
26 logger = logging.getLogger('OpenStackKeypair')
27
28
29 class OpenStackKeypair:
30     """
31     Class responsible for creating a keypair in OpenStack
32     """
33
34     def __init__(self, os_creds, keypair_settings):
35         """
36         Constructor - all parameters are required
37         :param os_creds: The credentials to connect with OpenStack
38         :param keypair_settings: The settings used to create a keypair
39         """
40         self.__nova = None
41         self.__os_creds = os_creds
42         self.keypair_settings = keypair_settings
43         self.__nova = nova_utils.nova_client(os_creds)
44         self.__delete_keys_on_clean = True
45
46         # Attributes instantiated on create()
47         self.__keypair = None
48
49     def create(self, cleanup=False):
50         """
51         Responsible for creating the keypair object.
52         :param cleanup: Denotes whether or not this is being called for cleanup
53                         or not
54         """
55         self.__nova = nova_utils.nova_client(self.__os_creds)
56
57         logger.info('Creating keypair %s...' % self.keypair_settings.name)
58
59         self.__keypair = nova_utils.get_keypair_by_name(
60             self.__nova, self.keypair_settings.name)
61
62         if not self.__keypair and not cleanup:
63             if self.keypair_settings.public_filepath and os.path.isfile(
64                     self.keypair_settings.public_filepath):
65                 logger.info("Uploading existing keypair")
66                 self.__keypair = nova_utils.upload_keypair_file(
67                     self.__nova, self.keypair_settings.name,
68                     self.keypair_settings.public_filepath)
69
70                 if self.keypair_settings.delete_on_clean is not None:
71                     self.__delete_keys_on_clean = self.keypair_settings.delete_on_clean
72                 else:
73                     self.__delete_keys_on_clean = False
74             else:
75                 logger.info("Creating new keypair")
76                 # TODO - Make this value configurable
77                 keys = nova_utils.create_keys(1024)
78                 self.__keypair = nova_utils.upload_keypair(
79                     self.__nova, self.keypair_settings.name,
80                     nova_utils.public_key_openssh(keys))
81                 nova_utils.save_keys_to_files(
82                     keys, self.keypair_settings.public_filepath,
83                     self.keypair_settings.private_filepath)
84
85                 if self.keypair_settings.delete_on_clean is not None:
86                     self.__delete_keys_on_clean = self.keypair_settings.delete_on_clean
87                 else:
88                     self.__delete_keys_on_clean = True
89         elif self.__keypair and not os.path.isfile(
90                 self.keypair_settings.private_filepath):
91             logger.warn("The public key already exist in OpenStack \
92                         but the private key file is not found ..")
93
94         return self.__keypair
95
96     def clean(self):
97         """
98         Removes and deletes the keypair.
99         """
100         if self.__keypair:
101             try:
102                 nova_utils.delete_keypair(self.__nova, self.__keypair)
103             except NotFound:
104                 pass
105             self.__keypair = None
106
107         if self.__delete_keys_on_clean:
108             if (self.keypair_settings.public_filepath and
109                     file_utils.file_exists(
110                         self.keypair_settings.public_filepath)):
111                 os.chmod(self.keypair_settings.public_filepath, 0o777)
112                 os.remove(self.keypair_settings.public_filepath)
113             if (self.keypair_settings.private_filepath and
114                     file_utils.file_exists(
115                         self.keypair_settings.private_filepath)):
116                 os.chmod(self.keypair_settings.private_filepath, 0o777)
117                 os.remove(self.keypair_settings.private_filepath)
118
119     def get_keypair(self):
120         """
121         Returns the OpenStack keypair object
122         :return:
123         """
124         return self.__keypair
125
126
127 class KeypairSettings:
128     """
129     Class representing a keypair configuration
130     """
131
132     def __init__(self, **kwargs):
133         """
134         Constructor - all parameters are optional
135         :param name: The keypair name.
136         :param public_filepath: The path to/from the filesystem where the
137                                 public key file is or will be stored
138         :param private_filepath: The path where the generated private key file
139                                  will be stored
140         :param delete_on_clean: when True, the key files will be deleted when
141                                 OpenStackKeypair#clean() is called
142         :return:
143         """
144
145         self.name = kwargs.get('name')
146         self.public_filepath = kwargs.get('public_filepath')
147         self.private_filepath = kwargs.get('private_filepath')
148
149         if kwargs.get('delete_on_clean') is not None:
150             if isinstance(kwargs.get('delete_on_clean'), bool):
151                 self.delete_on_clean = kwargs.get('delete_on_clean')
152             else:
153                 self.delete_on_clean = str2bool(kwargs.get('delete_on_clean'))
154         else:
155             self.delete_on_clean = None
156
157         if not self.name:
158             raise KeypairSettingsError('Name is a required attribute')
159
160
161 class KeypairSettingsError(Exception):
162     """
163     Exception to be thrown when keypair settings are incorrect
164     """