Charmhelper sync

This commit is contained in:
Liam Young 2015-09-04 11:44:31 +01:00
parent c0904504b1
commit a95691cd73

View File

@ -414,10 +414,16 @@ class CephBrokerRq(object):
The API is versioned and defaults to version 1. The API is versioned and defaults to version 1.
""" """
def __init__(self, api_version=1): def __init__(self, api_version=1, ops=None, request_id=None):
self.api_version = api_version self.api_version = api_version
self.request_id = str(uuid.uuid1()) if request_id:
self.ops = [] self.request_id = request_id
else:
self.request_id = str(uuid.uuid1())
if ops:
self.ops = ops
else:
self.ops = []
def add_op_create_pool(self, name, replica_count=3): def add_op_create_pool(self, name, replica_count=3):
self.ops.append({'op': 'create-pool', 'name': name, self.ops.append({'op': 'create-pool', 'name': name,
@ -428,6 +434,28 @@ class CephBrokerRq(object):
return json.dumps({'api-version': self.api_version, 'ops': self.ops, return json.dumps({'api-version': self.api_version, 'ops': self.ops,
'request-id': self.request_id}) 'request-id': self.request_id})
def _ops_equal(self, other):
if len(self.ops) == len(other.ops):
for req_no in range(0, len(self.ops)):
for key in ['replicas', 'name', 'op']:
if self.ops[req_no][key] != other.ops[req_no][key]:
return False
else:
return False
return True
def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
if self.api_version == other.api_version and \
self._ops_equal(other):
return True
else:
return False
def __ne__(self, other):
return not self.__eq__(other)
class CephBrokerRsp(object): class CephBrokerRsp(object):
"""Ceph broker response. """Ceph broker response.
@ -454,17 +482,42 @@ class CephBrokerRsp(object):
return self.rsp.get('stderr') return self.rsp.get('stderr')
def request_states(request_needed): def get_previous_request(rid):
"""Return dict showing if a request has been sent and completed per rid""" """Return the last ceph broker request sent on a given relation
@param rid: Relation id to query for request
"""
request = None
broker_req = relation_get(attribute='broker_req', rid=rid,
unit=local_unit())
if broker_req:
request_data = json.loads(broker_req)
request = CephBrokerRq(api_version=request_data['api-version'],
ops=request_data['ops'],
request_id=request_data['request-id'])
return request
def get_request_states(request):
"""Return a dict of requests per relation id with their corresponding
completion state.
This allows a charm, which has a request for ceph, to see whether there is
an equivalent request already being processed and if so what state that
request is in.
@param request: A CephBrokerRq object
"""
complete = [] complete = []
requests = {} requests = {}
for rid in relation_ids('ceph'): for rid in relation_ids('ceph'):
complete = False complete = False
previous_request = relation_get(attribute='broker_req', rid=rid, unit=local_unit()) previous_request = get_previous_request(rid)
sent = equivalent_broker_requests(previous_request, request_needed.request) if request == previous_request:
if sent: sent = True
complete = broker_request_completed(previous_request, rid) complete = is_broker_request_complete(previous_request, rid)
else: else:
sent = False
complete = False complete = False
requests[rid] = { requests[rid] = {
'sent': sent, 'sent': sent,
@ -473,48 +526,47 @@ def request_states(request_needed):
return requests return requests
def request_sent(request_needed): def is_request_sent(request):
"""Check to see if a matching request has been sent""" """Check to see if a functionally equivalent request has already been sent
states = request_states(request_needed)
Returns True if a similair request has been sent
@param request: A CephBrokerRq object
"""
states = get_request_states(request)
for rid in states.keys(): for rid in states.keys():
if not states[rid]['sent']: if not states[rid]['sent']:
return False return False
return True return True
def request_complete(request_needed): def is_request_complete(request):
"""Check to see if a matching request has been completed""" """Check to see if a functionally equivalent request has already been
states = request_states(request_needed) completed
Returns True if a similair request has been completed
@param request: A CephBrokerRq object
"""
states = get_request_states(request)
for rid in states.keys(): for rid in states.keys():
if not states[rid]['complete']: if not states[rid]['complete']:
return False return False
return True return True
def equivalent_broker_requests(encoded_req1, encoded_req2): def is_broker_request_complete(request, rid):
"""Check to see if two requests are equivalent (ignore request id)""" """Check if a given request has been completed on the given relation
if not encoded_req1 or not encoded_req2:
return False
req1 = json.loads(encoded_req1)
req2 = json.loads(encoded_req2)
if len(req1['ops']) != len(req2['ops']):
return False
for req_no in range(0, len(req1['ops'])):
for key in ['replicas', 'name', 'op']:
if req1['ops'][req_no][key] != req2['ops'][req_no][key]:
return False
return True
@param request: A CephBrokerRq object
def broker_request_completed(encoded_req, rid): @param rid: Relation ID
"""Check if a given request has been completed on the given relation""" """
req = json.loads(encoded_req)
broker_key = get_broker_rsp_key() broker_key = get_broker_rsp_key()
for unit in related_units(rid): for unit in related_units(rid):
rdata = relation_get(rid=rid, unit=unit) rdata = relation_get(rid=rid, unit=unit)
if rdata.get(broker_key): if rdata.get(broker_key):
rsp = CephBrokerRsp(rdata.get(broker_key)) rsp = CephBrokerRsp(rdata.get(broker_key))
if rsp.request_id == req.get('request-id'): if rsp.request_id == request.request_id:
if not rsp.exit_code: if not rsp.exit_code:
return True return True
else: else:
@ -522,12 +574,13 @@ def broker_request_completed(encoded_req, rid):
# remote ceph cluster does not support unit targeted replies or it # remote ceph cluster does not support unit targeted replies or it
# has not processed our request yet. # has not processed our request yet.
if rdata.get('broker_rsp'): if rdata.get('broker_rsp'):
if rdata.get('unit-targeted-reponses'): request_data = json.loads(rdata['broker_rsp'])
if request_data.get('request-id'):
log('Ignoring legacy broker_rsp without unit key as remote ' log('Ignoring legacy broker_rsp without unit key as remote '
'service supports unit specific replies') 'service supports unit specific replies', level=DEBUG)
else: else:
log('Using legacy broker_rsp as remote service does not ' log('Using legacy broker_rsp as remote service does not '
'supports unit specific replies') 'supports unit specific replies', level=DEBUG)
rsp = CephBrokerRsp(rdata['broker_rsp']) rsp = CephBrokerRsp(rdata['broker_rsp'])
if not rsp.exit_code: if not rsp.exit_code:
return True return True
@ -535,15 +588,23 @@ def broker_request_completed(encoded_req, rid):
def get_broker_rsp_key(): def get_broker_rsp_key():
"""Return broker request key for this unit""" """Return broker response key for this unit
This is the key that ceph is going to use to pass request status
information back to this unit
"""
return 'broker-rsp-' + local_unit().replace('/', '-') return 'broker-rsp-' + local_unit().replace('/', '-')
def send_request_if_needed(rq): def send_request_if_needed(request):
"""Send broker request if one has not already been sent""" """Send broker request if an equivalent request has not already been sent
if request_sent(rq):
log('Request already sent but not complete, not sending new request') @param request: A CephBrokerRq object
"""
if is_request_sent(request):
log('Request already sent but not complete, not sending new request',
level=DEBUG)
else: else:
for rid in relation_ids('ceph'): for rid in relation_ids('ceph'):
log('Sending request {}'.format(rq.request_id)) log('Sending request {}'.format(request.request_id), level=DEBUG)
relation_set(relation_id=rid, broker_req=rq.request) relation_set(relation_id=rid, broker_req=request.request)