Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 1 | # Copyright 2012 OpenStack Foundation |
| 2 | # All Rights Reserved. |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 5 | # not use this file except in compliance with the License. You may obtain |
| 6 | # 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, WITHOUT |
| 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 13 | # License for the specific language governing permissions and limitations |
| 14 | # under the License. |
| 15 | |
Cyril Roelandt | bde4a4b | 2015-05-07 13:00:38 +0000 | [diff] [blame] | 16 | from six.moves import configparser as ConfigParser |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 17 | import contextlib |
| 18 | from tempest_lib import exceptions as lib_exc |
| 19 | import types |
| 20 | import urlparse |
| 21 | |
| 22 | from neutron.tests.tempest import config |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 23 | |
| 24 | import boto |
| 25 | import boto.ec2 |
| 26 | import boto.s3.connection |
| 27 | |
| 28 | CONF = config.CONF |
| 29 | |
| 30 | |
| 31 | class BotoClientBase(object): |
| 32 | |
| 33 | ALLOWED_METHODS = set() |
| 34 | |
Maru Newby | 5690a35 | 2015-03-13 18:46:40 +0000 | [diff] [blame] | 35 | def __init__(self, identity_client): |
| 36 | self.identity_client = identity_client |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 37 | |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 38 | self.ca_cert = CONF.identity.ca_certificates_file |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 39 | self.connection_timeout = str(CONF.boto.http_socket_timeout) |
| 40 | self.num_retries = str(CONF.boto.num_retries) |
| 41 | self.build_timeout = CONF.boto.build_timeout |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 42 | |
Maru Newby | 5690a35 | 2015-03-13 18:46:40 +0000 | [diff] [blame] | 43 | self.connection_data = {} |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 44 | |
| 45 | def _config_boto_timeout(self, timeout, retries): |
| 46 | try: |
| 47 | boto.config.add_section("Boto") |
| 48 | except ConfigParser.DuplicateSectionError: |
| 49 | pass |
| 50 | boto.config.set("Boto", "http_socket_timeout", timeout) |
| 51 | boto.config.set("Boto", "num_retries", retries) |
| 52 | |
| 53 | def _config_boto_ca_certificates_file(self, ca_cert): |
| 54 | if ca_cert is None: |
| 55 | return |
| 56 | |
| 57 | try: |
| 58 | boto.config.add_section("Boto") |
| 59 | except ConfigParser.DuplicateSectionError: |
| 60 | pass |
| 61 | boto.config.set("Boto", "ca_certificates_file", ca_cert) |
| 62 | |
| 63 | def __getattr__(self, name): |
| 64 | """Automatically creates methods for the allowed methods set.""" |
| 65 | if name in self.ALLOWED_METHODS: |
| 66 | def func(self, *args, **kwargs): |
| 67 | with contextlib.closing(self.get_connection()) as conn: |
| 68 | return getattr(conn, name)(*args, **kwargs) |
| 69 | |
| 70 | func.__name__ = name |
| 71 | setattr(self, name, types.MethodType(func, self, self.__class__)) |
| 72 | setattr(self.__class__, name, |
| 73 | types.MethodType(func, None, self.__class__)) |
| 74 | return getattr(self, name) |
| 75 | else: |
| 76 | raise AttributeError(name) |
| 77 | |
| 78 | def get_connection(self): |
| 79 | self._config_boto_timeout(self.connection_timeout, self.num_retries) |
| 80 | self._config_boto_ca_certificates_file(self.ca_cert) |
Maru Newby | 5690a35 | 2015-03-13 18:46:40 +0000 | [diff] [blame] | 81 | |
| 82 | ec2_client_args = {'aws_access_key_id': CONF.boto.aws_access, |
| 83 | 'aws_secret_access_key': CONF.boto.aws_secret} |
| 84 | if not all(ec2_client_args.values()): |
| 85 | ec2_client_args = self.get_aws_credentials(self.identity_client) |
| 86 | |
| 87 | self.connection_data.update(ec2_client_args) |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 88 | return self.connect_method(**self.connection_data) |
| 89 | |
Maru Newby | 5690a35 | 2015-03-13 18:46:40 +0000 | [diff] [blame] | 90 | def get_aws_credentials(self, identity_client): |
| 91 | """ |
| 92 | Obtain existing, or create new AWS credentials |
| 93 | :param identity_client: identity client with embedded credentials |
| 94 | :return: EC2 credentials |
| 95 | """ |
| 96 | ec2_cred_list = identity_client.list_user_ec2_credentials( |
| 97 | identity_client.user_id) |
| 98 | for cred in ec2_cred_list: |
| 99 | if cred['tenant_id'] == identity_client.tenant_id: |
| 100 | ec2_cred = cred |
| 101 | break |
| 102 | else: |
| 103 | ec2_cred = identity_client.create_user_ec2_credentials( |
| 104 | identity_client.user_id, identity_client.tenant_id) |
| 105 | if not all((ec2_cred, ec2_cred['access'], ec2_cred['secret'])): |
| 106 | raise lib_exc.NotFound("Unable to get access and secret keys") |
| 107 | else: |
| 108 | ec2_cred_aws = {} |
| 109 | ec2_cred_aws['aws_access_key_id'] = ec2_cred['access'] |
| 110 | ec2_cred_aws['aws_secret_access_key'] = ec2_cred['secret'] |
| 111 | return ec2_cred_aws |
| 112 | |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 113 | |
| 114 | class APIClientEC2(BotoClientBase): |
| 115 | |
| 116 | def connect_method(self, *args, **kwargs): |
| 117 | return boto.connect_ec2(*args, **kwargs) |
| 118 | |
Maru Newby | 5690a35 | 2015-03-13 18:46:40 +0000 | [diff] [blame] | 119 | def __init__(self, identity_client): |
| 120 | super(APIClientEC2, self).__init__(identity_client) |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 121 | insecure_ssl = CONF.identity.disable_ssl_certificate_validation |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 122 | purl = urlparse.urlparse(CONF.boto.ec2_url) |
| 123 | |
| 124 | region_name = CONF.compute.region |
| 125 | if not region_name: |
| 126 | region_name = CONF.identity.region |
| 127 | region = boto.ec2.regioninfo.RegionInfo(name=region_name, |
| 128 | endpoint=purl.hostname) |
| 129 | port = purl.port |
| 130 | if port is None: |
| 131 | if purl.scheme is not "https": |
| 132 | port = 80 |
| 133 | else: |
| 134 | port = 443 |
| 135 | else: |
| 136 | port = int(port) |
Maru Newby | 5690a35 | 2015-03-13 18:46:40 +0000 | [diff] [blame] | 137 | self.connection_data.update({"is_secure": purl.scheme == "https", |
| 138 | "validate_certs": not insecure_ssl, |
| 139 | "region": region, |
| 140 | "host": purl.hostname, |
| 141 | "port": port, |
| 142 | "path": purl.path}) |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 143 | |
| 144 | ALLOWED_METHODS = set(('create_key_pair', 'get_key_pair', |
| 145 | 'delete_key_pair', 'import_key_pair', |
| 146 | 'get_all_key_pairs', |
| 147 | 'get_all_tags', |
| 148 | 'create_image', 'get_image', |
| 149 | 'register_image', 'deregister_image', |
| 150 | 'get_all_images', 'get_image_attribute', |
| 151 | 'modify_image_attribute', 'reset_image_attribute', |
| 152 | 'get_all_kernels', |
| 153 | 'create_volume', 'delete_volume', |
| 154 | 'get_all_volume_status', 'get_all_volumes', |
| 155 | 'get_volume_attribute', 'modify_volume_attribute' |
| 156 | 'bundle_instance', 'cancel_spot_instance_requests', |
| 157 | 'confirm_product_instanc', |
| 158 | 'get_all_instance_status', 'get_all_instances', |
| 159 | 'get_all_reserved_instances', |
| 160 | 'get_all_spot_instance_requests', |
| 161 | 'get_instance_attribute', 'monitor_instance', |
| 162 | 'monitor_instances', 'unmonitor_instance', |
| 163 | 'unmonitor_instances', |
| 164 | 'purchase_reserved_instance_offering', |
| 165 | 'reboot_instances', 'request_spot_instances', |
| 166 | 'reset_instance_attribute', 'run_instances', |
| 167 | 'start_instances', 'stop_instances', |
| 168 | 'terminate_instances', |
| 169 | 'attach_network_interface', 'attach_volume', |
| 170 | 'detach_network_interface', 'detach_volume', |
| 171 | 'get_console_output', |
| 172 | 'delete_network_interface', 'create_subnet', |
| 173 | 'create_network_interface', 'delete_subnet', |
| 174 | 'get_all_network_interfaces', |
| 175 | 'allocate_address', 'associate_address', |
| 176 | 'disassociate_address', 'get_all_addresses', |
| 177 | 'release_address', |
| 178 | 'create_snapshot', 'delete_snapshot', |
| 179 | 'get_all_snapshots', 'get_snapshot_attribute', |
| 180 | 'modify_snapshot_attribute', |
| 181 | 'reset_snapshot_attribute', 'trim_snapshots', |
| 182 | 'get_all_regions', 'get_all_zones', |
| 183 | 'get_all_security_groups', 'create_security_group', |
| 184 | 'delete_security_group', 'authorize_security_group', |
| 185 | 'authorize_security_group_egress', |
| 186 | 'revoke_security_group', |
| 187 | 'revoke_security_group_egress')) |
| 188 | |
| 189 | |
| 190 | class ObjectClientS3(BotoClientBase): |
| 191 | |
| 192 | def connect_method(self, *args, **kwargs): |
| 193 | return boto.connect_s3(*args, **kwargs) |
| 194 | |
Maru Newby | 5690a35 | 2015-03-13 18:46:40 +0000 | [diff] [blame] | 195 | def __init__(self, identity_client): |
| 196 | super(ObjectClientS3, self).__init__(identity_client) |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 197 | insecure_ssl = CONF.identity.disable_ssl_certificate_validation |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 198 | purl = urlparse.urlparse(CONF.boto.s3_url) |
| 199 | port = purl.port |
| 200 | if port is None: |
| 201 | if purl.scheme is not "https": |
| 202 | port = 80 |
| 203 | else: |
| 204 | port = 443 |
| 205 | else: |
| 206 | port = int(port) |
Maru Newby | 5690a35 | 2015-03-13 18:46:40 +0000 | [diff] [blame] | 207 | self.connection_data.update({"is_secure": purl.scheme == "https", |
| 208 | "validate_certs": not insecure_ssl, |
| 209 | "host": purl.hostname, |
| 210 | "port": port, |
| 211 | "calling_format": boto.s3.connection. |
| 212 | OrdinaryCallingFormat()}) |
Maru Newby | b096d9f | 2015-03-09 18:54:54 +0000 | [diff] [blame] | 213 | |
| 214 | ALLOWED_METHODS = set(('create_bucket', 'delete_bucket', 'generate_url', |
| 215 | 'get_all_buckets', 'get_bucket', 'delete_key', |
| 216 | 'lookup')) |