Reformat auth_url based on the ID API version.
[snaps.git] / snaps / openstack / os_credentials.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 from neutronclient.common.utils import str2bool
16 import numbers
17 from snaps import file_utils
18 from snaps.openstack.utils import glance_utils, keystone_utils
19
20 __author__ = 'spisarski'
21
22
23 class OSCreds:
24     """
25     Represents the credentials required to connect with OpenStack servers
26     """
27
28     def __init__(self, **kwargs):
29         """
30         Constructor
31         :param username: The user (required)
32         :param password: The user's password (required)
33         :param auth_url: The OpenStack cloud's authorization URL (required)
34         :param project_name: The project/tenant name
35         :param identity_api_version: The OpenStack's API version to use for
36                                      Keystone clients
37         :param image_api_version: The OpenStack's API version to use for Glance
38                                   clients
39         :param network_api_version: The OpenStack's API version to use for
40                                     Neutron clients
41         :param compute_api_version: The OpenStack's API version to use for Nova
42                                     clients
43         :param heat_api_version: The OpenStack's API version to use for Heat
44                                     clients
45         :param user_domain_id: Used for v3 APIs (default=None)
46         :param user_domain_name: Used for v3 APIs (default='default')
47         :param project_domain_id: Used for v3 APIs (default=None)
48         :param project_domain_name: Used for v3 APIs (default='default')
49         :param interface: Used to specify the endpoint type for keystone as
50                           public, admin, internal
51         :param proxy_settings: instance of os_credentials.ProxySettings class
52         :param cacert: Default to be True for http, or the certification file
53                        is specified for https verification, or set to be False
54                        to disable server certificate verification without cert
55                        file
56         :param region_name: the region (optional default = None)
57         """
58         self.username = kwargs.get('username')
59         self.password = kwargs.get('password')
60         self.auth_url = kwargs.get('auth_url')
61         self.project_name = kwargs.get('project_name')
62
63         if kwargs.get('identity_api_version') is None:
64             self.identity_api_version = keystone_utils.V2_VERSION_NUM
65         else:
66             self.identity_api_version = float(kwargs['identity_api_version'])
67
68         if kwargs.get('image_api_version') is None:
69             self.image_api_version = glance_utils.VERSION_2
70         else:
71             self.image_api_version = float(kwargs['image_api_version'])
72
73         if kwargs.get('network_api_version') is None:
74             self.network_api_version = 2
75         else:
76             self.network_api_version = float(kwargs['network_api_version'])
77
78         if kwargs.get('compute_api_version') is None:
79             self.compute_api_version = 2
80         else:
81             self.compute_api_version = float(kwargs['compute_api_version'])
82
83         if kwargs.get('heat_api_version') is None:
84             self.heat_api_version = 1
85         else:
86             self.heat_api_version = float(kwargs['heat_api_version'])
87
88         self.user_domain_id = kwargs.get('user_domain_id')
89
90         if kwargs.get('user_domain_name') is None:
91             self.user_domain_name = 'default'
92         else:
93             self.user_domain_name = kwargs['user_domain_name']
94
95         self.project_domain_id = kwargs.get('project_domain_id')
96
97         if kwargs.get('project_domain_name') is None:
98             self.project_domain_name = 'default'
99         else:
100             self.project_domain_name = kwargs['project_domain_name']
101
102         if kwargs.get('interface') is None:
103             self.interface = 'admin'
104         else:
105             self.interface = kwargs['interface']
106
107         self.region_name = kwargs.get('region_name', None)
108
109         self.cacert = False
110         if kwargs.get('cacert') is not None:
111             if isinstance(kwargs.get('cacert'), str):
112                 if file_utils.file_exists(kwargs['cacert']):
113                     self.cacert = kwargs['cacert']
114                 else:
115                     self.cacert = str2bool(kwargs['cacert'])
116             else:
117                 self.cacert = kwargs['cacert']
118
119         if isinstance(kwargs.get('proxy_settings'), ProxySettings):
120             self.proxy_settings = kwargs.get('proxy_settings')
121         elif isinstance(kwargs.get('proxy_settings'), dict):
122             self.proxy_settings = ProxySettings(**kwargs.get('proxy_settings'))
123         else:
124             self.proxy_settings = None
125
126         if (not self.username or not self.password or not self.auth_url
127                 or not self.project_name):
128             raise OSCredsError('username, password, auth_url, and project_name'
129                                ' are required')
130
131         self.auth_url = self.__scrub_auth_url()
132
133     def __scrub_auth_url(self):
134         """
135         As the Python APIs are have more stringent requirements around how the
136         auth_url is formed than the CLI, this method will scrub any version
137         from the end of
138         :return:
139         """
140         auth_url_tokens = self.auth_url.rstrip('/').split('/')
141         last_token = auth_url_tokens[len(auth_url_tokens) - 1]
142         token_iters = len(auth_url_tokens)
143         if last_token.startswith('v'):
144             token_iters -= 1
145         if self.identity_api_version == keystone_utils.V2_VERSION_NUM:
146             last_token = keystone_utils.V2_VERSION_STR
147         else:
148             last_token = 'v' + str(int(self.identity_api_version))
149
150         new_url = None
151         for ctr in range(0, token_iters):
152             if new_url:
153                 new_url += '/' + auth_url_tokens[ctr]
154             else:
155                 new_url = auth_url_tokens[ctr]
156         new_url += '/' + last_token
157
158         return new_url
159
160     @property
161     def __str__(self):
162         """Converts object to a string"""
163         return ('OSCreds - username=' + str(self.username) +
164                 ', password=' + str(self.password) +
165                 ', auth_url=' + str(self.auth_url) +
166                 ', project_name=' + str(self.project_name) +
167                 ', identity_api_version=' + str(self.identity_api_version) +
168                 ', image_api_version=' + str(self.image_api_version) +
169                 ', network_api_version=' + str(self.network_api_version) +
170                 ', compute_api_version=' + str(self.compute_api_version) +
171                 ', heat_api_version=' + str(self.heat_api_version) +
172                 ', user_domain_id=' + str(self.user_domain_id) +
173                 ', user_domain_name=' + str(self.user_domain_name) +
174                 ', project_domain_id=' + str(self.project_domain_id) +
175                 ', project_domain_name=' + str(self.project_domain_name) +
176                 ', interface=' + str(self.interface) +
177                 ', region_name=' + str(self.region_name) +
178                 ', proxy_settings=' + str(self.proxy_settings) +
179                 ', cacert=' + str(self.cacert))
180
181
182 class ProxySettings:
183     """
184     Represents the information required for sending traffic (HTTP & SSH)
185     through a proxy
186     """
187
188     def __init__(self, **kwargs):
189         """
190         Constructor
191         :param host: the HTTP proxy host
192         :param port: the HTTP proxy port
193         :param https_host: the HTTPS proxy host (defaults to host)
194         :param https_port: the HTTPS proxy port (defaults to port)
195         :param port: the HTTP proxy port
196         :param ssh_proxy_cmd: the SSH proxy command string (optional)
197         """
198         self.host = kwargs.get('host')
199         self.port = kwargs.get('port')
200         if self.port and isinstance(self.port, numbers.Number):
201             self.port = str(self.port)
202
203         self.https_host = kwargs.get('https_host', self.host)
204         self.https_port = kwargs.get('https_port', self.port)
205         if self.https_port and isinstance(self.https_port, numbers.Number):
206             self.https_port = str(self.https_port)
207
208         self.ssh_proxy_cmd = kwargs.get('ssh_proxy_cmd')
209
210         if not self.host or not self.port:
211             raise ProxySettingsError('host & port are required')
212
213     def __str__(self):
214         """Converts object to a string"""
215         return 'ProxySettings - host=' + str(self.host) + \
216                ', port=' + str(self.port) + \
217                ', ssh_proxy_cmd=' + str(self.ssh_proxy_cmd)
218
219
220 class ProxySettingsError(Exception):
221     """
222     Exception to be thrown when an OSCred are invalid
223     """
224
225
226 class OSCredsError(Exception):
227     """
228     Exception to be thrown when an OSCred are invalid
229     """