def require_one(self, key, host=None, strict=True, reverse=False, dirty=False): """Require a resource, returning a scalar. For the parameters, see :py:meth:`require`. :return: The matching resource that was provided. :rtype: object This version returns a single value instead of a list. Also, if the number of potential results is not exactly one, then an error will be raised (which you should not catch). batou will notify you of this as being an inconsistent configuration. """ resources = self.require(key, host, strict, reverse, dirty) if len(resources) > 1: raise KeyError( 'Expected only one result, got multiple for (key={}, host={})'. format(key, host)) elif len(resources) == 0: raise SilentConfigurationError() return resources[0]
def call(*args, **kw): output.annotate("rpc {}: {}(*{}, **{})".format( self.host.fqdn, name, args, kw), debug=True) self.host.channel.send((name, args, kw)) while True: message = self.host.channel.receive() output.annotate("{}: message: {}".format( self.host.fqdn, message), debug=True) type = message[0] if type == "batou-result": return message[1] elif type == "batou-output": _, output_cmd, args, kw = message getattr(output, output_cmd)(*args, **kw) elif type == "batou-configuration-error": raise SilentConfigurationError() elif type == "batou-deployment-error": raise DeploymentError() elif type == "batou-unknown-error": output.error(message[1]) raise RuntimeError( "{}: Remote exception encountered.".format( self.host.fqdn)) elif type == "batou-error": # Remote put out the details already. raise RuntimeError( "{}: Remote exception encountered.".format( self.host.fqdn)) else: raise RuntimeError("{}: Unknown message type {}".format( self.host.fqdn, type))