blob: bedb9ecdb97f31f2a965f76e973ac1c4c0052510 [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Attila Fazekasa23f5002012-10-23 19:32:45 +02002# 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
Attila Fazekas1aed6202013-02-11 14:47:45 +010016import contextlib
Attila Fazekas1aed6202013-02-11 14:47:45 +010017import types
Matthew Treinisha83a16e2012-12-07 13:44:02 -050018
Attila Fazekas1aed6202013-02-11 14:47:45 +010019import boto
20import boto.ec2
21import boto.s3.connection
Matthew Treinishfcd9a082015-04-23 09:43:23 -040022from six.moves import configparser as ConfigParser
Matthew Treinishf077dd22015-04-23 09:37:41 -040023from six.moves.urllib import parse as urlparse
24from tempest_lib import exceptions as lib_exc
25
26from tempest import config
Attila Fazekas1aed6202013-02-11 14:47:45 +010027
Matthew Treinish684d8992014-01-30 16:27:40 +000028CONF = config.CONF
29
Attila Fazekas1aed6202013-02-11 14:47:45 +010030
31class BotoClientBase(object):
32
33 ALLOWED_METHODS = set()
34
Andrea Frittoli32d74992015-03-06 17:01:07 +000035 def __init__(self, identity_client):
36 self.identity_client = identity_client
Attila Fazekas1aed6202013-02-11 14:47:45 +010037
Rob Crittenden1be45bf2015-02-09 22:29:35 -050038 self.ca_cert = CONF.identity.ca_certificates_file
Matthew Treinish684d8992014-01-30 16:27:40 +000039 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
Attila Fazekas1aed6202013-02-11 14:47:45 +010042
Andrea Frittoli32d74992015-03-06 17:01:07 +000043 self.connection_data = {}
Attila Fazekas1aed6202013-02-11 14:47:45 +010044
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
Rob Crittenden1be45bf2015-02-09 22:29:35 -050053 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
Attila Fazekas1aed6202013-02-11 14:47:45 +010063 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)
Rob Crittenden1be45bf2015-02-09 22:29:35 -050080 self._config_boto_ca_certificates_file(self.ca_cert)
Andrea Frittoli32d74992015-03-06 17:01:07 +000081
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)
Attila Fazekas1aed6202013-02-11 14:47:45 +010088 return self.connect_method(**self.connection_data)
Matthew Treinisha83a16e2012-12-07 13:44:02 -050089
Andrea Frittoli32d74992015-03-06 17:01:07 +000090 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(
Anusha Ramineni0cfb4612015-08-24 08:49:10 +053097 identity_client.user_id)['credentials']
Andrea Frittoli32d74992015-03-06 17:01:07 +000098 for cred in ec2_cred_list:
99 if cred['tenant_id'] == identity_client.tenant_id:
100 ec2_cred = cred
101 break
102 else:
Anusha Ramineni0cfb4612015-08-24 08:49:10 +0530103 ec2_cred = (identity_client.create_user_ec2_credentials(
Andrea Frittoli32d74992015-03-06 17:01:07 +0000104 identity_client.user_id, identity_client.tenant_id)
Anusha Ramineni0cfb4612015-08-24 08:49:10 +0530105 ['credential'])
Andrea Frittoli32d74992015-03-06 17:01:07 +0000106 if not all((ec2_cred, ec2_cred['access'], ec2_cred['secret'])):
107 raise lib_exc.NotFound("Unable to get access and secret keys")
108 else:
109 ec2_cred_aws = {}
110 ec2_cred_aws['aws_access_key_id'] = ec2_cred['access']
111 ec2_cred_aws['aws_secret_access_key'] = ec2_cred['secret']
112 return ec2_cred_aws
113
Attila Fazekasa23f5002012-10-23 19:32:45 +0200114
115class APIClientEC2(BotoClientBase):
116
117 def connect_method(self, *args, **kwargs):
118 return boto.connect_ec2(*args, **kwargs)
119
Andrea Frittoli32d74992015-03-06 17:01:07 +0000120 def __init__(self, identity_client):
121 super(APIClientEC2, self).__init__(identity_client)
Rob Crittendenaead3c22014-04-13 23:58:56 -0400122 insecure_ssl = CONF.identity.disable_ssl_certificate_validation
Matthew Treinish684d8992014-01-30 16:27:40 +0000123 purl = urlparse.urlparse(CONF.boto.ec2_url)
Attila Fazekasa23f5002012-10-23 19:32:45 +0200124
Matthew Treinish684d8992014-01-30 16:27:40 +0000125 region_name = CONF.compute.region
Arata Notsu8f440392013-09-13 16:14:20 +0900126 if not region_name:
Matthew Treinish684d8992014-01-30 16:27:40 +0000127 region_name = CONF.identity.region
Arata Notsu8f440392013-09-13 16:14:20 +0900128 region = boto.ec2.regioninfo.RegionInfo(name=region_name,
Attila Fazekas1aed6202013-02-11 14:47:45 +0100129 endpoint=purl.hostname)
Attila Fazekasa23f5002012-10-23 19:32:45 +0200130 port = purl.port
131 if port is None:
132 if purl.scheme is not "https":
133 port = 80
134 else:
135 port = 443
136 else:
137 port = int(port)
Andrea Frittoli32d74992015-03-06 17:01:07 +0000138 self.connection_data.update({"is_secure": purl.scheme == "https",
139 "validate_certs": not insecure_ssl,
140 "region": region,
141 "host": purl.hostname,
142 "port": port,
143 "path": purl.path})
Attila Fazekasa23f5002012-10-23 19:32:45 +0200144
145 ALLOWED_METHODS = set(('create_key_pair', 'get_key_pair',
146 'delete_key_pair', 'import_key_pair',
147 'get_all_key_pairs',
Burt Holzmanbb575e12013-07-14 00:23:30 -0500148 'get_all_tags',
Attila Fazekasa23f5002012-10-23 19:32:45 +0200149 'create_image', 'get_image',
150 'register_image', 'deregister_image',
151 'get_all_images', 'get_image_attribute',
152 'modify_image_attribute', 'reset_image_attribute',
153 'get_all_kernels',
154 'create_volume', 'delete_volume',
155 'get_all_volume_status', 'get_all_volumes',
156 'get_volume_attribute', 'modify_volume_attribute'
157 'bundle_instance', 'cancel_spot_instance_requests',
158 'confirm_product_instanc',
159 'get_all_instance_status', 'get_all_instances',
160 'get_all_reserved_instances',
161 'get_all_spot_instance_requests',
162 'get_instance_attribute', 'monitor_instance',
163 'monitor_instances', 'unmonitor_instance',
164 'unmonitor_instances',
165 'purchase_reserved_instance_offering',
166 'reboot_instances', 'request_spot_instances',
167 'reset_instance_attribute', 'run_instances',
168 'start_instances', 'stop_instances',
169 'terminate_instances',
170 'attach_network_interface', 'attach_volume',
171 'detach_network_interface', 'detach_volume',
172 'get_console_output',
173 'delete_network_interface', 'create_subnet',
174 'create_network_interface', 'delete_subnet',
175 'get_all_network_interfaces',
176 'allocate_address', 'associate_address',
177 'disassociate_address', 'get_all_addresses',
178 'release_address',
179 'create_snapshot', 'delete_snapshot',
180 'get_all_snapshots', 'get_snapshot_attribute',
181 'modify_snapshot_attribute',
182 'reset_snapshot_attribute', 'trim_snapshots',
183 'get_all_regions', 'get_all_zones',
184 'get_all_security_groups', 'create_security_group',
185 'delete_security_group', 'authorize_security_group',
186 'authorize_security_group_egress',
187 'revoke_security_group',
188 'revoke_security_group_egress'))
189
Attila Fazekasa23f5002012-10-23 19:32:45 +0200190
191class ObjectClientS3(BotoClientBase):
192
193 def connect_method(self, *args, **kwargs):
194 return boto.connect_s3(*args, **kwargs)
195
Andrea Frittoli32d74992015-03-06 17:01:07 +0000196 def __init__(self, identity_client):
197 super(ObjectClientS3, self).__init__(identity_client)
Rob Crittendenaead3c22014-04-13 23:58:56 -0400198 insecure_ssl = CONF.identity.disable_ssl_certificate_validation
Matthew Treinish684d8992014-01-30 16:27:40 +0000199 purl = urlparse.urlparse(CONF.boto.s3_url)
Attila Fazekasa23f5002012-10-23 19:32:45 +0200200 port = purl.port
201 if port is None:
202 if purl.scheme is not "https":
203 port = 80
204 else:
205 port = 443
206 else:
207 port = int(port)
Andrea Frittoli32d74992015-03-06 17:01:07 +0000208 self.connection_data.update({"is_secure": purl.scheme == "https",
209 "validate_certs": not insecure_ssl,
210 "host": purl.hostname,
211 "port": port,
212 "calling_format": boto.s3.connection.
213 OrdinaryCallingFormat()})
Attila Fazekasa23f5002012-10-23 19:32:45 +0200214
215 ALLOWED_METHODS = set(('create_bucket', 'delete_bucket', 'generate_url',
216 'get_all_buckets', 'get_bucket', 'delete_key',
217 'lookup'))