1 from abc
import ABCMeta
, abstractmethod
2 from io
import StringIO
6 from .conn
import get_gateway_connection
, get_gateway_iam_connection
, get_gateway_secure_connection
9 """ interface to run commands against a distinct ceph cluster """
10 __metaclass__
= ABCMeta
13 def admin(self
, args
= None, **kwargs
):
14 """ execute a radosgw-admin command """
18 """ interface to control a single radosgw instance """
19 __metaclass__
= ABCMeta
21 def __init__(self
, host
= None, port
= None, cluster
= None, zone
= None, ssl_port
= 0):
24 self
.cluster
= cluster
26 self
.connection
= None
27 self
.secure_connection
= None
28 self
.ssl_port
= ssl_port
29 self
.iam_connection
= None
32 def start(self
, args
= []):
33 """ start the gateway with the given args """
38 """ stop the gateway """
42 return 'http://%s:%d' % (self
.host
, self
.port
)
45 """ interface for system objects, represented in json format and
46 manipulated with radosgw-admin commands """
47 __metaclass__
= ABCMeta
49 def __init__(self
, data
= None, uuid
= None):
53 self
.load_from_json(data
)
56 def build_command(self
, command
):
57 """ return the command line for the given command, including arguments
58 to specify this object """
62 def load_from_json(self
, data
):
63 """ update internal state based on json data """
66 def command(self
, cluster
, cmd
, args
= None, **kwargs
):
67 """ run the given command and return the output and retcode """
68 args
= self
.build_command(cmd
) + (args
or [])
69 return cluster
.admin(args
, **kwargs
)
71 def json_command(self
, cluster
, cmd
, args
= None, **kwargs
):
72 """ run the given command, parse the output and return the resulting
74 s
, r
= self
.command(cluster
, cmd
, args
or [], **kwargs
)
77 self
.load_from_json(data
)
81 # mixins for supported commands
83 def create(self
, cluster
, args
= None, **kwargs
):
84 """ create the object with the given arguments """
85 return self
.json_command(cluster
, 'create', args
, **kwargs
)
88 def delete(self
, cluster
, args
= None, **kwargs
):
89 """ delete the object """
90 # not json_command() because delete has no output
91 _
, r
= self
.command(cluster
, 'delete', args
, **kwargs
)
97 def get(self
, cluster
, args
= None, **kwargs
):
98 """ read the object from storage """
99 kwargs
['read_only'] = True
100 return self
.json_command(cluster
, 'get', args
, **kwargs
)
103 def set(self
, cluster
, data
, args
= None, **kwargs
):
104 """ set the object by json """
105 kwargs
['stdin'] = StringIO(json
.dumps(data
))
106 return self
.json_command(cluster
, 'set', args
, **kwargs
)
108 class Modify(object):
109 def modify(self
, cluster
, args
= None, **kwargs
):
110 """ modify the object with the given arguments """
111 return self
.json_command(cluster
, 'modify', args
, **kwargs
)
113 class CreateDelete(Create
, Delete
): pass
114 class GetSet(Get
, Set
): pass
116 class Zone(SystemObject
, SystemObject
.CreateDelete
, SystemObject
.GetSet
, SystemObject
.Modify
):
117 def __init__(self
, name
, zonegroup
= None, cluster
= None, data
= None, zone_id
= None, gateways
= None):
119 self
.zonegroup
= zonegroup
120 self
.cluster
= cluster
121 self
.gateways
= gateways
or []
122 super(Zone
, self
).__init
__(data
, zone_id
)
125 """ command-line argument to specify this zone """
126 return ['--rgw-zone', self
.name
]
129 """ command-line arguments to specify this zone/zonegroup/realm """
130 args
= self
.zone_arg()
132 args
+= self
.zonegroup
.zonegroup_args()
135 def build_command(self
, command
):
136 """ build a command line for the given command and args """
137 return ['zone', command
] + self
.zone_args()
139 def load_from_json(self
, data
):
140 """ load the zone from json """
142 self
.name
= data
['name']
144 def start(self
, args
= None):
145 """ start all gateways """
146 for g
in self
.gateways
:
150 """ stop all gateways """
151 for g
in self
.gateways
:
155 return self
.zonegroup
.period
if self
.zonegroup
else None
158 return self
.zonegroup
.realm() if self
.zonegroup
else None
160 def is_read_only(self
):
164 raise NotImplementedError
166 def syncs_from(self
, zone_name
):
167 return zone_name
!= self
.name
169 def has_buckets(self
):
175 def get_conn(self
, credentials
):
176 return ZoneConn(self
, credentials
) # not implemented, but can be used
178 class ZoneConn(object):
179 def __init__(self
, zone
, credentials
):
181 self
.name
= zone
.name
182 """ connect to the zone's first gateway """
183 if isinstance(credentials
, list):
184 self
.credentials
= credentials
[0]
186 self
.credentials
= credentials
188 if self
.zone
.gateways
is not None:
189 self
.conn
= get_gateway_connection(self
.zone
.gateways
[0], self
.credentials
)
190 self
.secure_conn
= get_gateway_secure_connection(self
.zone
.gateways
[0], self
.credentials
)
192 self
.iam_conn
= get_gateway_iam_connection(self
.zone
.gateways
[0], self
.credentials
)
194 # create connections for the rest of the gateways (if exist)
195 for gw
in list(self
.zone
.gateways
):
196 get_gateway_connection(gw
, self
.credentials
)
197 get_gateway_secure_connection(gw
, self
.credentials
)
199 get_gateway_iam_connection(gw
, self
.credentials
)
202 def get_connection(self
):
205 def get_iam_connection(self
):
208 def get_bucket(self
, bucket_name
, credentials
):
209 raise NotImplementedError
211 def check_bucket_eq(self
, zone
, bucket_name
):
212 raise NotImplementedError
214 class ZoneGroup(SystemObject
, SystemObject
.CreateDelete
, SystemObject
.GetSet
, SystemObject
.Modify
):
215 def __init__(self
, name
, period
= None, data
= None, zonegroup_id
= None, zones
= None, master_zone
= None):
218 self
.zones
= zones
or []
219 self
.master_zone
= master_zone
220 super(ZoneGroup
, self
).__init
__(data
, zonegroup_id
)
223 self
.zones_by_type
= {}
226 self
.ro_zones
.append(z
)
228 self
.rw_zones
.append(z
)
230 def zonegroup_arg(self
):
231 """ command-line argument to specify this zonegroup """
232 return ['--rgw-zonegroup', self
.name
]
234 def zonegroup_args(self
):
235 """ command-line arguments to specify this zonegroup/realm """
236 args
= self
.zonegroup_arg()
239 args
+= realm
.realm_arg()
242 def build_command(self
, command
):
243 """ build a command line for the given command and args """
244 return ['zonegroup', command
] + self
.zonegroup_args()
246 def zone_by_id(self
, zone_id
):
247 """ return the matching zone by id """
248 for zone
in self
.zones
:
249 if zone
.id == zone_id
:
253 def load_from_json(self
, data
):
254 """ load the zonegroup from json """
256 self
.name
= data
['name']
257 master_id
= data
['master_zone']
258 if not self
.master_zone
or master_id
!= self
.master_zone
.id:
259 self
.master_zone
= self
.zone_by_id(master_id
)
261 def add(self
, cluster
, zone
, args
= None, **kwargs
):
262 """ add an existing zone to the zonegroup """
263 args
= zone
.zone_arg() + (args
or [])
264 data
, r
= self
.json_command(cluster
, 'add', args
, **kwargs
)
266 zone
.zonegroup
= self
267 self
.zones
.append(zone
)
270 def remove(self
, cluster
, zone
, args
= None, **kwargs
):
271 """ remove an existing zone from the zonegroup """
272 args
= zone
.zone_arg() + (args
or [])
273 data
, r
= self
.json_command(cluster
, 'remove', args
, **kwargs
)
275 zone
.zonegroup
= None
276 self
.zones
.remove(zone
)
280 return self
.period
.realm
if self
.period
else None
282 class Period(SystemObject
, SystemObject
.Get
):
283 def __init__(self
, realm
= None, data
= None, period_id
= None, zonegroups
= None, master_zonegroup
= None):
285 self
.zonegroups
= zonegroups
or []
286 self
.master_zonegroup
= master_zonegroup
287 super(Period
, self
).__init
__(data
, period_id
)
289 def zonegroup_by_id(self
, zonegroup_id
):
290 """ return the matching zonegroup by id """
291 for zonegroup
in self
.zonegroups
:
292 if zonegroup
.id == zonegroup_id
:
296 def build_command(self
, command
):
297 """ build a command line for the given command and args """
298 return ['period', command
]
300 def load_from_json(self
, data
):
301 """ load the period from json """
303 master_id
= data
['master_zonegroup']
304 if not self
.master_zonegroup
or master_id
!= self
.master_zonegroup
.id:
305 self
.master_zonegroup
= self
.zonegroup_by_id(master_id
)
307 def update(self
, zone
, args
= None, **kwargs
):
308 """ run 'radosgw-admin period update' on the given zone """
310 args
= zone
.zone_args() + (args
or [])
311 if kwargs
.pop('commit', False):
312 args
.append('--commit')
313 return self
.json_command(zone
.cluster
, 'update', args
, **kwargs
)
315 def commit(self
, zone
, args
= None, **kwargs
):
316 """ run 'radosgw-admin period commit' on the given zone """
318 args
= zone
.zone_args() + (args
or [])
319 return self
.json_command(zone
.cluster
, 'commit', args
, **kwargs
)
321 class Realm(SystemObject
, SystemObject
.CreateDelete
, SystemObject
.GetSet
):
322 def __init__(self
, name
, period
= None, data
= None, realm_id
= None):
324 self
.current_period
= period
325 super(Realm
, self
).__init
__(data
, realm_id
)
328 """ return the command-line arguments that specify this realm """
329 return ['--rgw-realm', self
.name
]
331 def build_command(self
, command
):
332 """ build a command line for the given command and args """
333 return ['realm', command
] + self
.realm_arg()
335 def load_from_json(self
, data
):
336 """ load the realm from json """
339 def pull(self
, cluster
, gateway
, credentials
, args
= [], **kwargs
):
340 """ pull an existing realm from the given gateway """
341 args
+= ['--url', gateway
.endpoint()]
342 args
+= credentials
.credential_args()
343 return self
.json_command(cluster
, 'pull', args
, **kwargs
)
345 def master_zonegroup(self
):
346 """ return the current period's master zonegroup """
347 if self
.current_period
is None:
349 return self
.current_period
.master_zonegroup
351 def meta_master_zone(self
):
352 """ return the current period's metadata master zone """
353 zonegroup
= self
.master_zonegroup()
354 if zonegroup
is None:
356 return zonegroup
.master_zone
359 def __init__(self
, access_key
, secret
):
360 self
.access_key
= access_key
363 def credential_args(self
):
364 return ['--access-key', self
.access_key
, '--secret', self
.secret
]
366 class User(SystemObject
):
367 def __init__(self
, uid
, data
= None, name
= None, credentials
= None, tenant
= None):
369 self
.credentials
= credentials
or []
371 super(User
, self
).__init
__(data
, uid
)
374 """ command-line argument to specify this user """
375 args
= ['--uid', self
.id]
377 args
+= ['--tenant', self
.tenant
]
380 def build_command(self
, command
):
381 """ build a command line for the given command and args """
382 return ['user', command
] + self
.user_arg()
384 def load_from_json(self
, data
):
385 """ load the user from json """
386 self
.id = data
['user_id']
387 self
.name
= data
['display_name']
388 self
.credentials
= [Credentials(k
['access_key'], k
['secret_key']) for k
in data
['keys']]
390 def create(self
, zone
, args
= None, **kwargs
):
391 """ create the user with the given arguments """
393 args
= zone
.zone_args() + (args
or [])
394 return self
.json_command(zone
.cluster
, 'create', args
, **kwargs
)
396 def info(self
, zone
, args
= None, **kwargs
):
397 """ read the user from storage """
399 args
= zone
.zone_args() + (args
or [])
400 kwargs
['read_only'] = True
401 return self
.json_command(zone
.cluster
, 'info', args
, **kwargs
)
403 def delete(self
, zone
, args
= None, **kwargs
):
404 """ delete the user """
406 args
= zone
.zone_args() + (args
or [])
407 return self
.command(zone
.cluster
, 'delete', args
, **kwargs
)