1 from abc
import ABCMeta
, abstractmethod
2 from io
import StringIO
6 from .conn
import get_gateway_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
31 def start(self
, args
= []):
32 """ start the gateway with the given args """
37 """ stop the gateway """
41 return 'http://%s:%d' % (self
.host
, self
.port
)
44 """ interface for system objects, represented in json format and
45 manipulated with radosgw-admin commands """
46 __metaclass__
= ABCMeta
48 def __init__(self
, data
= None, uuid
= None):
52 self
.load_from_json(data
)
55 def build_command(self
, command
):
56 """ return the command line for the given command, including arguments
57 to specify this object """
61 def load_from_json(self
, data
):
62 """ update internal state based on json data """
65 def command(self
, cluster
, cmd
, args
= None, **kwargs
):
66 """ run the given command and return the output and retcode """
67 args
= self
.build_command(cmd
) + (args
or [])
68 return cluster
.admin(args
, **kwargs
)
70 def json_command(self
, cluster
, cmd
, args
= None, **kwargs
):
71 """ run the given command, parse the output and return the resulting
73 s
, r
= self
.command(cluster
, cmd
, args
or [], **kwargs
)
76 self
.load_from_json(data
)
80 # mixins for supported commands
82 def create(self
, cluster
, args
= None, **kwargs
):
83 """ create the object with the given arguments """
84 return self
.json_command(cluster
, 'create', args
, **kwargs
)
87 def delete(self
, cluster
, args
= None, **kwargs
):
88 """ delete the object """
89 # not json_command() because delete has no output
90 _
, r
= self
.command(cluster
, 'delete', args
, **kwargs
)
96 def get(self
, cluster
, args
= None, **kwargs
):
97 """ read the object from storage """
98 kwargs
['read_only'] = True
99 return self
.json_command(cluster
, 'get', args
, **kwargs
)
102 def set(self
, cluster
, data
, args
= None, **kwargs
):
103 """ set the object by json """
104 kwargs
['stdin'] = StringIO(json
.dumps(data
))
105 return self
.json_command(cluster
, 'set', args
, **kwargs
)
107 class Modify(object):
108 def modify(self
, cluster
, args
= None, **kwargs
):
109 """ modify the object with the given arguments """
110 return self
.json_command(cluster
, 'modify', args
, **kwargs
)
112 class CreateDelete(Create
, Delete
): pass
113 class GetSet(Get
, Set
): pass
115 class Zone(SystemObject
, SystemObject
.CreateDelete
, SystemObject
.GetSet
, SystemObject
.Modify
):
116 def __init__(self
, name
, zonegroup
= None, cluster
= None, data
= None, zone_id
= None, gateways
= None):
118 self
.zonegroup
= zonegroup
119 self
.cluster
= cluster
120 self
.gateways
= gateways
or []
121 super(Zone
, self
).__init
__(data
, zone_id
)
124 """ command-line argument to specify this zone """
125 return ['--rgw-zone', self
.name
]
128 """ command-line arguments to specify this zone/zonegroup/realm """
129 args
= self
.zone_arg()
131 args
+= self
.zonegroup
.zonegroup_args()
134 def build_command(self
, command
):
135 """ build a command line for the given command and args """
136 return ['zone', command
] + self
.zone_args()
138 def load_from_json(self
, data
):
139 """ load the zone from json """
141 self
.name
= data
['name']
143 def start(self
, args
= None):
144 """ start all gateways """
145 for g
in self
.gateways
:
149 """ stop all gateways """
150 for g
in self
.gateways
:
154 return self
.zonegroup
.period
if self
.zonegroup
else None
157 return self
.zonegroup
.realm() if self
.zonegroup
else None
159 def is_read_only(self
):
163 raise NotImplementedError
165 def syncs_from(self
, zone_name
):
166 return zone_name
!= self
.name
168 def has_buckets(self
):
171 def get_conn(self
, credentials
):
172 return ZoneConn(self
, credentials
) # not implemented, but can be used
174 class ZoneConn(object):
175 def __init__(self
, zone
, credentials
):
177 self
.name
= zone
.name
178 """ connect to the zone's first gateway """
179 if isinstance(credentials
, list):
180 self
.credentials
= credentials
[0]
182 self
.credentials
= credentials
184 if self
.zone
.gateways
is not None:
185 self
.conn
= get_gateway_connection(self
.zone
.gateways
[0], self
.credentials
)
186 self
.secure_conn
= get_gateway_secure_connection(self
.zone
.gateways
[0], self
.credentials
)
187 # create connections for the rest of the gateways (if exist)
188 for gw
in list(self
.zone
.gateways
):
189 get_gateway_connection(gw
, self
.credentials
)
190 get_gateway_secure_connection(gw
, self
.credentials
)
193 def get_connection(self
):
196 def get_bucket(self
, bucket_name
, credentials
):
197 raise NotImplementedError
199 def check_bucket_eq(self
, zone
, bucket_name
):
200 raise NotImplementedError
202 class ZoneGroup(SystemObject
, SystemObject
.CreateDelete
, SystemObject
.GetSet
, SystemObject
.Modify
):
203 def __init__(self
, name
, period
= None, data
= None, zonegroup_id
= None, zones
= None, master_zone
= None):
206 self
.zones
= zones
or []
207 self
.master_zone
= master_zone
208 super(ZoneGroup
, self
).__init
__(data
, zonegroup_id
)
211 self
.zones_by_type
= {}
214 self
.ro_zones
.append(z
)
216 self
.rw_zones
.append(z
)
218 def zonegroup_arg(self
):
219 """ command-line argument to specify this zonegroup """
220 return ['--rgw-zonegroup', self
.name
]
222 def zonegroup_args(self
):
223 """ command-line arguments to specify this zonegroup/realm """
224 args
= self
.zonegroup_arg()
227 args
+= realm
.realm_arg()
230 def build_command(self
, command
):
231 """ build a command line for the given command and args """
232 return ['zonegroup', command
] + self
.zonegroup_args()
234 def zone_by_id(self
, zone_id
):
235 """ return the matching zone by id """
236 for zone
in self
.zones
:
237 if zone
.id == zone_id
:
241 def load_from_json(self
, data
):
242 """ load the zonegroup from json """
244 self
.name
= data
['name']
245 master_id
= data
['master_zone']
246 if not self
.master_zone
or master_id
!= self
.master_zone
.id:
247 self
.master_zone
= self
.zone_by_id(master_id
)
249 def add(self
, cluster
, zone
, args
= None, **kwargs
):
250 """ add an existing zone to the zonegroup """
251 args
= zone
.zone_arg() + (args
or [])
252 data
, r
= self
.json_command(cluster
, 'add', args
, **kwargs
)
254 zone
.zonegroup
= self
255 self
.zones
.append(zone
)
258 def remove(self
, cluster
, zone
, args
= None, **kwargs
):
259 """ remove an existing zone from the zonegroup """
260 args
= zone
.zone_arg() + (args
or [])
261 data
, r
= self
.json_command(cluster
, 'remove', args
, **kwargs
)
263 zone
.zonegroup
= None
264 self
.zones
.remove(zone
)
268 return self
.period
.realm
if self
.period
else None
270 class Period(SystemObject
, SystemObject
.Get
):
271 def __init__(self
, realm
= None, data
= None, period_id
= None, zonegroups
= None, master_zonegroup
= None):
273 self
.zonegroups
= zonegroups
or []
274 self
.master_zonegroup
= master_zonegroup
275 super(Period
, self
).__init
__(data
, period_id
)
277 def zonegroup_by_id(self
, zonegroup_id
):
278 """ return the matching zonegroup by id """
279 for zonegroup
in self
.zonegroups
:
280 if zonegroup
.id == zonegroup_id
:
284 def build_command(self
, command
):
285 """ build a command line for the given command and args """
286 return ['period', command
]
288 def load_from_json(self
, data
):
289 """ load the period from json """
291 master_id
= data
['master_zonegroup']
292 if not self
.master_zonegroup
or master_id
!= self
.master_zonegroup
.id:
293 self
.master_zonegroup
= self
.zonegroup_by_id(master_id
)
295 def update(self
, zone
, args
= None, **kwargs
):
296 """ run 'radosgw-admin period update' on the given zone """
298 args
= zone
.zone_args() + (args
or [])
299 if kwargs
.pop('commit', False):
300 args
.append('--commit')
301 return self
.json_command(zone
.cluster
, 'update', args
, **kwargs
)
303 def commit(self
, zone
, args
= None, **kwargs
):
304 """ run 'radosgw-admin period commit' on the given zone """
306 args
= zone
.zone_args() + (args
or [])
307 return self
.json_command(zone
.cluster
, 'commit', args
, **kwargs
)
309 class Realm(SystemObject
, SystemObject
.CreateDelete
, SystemObject
.GetSet
):
310 def __init__(self
, name
, period
= None, data
= None, realm_id
= None):
312 self
.current_period
= period
313 super(Realm
, self
).__init
__(data
, realm_id
)
316 """ return the command-line arguments that specify this realm """
317 return ['--rgw-realm', self
.name
]
319 def build_command(self
, command
):
320 """ build a command line for the given command and args """
321 return ['realm', command
] + self
.realm_arg()
323 def load_from_json(self
, data
):
324 """ load the realm from json """
327 def pull(self
, cluster
, gateway
, credentials
, args
= [], **kwargs
):
328 """ pull an existing realm from the given gateway """
329 args
+= ['--url', gateway
.endpoint()]
330 args
+= credentials
.credential_args()
331 return self
.json_command(cluster
, 'pull', args
, **kwargs
)
333 def master_zonegroup(self
):
334 """ return the current period's master zonegroup """
335 if self
.current_period
is None:
337 return self
.current_period
.master_zonegroup
339 def meta_master_zone(self
):
340 """ return the current period's metadata master zone """
341 zonegroup
= self
.master_zonegroup()
342 if zonegroup
is None:
344 return zonegroup
.master_zone
347 def __init__(self
, access_key
, secret
):
348 self
.access_key
= access_key
351 def credential_args(self
):
352 return ['--access-key', self
.access_key
, '--secret', self
.secret
]
354 class User(SystemObject
):
355 def __init__(self
, uid
, data
= None, name
= None, credentials
= None, tenant
= None):
357 self
.credentials
= credentials
or []
359 super(User
, self
).__init
__(data
, uid
)
362 """ command-line argument to specify this user """
363 args
= ['--uid', self
.id]
365 args
+= ['--tenant', self
.tenant
]
368 def build_command(self
, command
):
369 """ build a command line for the given command and args """
370 return ['user', command
] + self
.user_arg()
372 def load_from_json(self
, data
):
373 """ load the user from json """
374 self
.id = data
['user_id']
375 self
.name
= data
['display_name']
376 self
.credentials
= [Credentials(k
['access_key'], k
['secret_key']) for k
in data
['keys']]
378 def create(self
, zone
, args
= None, **kwargs
):
379 """ create the user with the given arguments """
381 args
= zone
.zone_args() + (args
or [])
382 return self
.json_command(zone
.cluster
, 'create', args
, **kwargs
)
384 def info(self
, zone
, args
= None, **kwargs
):
385 """ read the user from storage """
387 args
= zone
.zone_args() + (args
or [])
388 kwargs
['read_only'] = True
389 return self
.json_command(zone
.cluster
, 'info', args
, **kwargs
)
391 def delete(self
, zone
, args
= None, **kwargs
):
392 """ delete the user """
394 args
= zone
.zone_args() + (args
or [])
395 return self
.command(zone
.cluster
, 'delete', args
, **kwargs
)