Tal Kammer | c6b9788 | 2013-08-20 18:06:18 +0300 | [diff] [blame] | 1 | # vim: tabstop=4 shiftwidth=4 softtabstop=4 |
| 2 | |
| 3 | # Copyright 2012 OpenStack Foundation |
| 4 | # All Rights Reserved. |
| 5 | # |
| 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 7 | # not use this file except in compliance with the License. You may obtain |
| 8 | # a copy of the License at |
| 9 | # |
| 10 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | # |
| 12 | # Unless required by applicable law or agreed to in writing, software |
| 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 15 | # License for the specific language governing permissions and limitations |
| 16 | # under the License. |
| 17 | |
| 18 | # Config |
| 19 | import ConfigParser |
| 20 | import os |
| 21 | |
| 22 | # Default client libs |
| 23 | import keystoneclient.v2_0.client as keystone_client |
| 24 | |
| 25 | # Import Openstack exceptions |
| 26 | import keystoneclient.exceptions as keystone_exception |
| 27 | |
| 28 | |
| 29 | DEFAULT_CONFIG_DIR = "%s/etc" % os.path.abspath(os.path.pardir) |
| 30 | DEFAULT_CONFIG_FILE = "tempest.conf" |
| 31 | DEFAULT_CONFIG_SAMPLE = "tempest.conf.sample" |
| 32 | |
| 33 | # Environment variables override defaults |
| 34 | TEMPEST_CONFIG_DIR = os.environ.get('TEMPEST_CONFIG_DIR') or DEFAULT_CONFIG_DIR |
| 35 | TEMPEST_CONFIG = os.environ.get('TEMPEST_CONFIG') or "%s/%s" % \ |
| 36 | (TEMPEST_CONFIG_DIR, DEFAULT_CONFIG_FILE) |
| 37 | TEMPEST_CONFIG_SAMPLE = os.environ.get('TEMPEST_CONFIG_SAMPLE') or "%s/%s" % \ |
| 38 | (TEMPEST_CONFIG_DIR, DEFAULT_CONFIG_SAMPLE) |
| 39 | |
| 40 | # Admin credentials |
| 41 | OS_USERNAME = os.environ.get('OS_USERNAME') |
| 42 | OS_PASSWORD = os.environ.get('OS_PASSWORD') |
| 43 | OS_TENANT_NAME = os.environ.get('OS_TENANT_NAME') |
| 44 | OS_AUTH_URL = os.environ.get('OS_AUTH_URL') |
| 45 | |
| 46 | # Image references |
| 47 | IMAGE_ID = os.environ.get('IMAGE_ID') |
| 48 | IMAGE_ID_ALT = os.environ.get('IMAGE_ID_ALT') |
| 49 | |
| 50 | |
| 51 | class ClientManager(object): |
| 52 | """ |
| 53 | Manager that provides access to the official python clients for |
| 54 | calling various OpenStack APIs. |
| 55 | """ |
| 56 | def __init__(self): |
| 57 | self.identity_client = None |
| 58 | self.image_client = None |
| 59 | self.network_client = None |
| 60 | self.compute_client = None |
| 61 | self.volume_client = None |
| 62 | |
| 63 | def get_identity_client(self, **kwargs): |
| 64 | """ |
| 65 | Returns the openstack identity python client |
| 66 | :param username: a string representing the username |
| 67 | :param password: a string representing the user's password |
| 68 | :param tenant_name: a string representing the tenant name of the user |
| 69 | :param auth_url: a string representing the auth url of the identity |
| 70 | :param insecure: True if we wish to disable ssl certificate validation, |
| 71 | False otherwise |
| 72 | :returns an instance of openstack identity python client |
| 73 | """ |
| 74 | if not self.identity_client: |
| 75 | self.identity_client = keystone_client.Client(**kwargs) |
| 76 | |
| 77 | return self.identity_client |
| 78 | |
| 79 | |
| 80 | def getTempestConfigSample(): |
| 81 | """ |
| 82 | Gets the tempest configuration file as a ConfigParser object |
| 83 | :return: the tempest configuration file |
| 84 | """ |
| 85 | # get the sample config file from the sample |
| 86 | config_sample = ConfigParser.ConfigParser() |
| 87 | config_sample.readfp(open(TEMPEST_CONFIG_SAMPLE)) |
| 88 | |
| 89 | return config_sample |
| 90 | |
| 91 | |
| 92 | def update_config_admin_credentials(config, config_section): |
| 93 | """ |
| 94 | Updates the tempest config with the admin credentials |
| 95 | :param config: an object representing the tempest config file |
| 96 | :param config_section: the section name where the admin credentials are |
| 97 | """ |
| 98 | # Check if credentials are present |
| 99 | if not (OS_AUTH_URL and |
| 100 | OS_USERNAME and |
| 101 | OS_PASSWORD and |
| 102 | OS_TENANT_NAME): |
| 103 | raise Exception("Admin environment variables not found.") |
| 104 | |
| 105 | # TODO(tkammer): Add support for uri_v3 |
| 106 | config_identity_params = {'uri': OS_AUTH_URL, |
| 107 | 'admin_username': OS_USERNAME, |
| 108 | 'admin_password': OS_PASSWORD, |
| 109 | 'admin_tenant_name': OS_TENANT_NAME} |
| 110 | |
| 111 | update_config_section_with_params(config, |
| 112 | config_section, |
| 113 | config_identity_params) |
| 114 | |
| 115 | |
| 116 | def update_config_section_with_params(config, section, params): |
| 117 | """ |
| 118 | Updates a given config object with given params |
| 119 | :param config: the object representing the config file of tempest |
| 120 | :param section: the section we would like to update |
| 121 | :param params: the parameters we wish to update for that section |
| 122 | """ |
| 123 | for option, value in params.items(): |
| 124 | config.set(section, option, value) |
| 125 | |
| 126 | |
| 127 | def get_identity_client_kwargs(config, section_name): |
| 128 | """ |
| 129 | Get the required arguments for the identity python client |
| 130 | :param config: the tempest configuration file |
| 131 | :param section_name: the section name in the configuration where the |
| 132 | arguments can be found |
| 133 | :return: a dictionary representing the needed arguments for the identity |
| 134 | client |
| 135 | """ |
| 136 | username = config.get(section_name, 'admin_username') |
| 137 | password = config.get(section_name, 'admin_password') |
| 138 | tenant_name = config.get(section_name, 'admin_tenant_name') |
| 139 | auth_url = config.get(section_name, 'uri') |
| 140 | dscv = config.get(section_name, 'disable_ssl_certificate_validation') |
| 141 | kwargs = {'username': username, |
| 142 | 'password': password, |
| 143 | 'tenant_name': tenant_name, |
| 144 | 'auth_url': auth_url, |
| 145 | 'insecure': dscv} |
| 146 | |
| 147 | return kwargs |
| 148 | |
| 149 | |
| 150 | def create_user_with_tenant(identity_client, username, password, tenant_name): |
| 151 | """ |
| 152 | Creates a user using a given identity client |
| 153 | :param identity_client: openstack identity python client |
| 154 | :param username: a string representing the username |
| 155 | :param password: a string representing the user's password |
| 156 | :param tenant_name: a string representing the tenant name of the user |
| 157 | """ |
| 158 | # Try to create the necessary tenant |
| 159 | tenant_id = None |
| 160 | try: |
| 161 | tenant_description = "Tenant for Tempest %s user" % username |
| 162 | tenant = identity_client.tenants.create(tenant_name, |
| 163 | tenant_description) |
| 164 | tenant_id = tenant.id |
| 165 | except keystone_exception.Conflict: |
| 166 | |
| 167 | # if already exist, use existing tenant |
| 168 | tenant_list = identity_client.tenants.list() |
| 169 | for tenant in tenant_list: |
| 170 | if tenant.name == tenant_name: |
| 171 | tenant_id = tenant.id |
| 172 | |
| 173 | # Try to create the user |
| 174 | try: |
| 175 | email = "%s@test.com" % username |
| 176 | identity_client.users.create(name=username, |
| 177 | password=password, |
| 178 | email=email, |
| 179 | tenant_id=tenant_id) |
| 180 | except keystone_exception.Conflict: |
| 181 | |
| 182 | # if already exist, use existing user |
| 183 | pass |
| 184 | |
| 185 | |
| 186 | def create_users_and_tenants(identity_client, |
| 187 | config, |
| 188 | identity_section): |
| 189 | """ |
| 190 | Creates the two non admin users and tenants for tempest |
| 191 | :param identity_client: openstack identity python client |
| 192 | :param config: tempest configuration file |
| 193 | :param identity_section: the section name of identity in the config |
| 194 | """ |
| 195 | # Get the necessary params from the config file |
| 196 | tenant_name = config.get(identity_section, 'tenant_name') |
| 197 | username = config.get(identity_section, 'username') |
| 198 | password = config.get(identity_section, 'password') |
| 199 | |
| 200 | alt_tenant_name = config.get(identity_section, 'alt_tenant_name') |
| 201 | alt_username = config.get(identity_section, 'alt_username') |
| 202 | alt_password = config.get(identity_section, 'alt_password') |
| 203 | |
| 204 | # Create the necessary users for the test runs |
| 205 | create_user_with_tenant(identity_client, username, password, tenant_name) |
| 206 | create_user_with_tenant(identity_client, alt_username, alt_password, |
| 207 | alt_tenant_name) |
| 208 | |
| 209 | |
| 210 | def main(): |
| 211 | """ |
| 212 | Main module to control the script |
| 213 | """ |
| 214 | # TODO(tkammer): add support for existing config file |
| 215 | config_sample = getTempestConfigSample() |
| 216 | update_config_admin_credentials(config_sample, 'identity') |
| 217 | |
| 218 | client_manager = ClientManager() |
| 219 | |
| 220 | # Set the identity related info for tempest |
| 221 | identity_client_kwargs = get_identity_client_kwargs(config_sample, |
| 222 | 'identity') |
| 223 | identity_client = client_manager.get_identity_client( |
| 224 | **identity_client_kwargs) |
| 225 | |
| 226 | # Create the necessary users and tenants for tempest run |
| 227 | create_users_and_tenants(identity_client, |
| 228 | config_sample, |
| 229 | 'identity') |
| 230 | |
| 231 | # TODO(tkammer): add image implementation |
| 232 | |
| 233 | if __name__ == "__main__": |
| 234 | main() |