7562896ad87c636d5797dd3cf58ae6ce15741330
[nfvbench.git] / nfvbench / credentials.py
1 # Copyright 2016 Cisco Systems, Inc.  All rights reserved.
2 #
3 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
4 #    not use this file except in compliance with the License. You may obtain
5 #    a copy of the License at
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
9 #    Unless required by applicable law or agreed to in writing, software
10 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 #    License for the specific language governing permissions and limitations
13 #    under the License.
14 #
15
16 import os
17 import re
18
19 # Module for credentials in Openstack
20 import getpass
21 from keystoneauth1.identity import v2
22 from keystoneauth1.identity import v3
23 from keystoneauth1 import session
24 import openstack
25 from keystoneclient.exceptions import HTTPClientError
26
27 from .log import LOG
28
29
30 class Credentials(object):
31
32     def get_session(self):
33
34         if self.clouds_detail:
35             connection = openstack.connect(cloud=self.clouds_detail)
36             cred_session = connection.session
37         else:
38             dct = {
39                 'username': self.rc_username,
40                 'password': self.rc_password,
41                 'auth_url': self.rc_auth_url
42             }
43
44             if self.rc_identity_api_version == 3:
45                 dct.update({
46                     'project_name': self.rc_project_name,
47                     'project_domain_name': self.rc_project_domain_name,
48                     'user_domain_name': self.rc_user_domain_name
49                 })
50                 auth = v3.Password(**dct)
51             else:
52                 dct.update({
53                     'tenant_name': self.rc_tenant_name
54                 })
55                 auth = v2.Password(**dct)
56             cred_session = session.Session(auth=auth, verify=self.rc_cacert)
57         return cred_session
58
59     def __parse_openrc(self, file):
60         export_re = re.compile('export OS_([A-Z_]*)="?(.*)')
61         for line in file:
62             line = line.strip()
63             mstr = export_re.match(line)
64             if mstr:
65                 # get rif of posible trailing double quote
66                 # the first one was removed by the re
67                 name = mstr.group(1)
68                 value = mstr.group(2)
69                 if value.endswith('"'):
70                     value = value[:-1]
71                 # get rid of password assignment
72                 # echo "Please enter your OpenStack Password: "
73                 # read -sr OS_PASSWORD_INPUT
74                 # export OS_PASSWORD=$OS_PASSWORD_INPUT
75                 if value.startswith('$'):
76                     continue
77                 # Check if api version is provided
78                 # Default is keystone v2
79                 if name == 'IDENTITY_API_VERSION':
80                     self.rc_identity_api_version = int(value)
81
82                 # now match against wanted variable names
83                 elif name == 'USERNAME':
84                     self.rc_username = value
85                 elif name == 'AUTH_URL':
86                     self.rc_auth_url = value
87                 elif name == 'TENANT_NAME':
88                     self.rc_tenant_name = value
89                 elif name == "CACERT":
90                     self.rc_cacert = value
91                 elif name == "REGION_NAME":
92                     self.rc_region_name = value
93                 elif name == "PASSWORD":
94                     self.rc_password = value
95                 elif name == "USER_DOMAIN_NAME":
96                     self.rc_user_domain_name = value
97                 elif name == "PROJECT_NAME":
98                     self.rc_project_name = value
99                 elif name == "PROJECT_DOMAIN_NAME":
100                     self.rc_project_domain_name = value
101
102     # /users URL returns exception (HTTP 403) if user is not admin.
103     # try first without the version in case session already has it in
104     # Return HTTP 200 if user is admin
105     def __user_is_admin(self, url):
106         is_admin = False
107         try:
108             # check if user has admin role in OpenStack project
109             filter = {'service_type': 'identity',
110                       'interface': 'public'}
111             self.get_session().get(url, endpoint_filter=filter)
112             is_admin = True
113         except HTTPClientError as exc:
114             if exc.http_status == 403:
115                 LOG.warning(
116                     "User is not admin, no permission to list user roles. Exception: %s", exc)
117         return is_admin
118
119     #
120     # Read a openrc file and take care of the password
121     # The 2 args are passed from the command line and can be None
122     #
123     def __init__(self, openrc_file, clouds_detail, pwd=None, no_env=False):
124         self.rc_password = None
125         self.rc_username = None
126         self.rc_tenant_name = None
127         self.rc_auth_url = None
128         self.rc_cacert = None
129         self.rc_region_name = None
130         self.rc_user_domain_name = None
131         self.rc_project_domain_name = None
132         self.rc_project_name = None
133         self.rc_identity_api_version = 3
134         self.is_admin = False
135         self.clouds_detail = clouds_detail
136         success = True
137
138         if openrc_file:
139             if isinstance(openrc_file, str):
140                 if os.path.exists(openrc_file):
141                     with open(openrc_file) as rc_file:
142                         self.__parse_openrc(rc_file)
143                 else:
144                     LOG.error('Error: rc file does not exist %s', openrc_file)
145                     success = False
146             else:
147                 self.__parse_openrc(openrc_file)
148         elif not clouds_detail and not no_env:
149             # no openrc file passed - we assume the variables have been
150             # sourced by the calling shell
151             # just check that they are present
152             if 'OS_IDENTITY_API_VERSION' in os.environ:
153                 self.rc_identity_api_version = int(os.environ['OS_IDENTITY_API_VERSION'])
154
155             if self.rc_identity_api_version == 2:
156                 for varname in ['OS_USERNAME', 'OS_AUTH_URL', 'OS_TENANT_NAME']:
157                     if varname not in os.environ:
158                         LOG.warning('%s is missing', varname)
159                         success = False
160                 if success:
161                     self.rc_username = os.environ['OS_USERNAME']
162                     self.rc_auth_url = os.environ['OS_AUTH_URL']
163                     self.rc_tenant_name = os.environ['OS_TENANT_NAME']
164                 if 'OS_REGION_NAME' in os.environ:
165                     self.rc_region_name = os.environ['OS_REGION_NAME']
166             elif self.rc_identity_api_version == 3:
167                 for varname in ['OS_USERNAME', 'OS_AUTH_URL', 'OS_PROJECT_NAME',
168                                 'OS_PROJECT_DOMAIN_NAME', 'OS_USER_DOMAIN_NAME']:
169                     if varname not in os.environ:
170                         LOG.warning('%s is missing', varname)
171                         success = False
172                 if success:
173                     self.rc_username = os.environ['OS_USERNAME']
174                     self.rc_auth_url = os.environ['OS_AUTH_URL']
175                     self.rc_project_name = os.environ['OS_PROJECT_NAME']
176                     self.rc_project_domain_name = os.environ['OS_PROJECT_DOMAIN_NAME']
177                     self.rc_user_domain_name = os.environ['OS_USER_DOMAIN_NAME']
178             if 'OS_CACERT' in os.environ:
179                 self.rc_cacert = os.environ['OS_CACERT']
180
181
182         # always override with CLI argument if provided
183         if not clouds_detail:
184             if pwd:
185                 self.rc_password = pwd
186             # if password not know, check from env variable
187             elif self.rc_auth_url and not self.rc_password and success:
188                 if 'OS_PASSWORD' in os.environ and not no_env:
189                     self.rc_password = os.environ['OS_PASSWORD']
190                 else:
191                     # interactively ask for password
192                     self.rc_password = getpass.getpass(
193                         'Please enter your OpenStack Password: ')
194             if not self.rc_password:
195                 self.rc_password = ""
196
197
198         try:
199             # /users URL returns exception (HTTP 403) if user is not admin.
200             # try first without the version in case session already has it in
201             # Return HTTP 200 if user is admin
202             self.is_admin = self.__user_is_admin('/users') or self.__user_is_admin(
203                 '/v2/users') or self.__user_is_admin('/v3/users')
204         except Exception as e:
205             LOG.warning("Error occurred during Openstack API access. "
206                         "Unable to check user is admin. Exception: %s", e)