Added configuration for keypair size.
[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                     delete_on_clean = self.keypair_settings.delete_on_clean
72                     self.__delete_keys_on_clean = delete_on_clean
73                 else:
74                     self.__delete_keys_on_clean = False
75             else:
76                 logger.info("Creating new keypair")
77                 keys = nova_utils.create_keys(self.keypair_settings.key_size)
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                     delete_on_clean = self.keypair_settings.delete_on_clean
87                     self.__delete_keys_on_clean = delete_on_clean
88                 else:
89                     self.__delete_keys_on_clean = True
90         elif self.__keypair and not os.path.isfile(
91                 self.keypair_settings.private_filepath):
92             logger.warn("The public key already exist in OpenStack \
93                         but the private key file is not found ..")
94
95         return self.__keypair
96
97     def clean(self):
98         """
99         Removes and deletes the keypair.
100         """
101         if self.__keypair:
102             try:
103                 nova_utils.delete_keypair(self.__nova, self.__keypair)
104             except NotFound:
105                 pass
106             self.__keypair = None
107
108         if self.__delete_keys_on_clean:
109             if (self.keypair_settings.public_filepath and
110                     file_utils.file_exists(
111                         self.keypair_settings.public_filepath)):
112                 os.chmod(self.keypair_settings.public_filepath, 0o777)
113                 os.remove(self.keypair_settings.public_filepath)
114             if (self.keypair_settings.private_filepath and
115                     file_utils.file_exists(
116                         self.keypair_settings.private_filepath)):
117                 os.chmod(self.keypair_settings.private_filepath, 0o777)
118                 os.remove(self.keypair_settings.private_filepath)
119
120     def get_keypair(self):
121         """
122         Returns the OpenStack keypair object
123         :return:
124         """
125         return self.__keypair
126
127
128 class KeypairSettings:
129     """
130     Class representing a keypair configuration
131     """
132
133     def __init__(self, **kwargs):
134         """
135         Constructor - all parameters are optional
136         :param name: The keypair name.
137         :param public_filepath: The path to/from the filesystem where the
138                                 public key file is or will be stored
139         :param private_filepath: The path where the generated private key file
140                                  will be stored
141         :param key_size: The number of bytes for the key size when it needs to
142                          be generated (Must be >=512 default 1024)
143         :param delete_on_clean: when True, the key files will be deleted when
144                                 OpenStackKeypair#clean() is called
145         :return:
146         """
147
148         self.name = kwargs.get('name')
149         self.public_filepath = kwargs.get('public_filepath')
150         self.private_filepath = kwargs.get('private_filepath')
151         self.key_size = int(kwargs.get('key_size', 1024))
152
153         if kwargs.get('delete_on_clean') is not None:
154             if isinstance(kwargs.get('delete_on_clean'), bool):
155                 self.delete_on_clean = kwargs.get('delete_on_clean')
156             else:
157                 self.delete_on_clean = str2bool(kwargs.get('delete_on_clean'))
158         else:
159             self.delete_on_clean = None
160
161         if not self.name:
162             raise KeypairSettingsError('Name is a required attribute')
163
164         if self.key_size < 512:
165             raise KeypairSettingsError('key_size must be >=512')
166
167
168 class KeypairSettingsError(Exception):
169     """
170     Exception to be thrown when keypair settings are incorrect
171     """