diff options
author | Sundar Nadathur <sundar.nadathur@intel.com> | 2019-01-16 00:35:55 -0800 |
---|---|---|
committer | Sundar Nadathur <sundar.nadathur@intel.com> | 2020-03-21 12:03:38 -0700 |
commit | cc630b4eb62c4a45ff08a1862a8339a0f129e0a3 (patch) | |
tree | bbe43bcc14621c5ef75b21b79062c6d77fb8b9ff /nova/accelerator | |
parent | 0c52730f6a138ce3b40efd6a0bd2809b2c41dada (diff) | |
download | nova-cc630b4eb62c4a45ff08a1862a8339a0f129e0a3.tar.gz |
Create and bind Cyborg ARQs.
* Call Cyborg with device profile name to get ARQs (Accelerator Requests).
Each ARQ corresponds to a single device profile group, which
corrresponds to a single request group in request spec.
* Match each ARQ to associated request group, and thereby obtain the
corresponding RP for that ARQ.
* Call Cyborg to bind the ARQ to that host/device-RP.
* When Cyborg sends the ARQ bind notification events, wait for those
events with a timeout.
Change-Id: I0f8b6bf2b4f4510da6c84fede532533602b6af7f
Blueprint: nova-cyborg-interaction
Diffstat (limited to 'nova/accelerator')
-rw-r--r-- | nova/accelerator/cyborg.py | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/nova/accelerator/cyborg.py b/nova/accelerator/cyborg.py index 61aa78c86f..1991336f76 100644 --- a/nova/accelerator/cyborg.py +++ b/nova/accelerator/cyborg.py @@ -80,6 +80,7 @@ def get_device_profile_request_groups(context, dp_name): class _CyborgClient(object): DEVICE_PROFILE_URL = "/device_profiles" + ARQ_URL = "/accelerator_requests" def __init__(self, context): auth = service_auth.get_auth_plugin(context) @@ -145,3 +146,120 @@ class _CyborgClient(object): rg.add_trait(trait_name=name, trait_type=val) request_groups.append(rg) return request_groups + + def _create_arqs(self, dp_name): + data = {"device_profile_name": dp_name} + resp, err_msg = self._call_cyborg(self._client.post, + self.ARQ_URL, json=data) + + if err_msg: + raise exception.AcceleratorRequestOpFailed( + op=_('create'), msg=err_msg) + + return resp.json().get('arqs') + + def create_arqs_and_match_resource_providers(self, dp_name, rg_rp_map): + """Create ARQs, match them with request groups and thereby + determine their corresponding RPs. + + :param dp_name: Device profile name + :param rg_rp_map: Request group - Resource Provider map + {requester_id: [resource_provider_uuid]} + :returns: + [arq], with each ARQ associated with an RP + :raises: DeviceProfileError, AcceleratorRequestOpFailed + """ + LOG.info('Creating ARQs for device profile %s', dp_name) + arqs = self._create_arqs(dp_name) + if not arqs or len(arqs) == 0: + msg = _('device profile name %s') % dp_name + raise exception.AcceleratorRequestOpFailed(op=_('create'), msg=msg) + for arq in arqs: + dp_group_id = arq['device_profile_group_id'] + arq['device_rp_uuid'] = None + requester_id = ( + get_device_profile_group_requester_id(dp_group_id)) + arq['device_rp_uuid'] = rg_rp_map[requester_id][0] + return arqs + + def bind_arqs(self, bindings): + """Initiate Cyborg bindings. + + Handles RFC 6902-compliant JSON patching, sparing + calling Nova code from those details. + + :param bindings: + { "$arq_uuid": { + "hostname": STRING + "device_rp_uuid": UUID + "instance_uuid": UUID + }, + ... + } + :returns: nothing + :raises: AcceleratorRequestOpFailed + """ + LOG.info('Binding ARQs.') + # Create a JSON patch in RFC 6902 format + patch_list = {} + for arq_uuid, binding in bindings.items(): + patch = [{"path": "/" + field, + "op": "add", + "value": value + } for field, value in binding.items()] + patch_list[arq_uuid] = patch + + resp, err_msg = self._call_cyborg(self._client.patch, + self.ARQ_URL, json=patch_list) + if err_msg: + msg = _(' Binding failed for ARQ UUIDs: ') + err_msg = err_msg + msg + ','.join(bindings.keys()) + raise exception.AcceleratorRequestOpFailed( + op=_('bind'), msg=err_msg) + + def get_arqs_for_instance(self, instance_uuid, only_resolved=False): + """Get ARQs for the instance. + + :param instance_uuid: Instance UUID + :param only_resolved: flag to return only resolved ARQs + :returns: List of ARQs for the instance: + if only_resolved: only those ARQs which have completed binding + else: all ARQs + The format of the returned data structure is as below: + [ + {'uuid': $arq_uuid, + 'device_profile_name': $dp_name, + 'device_profile_group_id': $dp_request_group_index, + 'state': 'Bound', + 'device_rp_uuid': $resource_provider_uuid, + 'hostname': $host_nodename, + 'instance_uuid': $instance_uuid, + 'attach_handle_info': { # PCI bdf + 'bus': '0c', 'device': '0', + 'domain': '0000', 'function': '0'}, + 'attach_handle_type': 'PCI' + # or 'TEST_PCI' for Cyborg fake driver + } + ] + :raises: AcceleratorRequestOpFailed + """ + query = {"instance": instance_uuid} + resp, err_msg = self._call_cyborg(self._client.get, + self.ARQ_URL, params=query) + + if err_msg: + err_msg = err_msg + _(' Instance %s') % instance_uuid + raise exception.AcceleratorRequestOpFailed( + op=_('get'), msg=err_msg) + + arqs = resp.json().get('arqs') + if not arqs: + err_msg = _('Cyborg returned no accelerator requests for ' + 'instance %s') % instance_uuid + raise exception.AcceleratorRequestOpFailed( + op=_('get'), msg=err_msg) + + if only_resolved: + arqs = [arq for arq in arqs if + arq['state'] in ['Bound', 'BindFailed', 'Deleting']] + return arqs |