blob: a1e1b5c1b4af88c494d651406b55ed926784203f [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 ConfigParser
17import contextlib
Attila Fazekas1aed6202013-02-11 14:47:45 +010018import types
Attila Fazekasa23f5002012-10-23 19:32:45 +020019import urlparse
20
Attila Fazekas1aed6202013-02-11 14:47:45 +010021from tempest import exceptions
Matthew Treinisha83a16e2012-12-07 13:44:02 -050022
Attila Fazekas1aed6202013-02-11 14:47:45 +010023import boto
24import boto.ec2
25import boto.s3.connection
26
27
28class BotoClientBase(object):
29
30 ALLOWED_METHODS = set()
31
32 def __init__(self, config,
33 username=None, password=None,
34 auth_url=None, tenant_name=None,
35 *args, **kwargs):
36
37 self.connection_timeout = str(config.boto.http_socket_timeout)
38 self.num_retries = str(config.boto.num_retries)
39 self.build_timeout = config.boto.build_timeout
40 self.ks_cred = {"username": username,
41 "password": password,
42 "auth_url": auth_url,
43 "tenant_name": tenant_name}
44
45 def _keystone_aws_get(self):
46 import keystoneclient.v2_0.client
47
48 keystone = keystoneclient.v2_0.client.Client(**self.ks_cred)
49 ec2_cred_list = keystone.ec2.list(keystone.auth_user_id)
50 ec2_cred = None
51 for cred in ec2_cred_list:
52 if cred.tenant_id == keystone.auth_tenant_id:
53 ec2_cred = cred
54 break
55 else:
56 ec2_cred = keystone.ec2.create(keystone.auth_user_id,
57 keystone.auth_tenant_id)
58 if not all((ec2_cred, ec2_cred.access, ec2_cred.secret)):
59 raise exceptions.NotFound("Unable to get access and secret keys")
60 return ec2_cred
61
62 def _config_boto_timeout(self, timeout, retries):
63 try:
64 boto.config.add_section("Boto")
65 except ConfigParser.DuplicateSectionError:
66 pass
67 boto.config.set("Boto", "http_socket_timeout", timeout)
68 boto.config.set("Boto", "num_retries", retries)
69
70 def __getattr__(self, name):
71 """Automatically creates methods for the allowed methods set."""
72 if name in self.ALLOWED_METHODS:
73 def func(self, *args, **kwargs):
74 with contextlib.closing(self.get_connection()) as conn:
75 return getattr(conn, name)(*args, **kwargs)
76
77 func.__name__ = name
78 setattr(self, name, types.MethodType(func, self, self.__class__))
79 setattr(self.__class__, name,
80 types.MethodType(func, None, self.__class__))
81 return getattr(self, name)
82 else:
83 raise AttributeError(name)
84
85 def get_connection(self):
86 self._config_boto_timeout(self.connection_timeout, self.num_retries)
87 if not all((self.connection_data["aws_access_key_id"],
88 self.connection_data["aws_secret_access_key"])):
89 if all(self.ks_cred.itervalues()):
90 ec2_cred = self._keystone_aws_get()
91 self.connection_data["aws_access_key_id"] = \
92 ec2_cred.access
93 self.connection_data["aws_secret_access_key"] = \
94 ec2_cred.secret
95 else:
96 raise exceptions.InvalidConfiguration(
Sean Dague14c68182013-04-14 15:34:30 -040097 "Unable to get access and secret keys")
Attila Fazekas1aed6202013-02-11 14:47:45 +010098 return self.connect_method(**self.connection_data)
Matthew Treinisha83a16e2012-12-07 13:44:02 -050099
Attila Fazekasa23f5002012-10-23 19:32:45 +0200100
101class APIClientEC2(BotoClientBase):
102
103 def connect_method(self, *args, **kwargs):
104 return boto.connect_ec2(*args, **kwargs)
105
106 def __init__(self, config, *args, **kwargs):
107 super(APIClientEC2, self).__init__(config, *args, **kwargs)
108 aws_access = config.boto.aws_access
109 aws_secret = config.boto.aws_secret
110 purl = urlparse.urlparse(config.boto.ec2_url)
111
Arata Notsu8f440392013-09-13 16:14:20 +0900112 region_name = config.compute.region
113 if not region_name:
114 region_name = config.identity.region
115 region = boto.ec2.regioninfo.RegionInfo(name=region_name,
Attila Fazekas1aed6202013-02-11 14:47:45 +0100116 endpoint=purl.hostname)
Attila Fazekasa23f5002012-10-23 19:32:45 +0200117 port = purl.port
118 if port is None:
119 if purl.scheme is not "https":
120 port = 80
121 else:
122 port = 443
123 else:
124 port = int(port)
125 self.connection_data = {"aws_access_key_id": aws_access,
126 "aws_secret_access_key": aws_secret,
127 "is_secure": purl.scheme == "https",
128 "region": region,
129 "host": purl.hostname,
130 "port": port,
131 "path": purl.path}
132
133 ALLOWED_METHODS = set(('create_key_pair', 'get_key_pair',
134 'delete_key_pair', 'import_key_pair',
135 'get_all_key_pairs',
Burt Holzmanbb575e12013-07-14 00:23:30 -0500136 'get_all_tags',
Attila Fazekasa23f5002012-10-23 19:32:45 +0200137 'create_image', 'get_image',
138 'register_image', 'deregister_image',
139 'get_all_images', 'get_image_attribute',
140 'modify_image_attribute', 'reset_image_attribute',
141 'get_all_kernels',
142 'create_volume', 'delete_volume',
143 'get_all_volume_status', 'get_all_volumes',
144 'get_volume_attribute', 'modify_volume_attribute'
145 'bundle_instance', 'cancel_spot_instance_requests',
146 'confirm_product_instanc',
147 'get_all_instance_status', 'get_all_instances',
148 'get_all_reserved_instances',
149 'get_all_spot_instance_requests',
150 'get_instance_attribute', 'monitor_instance',
151 'monitor_instances', 'unmonitor_instance',
152 'unmonitor_instances',
153 'purchase_reserved_instance_offering',
154 'reboot_instances', 'request_spot_instances',
155 'reset_instance_attribute', 'run_instances',
156 'start_instances', 'stop_instances',
157 'terminate_instances',
158 'attach_network_interface', 'attach_volume',
159 'detach_network_interface', 'detach_volume',
160 'get_console_output',
161 'delete_network_interface', 'create_subnet',
162 'create_network_interface', 'delete_subnet',
163 'get_all_network_interfaces',
164 'allocate_address', 'associate_address',
165 'disassociate_address', 'get_all_addresses',
166 'release_address',
167 'create_snapshot', 'delete_snapshot',
168 'get_all_snapshots', 'get_snapshot_attribute',
169 'modify_snapshot_attribute',
170 'reset_snapshot_attribute', 'trim_snapshots',
171 'get_all_regions', 'get_all_zones',
172 'get_all_security_groups', 'create_security_group',
173 'delete_security_group', 'authorize_security_group',
174 'authorize_security_group_egress',
175 'revoke_security_group',
176 'revoke_security_group_egress'))
177
178 def get_good_zone(self):
179 """
180 :rtype: BaseString
181 :return: Returns with the first available zone name
182 """
183 for zone in self.get_all_zones():
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200184 # NOTE(afazekas): zone.region_name was None
Attila Fazekasa23f5002012-10-23 19:32:45 +0200185 if (zone.state == "available" and
186 zone.region.name == self.connection_data["region"].name):
187 return zone.name
188 else:
189 raise IndexError("Don't have a good zone")
190
191
192class ObjectClientS3(BotoClientBase):
193
194 def connect_method(self, *args, **kwargs):
195 return boto.connect_s3(*args, **kwargs)
196
197 def __init__(self, config, *args, **kwargs):
198 super(ObjectClientS3, self).__init__(config, *args, **kwargs)
199 aws_access = config.boto.aws_access
200 aws_secret = config.boto.aws_secret
201 purl = urlparse.urlparse(config.boto.s3_url)
202 port = purl.port
203 if port is None:
204 if purl.scheme is not "https":
205 port = 80
206 else:
207 port = 443
208 else:
209 port = int(port)
210 self.connection_data = {"aws_access_key_id": aws_access,
211 "aws_secret_access_key": aws_secret,
212 "is_secure": purl.scheme == "https",
213 "host": purl.hostname,
214 "port": port,
Attila Fazekas1aed6202013-02-11 14:47:45 +0100215 "calling_format": boto.s3.connection.
216 OrdinaryCallingFormat()}
Attila Fazekasa23f5002012-10-23 19:32:45 +0200217
218 ALLOWED_METHODS = set(('create_bucket', 'delete_bucket', 'generate_url',
219 'get_all_buckets', 'get_bucket', 'delete_key',
220 'lookup'))