def _call_agent(session, instance, vm_ref, method, addl_args=None,
                timeout=None, success_codes=None):
    if addl_args is None:
        addl_args = {}
    if timeout is None:
        timeout = CONF.xenserver.agent_timeout
    if success_codes is None:
        success_codes = ['0']

    # always fetch domid because VM may have rebooted
    dom_id = session.VM.get_domid(vm_ref)

    args = {
        'id': str(uuid.uuid4()),
        'dom_id': str(dom_id),
        'timeout': str(timeout),
    }
    args.update(addl_args)

    try:
        ret = session.call_plugin('agent', method, args)
    except session.XenAPI.Failure as e:
        err_msg = e.details[-1].splitlines()[-1]
        if 'TIMEOUT:' in err_msg:
            LOG.error(_LE('TIMEOUT: The call to %(method)s timed out. '
                          'args=%(args)r'),
                      {'method': method, 'args': args}, instance=instance)
            raise exception.AgentTimeout(method=method)
        elif 'REBOOT:' in err_msg:
            LOG.debug('REBOOT: The call to %(method)s detected a reboot. '
                      'args=%(args)r',
                      {'method': method, 'args': args}, instance=instance)
            _wait_for_new_dom_id(session, vm_ref, dom_id, method)
            return _call_agent(session, instance, vm_ref, method,
                               addl_args, timeout, success_codes)
        elif 'NOT IMPLEMENTED:' in err_msg:
            LOG.error(_LE('NOT IMPLEMENTED: The call to %(method)s is not '
                          'supported by the agent. args=%(args)r'),
                      {'method': method, 'args': args}, instance=instance)
            raise exception.AgentNotImplemented(method=method)
        else:
            LOG.error(_LE('The call to %(method)s returned an error: %(e)s. '
                          'args=%(args)r'),
                      {'method': method, 'args': args, 'e': e},
                      instance=instance)
            raise exception.AgentError(method=method)

    if not isinstance(ret, dict):
        try:
            ret = jsonutils.loads(ret)
        except TypeError:
            LOG.error(_LE('The agent call to %(method)s returned an invalid '
                          'response: %(ret)r. args=%(args)r'),
                      {'method': method, 'ret': ret, 'args': args},
                      instance=instance)
            raise exception.AgentError(method=method)

    if ret['returncode'] not in success_codes:
        LOG.error(_LE('The agent call to %(method)s returned '
                      'an error: %(ret)r. args=%(args)r'),
                  {'method': method, 'ret': ret, 'args': args},
                  instance=instance)
        raise exception.AgentError(method=method)

    LOG.debug('The agent call to %(method)s was successful: '
              '%(ret)r. args=%(args)r',
              {'method': method, 'ret': ret, 'args': args},
              instance=instance)

    # Some old versions of the Windows agent have a trailing \\r\\n
    # (ie CRLF escaped) for some reason. Strip that off.
    return ret['message'].replace('\\r\\n', '')
Abstracts out the interaction with the agent xenapi plugin.
dataset/ETHPy150Open BU-NU-CLOUD-SP16/Trusted-Platform-Module-nova/nova/virt/xenapi/agent.py/_call_agent