launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #06176
[Merge] lp:~julian-edwards/maas/twisted-provisioning into lp:maas
Julian Edwards has proposed merging lp:~julian-edwards/maas/twisted-provisioning into lp:maas.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~julian-edwards/maas/twisted-provisioning/+merge/90092
Add the basic TAP framework for the provisioning server. A lot of code was cargo-culted from txlongpoll.
--
https://code.launchpad.net/~julian-edwards/maas/twisted-provisioning/+merge/90092
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~julian-edwards/maas/twisted-provisioning into lp:maas.
=== added directory 'src/provisioningserver'
=== added file 'src/provisioningserver/__init__.py'
=== added file 'src/provisioningserver/amqpclient.py'
--- src/provisioningserver/amqpclient.py 1970-01-01 00:00:00 +0000
+++ src/provisioningserver/amqpclient.py 2012-01-25 12:26:24 +0000
@@ -0,0 +1,124 @@
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+# Shamelessly cargo-culted from the txlongpoll source.
+
+"""
+Asynchronous client for AMQP using txAMQP.
+"""
+
+from __future__ import (
+ print_function,
+ unicode_literals,
+ )
+
+import os.path
+
+from twisted.internet.defer import maybeDeferred
+from twisted.internet.protocol import ReconnectingClientFactory
+from txamqp.client import TwistedDelegate
+from txamqp.protocol import AMQClient
+from txamqp.queue import Closed
+from txamqp.spec import load as load_spec
+
+__metaclass__ = type
+__all__ = [
+ "AMQFactory",
+ ]
+
+
+class AMQClientWithCallback(AMQClient):
+ """
+ An C{AMQClient} that notifies connections with a callback.
+
+ @ivar connected_callback: callback called when C{connectionMade} is
+ called. It takes one argument, the protocol instance itself.
+ """
+
+ def __init__(self, connected_callback, *args, **kwargs):
+ AMQClient.__init__(self, *args, **kwargs)
+ self.connected_callback = connected_callback
+
+ def connectionMade(self):
+ AMQClient.connectionMade(self)
+ self.connected_callback(self)
+
+
+_base_dir = os.path.dirname(os.path.abspath(__file__))
+AMQP0_8_SPEC = load_spec(os.path.join(_base_dir, "specs", "amqp0-8.xml"))
+del _base_dir
+
+
+class AMQFactory(ReconnectingClientFactory):
+ """
+ A C{ClientFactory} for C{AMQClient} protocol with reconnecting facilities.
+
+ @ivar user: the user name to use to connect to the AMQP server.
+ @ivar password: the corresponding password of the user.
+ @ivar vhost: the AMQP vhost to create connections against.
+ @ivar connected_callback: callback called when a successful connection
+ happened. It takes one argument, the channel opened for the connection.
+ @ivar disconnected_callback: callback called when a previously connected
+ connection was lost. It takes no argument.
+ """
+ protocol = AMQClientWithCallback
+ initialDelay = 0.01
+
+ def __init__(self, user, password, vhost, connected_callback,
+ disconnected_callback, failed_callback, spec=None):
+ self.user = user
+ self.password = password
+ self.vhost = vhost
+ self.delegate = TwistedDelegate()
+ if spec is None:
+ spec = AMQP0_8_SPEC
+ self.spec = spec
+ self.connected_callback = connected_callback
+ self.disconnected_callback = disconnected_callback
+ self.failed_callback = failed_callback
+
+ def buildProtocol(self, addr):
+ """
+ Create the protocol instance and returns it for letting Twisted
+ connect it to the transport.
+
+ @param addr: the attributed address, unused for now.
+ """
+ protocol = self.protocol(self.clientConnectionMade, self.delegate,
+ self.vhost, spec=self.spec)
+ protocol.factory = self
+ return protocol
+
+ def clientConnectionMade(self, client):
+ """
+ Called when a connection succeeds: login to the server, and open a
+ channel against it.
+ """
+ self.resetDelay()
+
+ def started(ignored):
+ # We don't care about authenticate result as long as it succeeds
+ return client.channel(1).addCallback(got_channel)
+
+ def got_channel(channel):
+ return channel.channel_open().addCallback(opened, channel)
+
+ def opened(ignored, channel):
+ deferred = maybeDeferred(
+ self.connected_callback, (client, channel))
+ deferred.addErrback(catch_closed)
+
+ def catch_closed(failure):
+ failure.trap(Closed)
+
+ deferred = client.authenticate(self.user, self.password)
+ return deferred.addCallback(started)
+
+ def clientConnectionLost(self, connector, reason):
+ ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
+ self.disconnected_callback()
+
+ def clientConnectionFailed(self, connector, reason):
+ ReconnectingClientFactory.clientConnectionFailed(
+ self, connector, reason)
+ self.failed_callback((connector, reason))
=== added file 'src/provisioningserver/plugin.py'
--- src/provisioningserver/plugin.py 1970-01-01 00:00:00 +0000
+++ src/provisioningserver/plugin.py 2012-01-25 12:26:24 +0000
@@ -0,0 +1,150 @@
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+from __future__ import (
+ print_function,
+ unicode_literals,
+ )
+
+"""Twisted Application Plugin code for the MaaS provisioning server"""
+
+import setproctitle
+import signal
+import sys
+
+import oops
+from oops_datedir_repo import DateDirRepo
+from oops_twisted import (
+ Config as oops_config,
+ defer_publisher,
+ OOPSObserver,
+ )
+from twisted.application.internet import TCPClient
+from twisted.application.service import (
+ IServiceMaker,
+ MultiService,
+ )
+from twisted.internet import reactor
+from twisted.plugin import IPlugin
+from twisted.python import (
+ log,
+ usage,
+ )
+from twisted.python.logfile import LogFile
+from twisted.python.log import (
+ addObserver,
+ FileLogObserver,
+ )
+from zope.interface import implements
+
+from amqpclient import AMQFactory
+
+__metaclass__ = type
+__all__ = []
+
+
+def getRotatableLogFileObserver(filename):
+ """Setup a L{LogFile} for the given application."""
+ if filename != '-':
+ logfile = LogFile.fromFullPath(
+ filename, rotateLength=None, defaultMode=0644)
+ def signal_handler(sig, frame):
+ reactor.callFromThread(logfile.reopen)
+ signal.signal(signal.SIGUSR1, signal_handler)
+ else:
+ logfile = sys.stdout
+ return FileLogObserver(logfile)
+
+
+def setUpOOPSHandler(options, logfile):
+ """Add OOPS handling based on the passed command line options."""
+ config = oops_config()
+
+ # Add the oops publisher that writes files in the configured place
+ # if the command line option was set.
+
+ if options["oops-dir"]:
+ repo = DateDirRepo(options["oops-dir"])
+ config.publishers.append(
+ defer_publisher(oops.publish_new_only(repo.publish)))
+
+ if options["oops-reporter"]:
+ config.template['reporter'] = options["oops-reporter"]
+
+ observer = OOPSObserver(config, logfile.emit)
+ addObserver(observer.emit)
+ return observer
+
+
+class Options(usage.Options):
+ """Command line options for the provisioning server."""
+
+ optParameters = [
+ ["logfile", "l", "provisioningserver.log", "Logfile name."],
+ ["brokerport", "p", 5672, "Broker port"],
+ ["brokerhost", "h", '127.0.0.1', "Broker host"],
+ ["brokeruser", "u", None, "Broker user"],
+ ["brokerpassword", "a", None, "Broker password"],
+ ["brokervhost", "v", '/', "Broker vhost"],
+ ["oops-dir", "r", None, "Where to write OOPS reports"],
+ ["oops-reporter", "o", "MAAS-PS", "String identifying this service."],
+ ]
+
+ def postOptions(self):
+ for arg in ('brokeruser', 'brokerpassword'):
+ if not self[arg]:
+ raise usage.UsageError("--%s must be specified." % arg)
+ for int_arg in ('brokerport'):
+ try:
+ self[int_arg] = int(self[int_arg])
+ except (TypeError, ValueError):
+ raise usage.UsageError("--%s must be an integer." % int_arg)
+ if not self["oops-reporter"] and self["oops-dir"]:
+ raise usage.UsageError(
+ "A reporter must be supplied to identify reports "
+ "from this service from other OOPS reports.")
+
+class ProvisioningServiceMaker(object):
+ """Create a service for the Twisted plugin."""
+
+ implements(IServiceMaker, IPlugin)
+
+ def __init__(self, name, description):
+ self.tapname = name
+ self.description = description
+
+ def makeService(self, options):
+ """Construct a service."""
+ # Required to hide the command line options that include a password.
+ # There is a small window where it can be seen though, between
+ # invocation and when this code runs.
+ setproctitle.setproctitle("maas provisioning service")
+
+ logfile = getRotatableLogFileObserver(options["logfile"])
+ setUpOOPSHandler(options, logfile)
+
+ broker_port = options["brokerport"]
+ broker_host = options["brokerhost"]
+ broker_user = options["brokeruser"]
+ broker_password = options["brokerpassword"]
+ broker_vhost = options["brokervhost"]
+
+ # TODO: define callbacks for Rabbit connectivity.
+ # e.g. construct a manager object.
+ client_factory = AMQFactory(
+ broker_user, broker_password, broker_vhost,
+ CONNECTED_CALLBACK, DISCONNECTED_CALLBACK,
+ lambda (connector, reason): log.err(reason, "Connection failed"))
+
+ # TODO: Create services here, e.g.
+ # service1 = thing
+ # service2 = thing2
+ # services = MultiService()
+ # services.addService(service1)
+ # services.addService(service2)
+ # return services
+
+ client_service = TCPClient(broker_host, broker_port, client_factory)
+ services = MultiService()
+ services.addService(client_service)
+ return services
=== added directory 'src/provisioningserver/specs'
=== added file 'src/provisioningserver/specs/amqp0-8.xml'
--- src/provisioningserver/specs/amqp0-8.xml 1970-01-01 00:00:00 +0000
+++ src/provisioningserver/specs/amqp0-8.xml 2012-01-25 12:26:24 +0000
@@ -0,0 +1,771 @@
+<?xml version="1.0"?>
+<!--
+Copyright (c) 2009 AMQP Working Group.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<amqp major="8" minor="0" port="5672">
+ <constant name="frame method" value="1"/>
+ <constant name="frame header" value="2"/>
+ <constant name="frame body" value="3"/>
+ <constant name="frame oob method" value="4"/>
+ <constant name="frame oob header" value="5"/>
+ <constant name="frame oob body" value="6"/>
+ <constant name="frame trace" value="7"/>
+ <constant name="frame heartbeat" value="8"/>
+ <constant name="frame min size" value="4096"/>
+ <constant name="frame end" value="206"/>
+ <constant name="reply success" value="200"/>
+ <constant name="not delivered" value="310" class="soft error"/>
+ <constant name="content too large" value="311" class="soft error"/>
+ <constant name="connection forced" value="320" class="hard error"/>
+ <constant name="invalid path" value="402" class="hard error"/>
+ <constant name="access refused" value="403" class="soft error"/>
+ <constant name="not found" value="404" class="soft error"/>
+ <constant name="resource locked" value="405" class="soft error"/>
+ <constant name="frame error" value="501" class="hard error"/>
+ <constant name="syntax error" value="502" class="hard error"/>
+ <constant name="command invalid" value="503" class="hard error"/>
+ <constant name="channel error" value="504" class="hard error"/>
+ <constant name="resource error" value="506" class="hard error"/>
+ <constant name="not allowed" value="530" class="hard error"/>
+ <constant name="not implemented" value="540" class="hard error"/>
+ <constant name="internal error" value="541" class="hard error"/>
+ <domain name="access ticket" type="short">
+ <assert check="ne" value="0"/>
+ </domain>
+ <domain name="class id" type="short"/>
+ <domain name="consumer tag" type="shortstr"/>
+ <domain name="delivery tag" type="longlong"/>
+ <domain name="exchange name" type="shortstr">
+ <assert check="length" value="127"/>
+ </domain>
+ <domain name="known hosts" type="shortstr"/>
+ <domain name="method id" type="short"/>
+ <domain name="no ack" type="bit"/>
+ <domain name="no local" type="bit"/>
+ <domain name="path" type="shortstr">
+ <assert check="notnull"/>
+ <assert check="syntax" rule="path"/>
+ <assert check="length" value="127"/>
+ </domain>
+ <domain name="peer properties" type="table"/>
+ <domain name="queue name" type="shortstr">
+ <assert check="length" value="127"/>
+ </domain>
+ <domain name="redelivered" type="bit"/>
+ <domain name="reply code" type="short">
+ <assert check="notnull"/>
+ </domain>
+ <domain name="reply text" type="shortstr">
+ <assert check="notnull"/>
+ </domain>
+ <class name="connection" handler="connection" index="10">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <method name="start" synchronous="1" index="10">
+ <chassis name="client" implement="MUST"/>
+ <response name="start-ok"/>
+ <field name="version major" type="octet"/>
+ <field name="version minor" type="octet"/>
+ <field name="server properties" domain="peer properties"/>
+ <field name="mechanisms" type="longstr">
+ <see name="security mechanisms"/>
+ <assert check="notnull"/>
+ </field>
+ <field name="locales" type="longstr">
+ <assert check="notnull"/>
+ </field>
+ </method>
+ <method name="start-ok" synchronous="1" index="11">
+ <chassis name="server" implement="MUST"/>
+ <field name="client properties" domain="peer properties"/>
+ <field name="mechanism" type="shortstr">
+ <assert check="notnull"/>
+ </field>
+ <field name="response" type="longstr">
+ <assert check="notnull"/>
+ </field>
+ <field name="locale" type="shortstr">
+ <assert check="notnull"/>
+ </field>
+ </method>
+ <method name="secure" synchronous="1" index="20">
+ <chassis name="client" implement="MUST"/>
+ <response name="secure-ok"/>
+ <field name="challenge" type="longstr">
+ <see name="security mechanisms"/>
+ </field>
+ </method>
+ <method name="secure-ok" synchronous="1" index="21">
+ <chassis name="server" implement="MUST"/>
+ <field name="response" type="longstr">
+ <assert check="notnull"/>
+ </field>
+ </method>
+ <method name="tune" synchronous="1" index="30">
+ <chassis name="client" implement="MUST"/>
+ <response name="tune-ok"/>
+ <field name="channel max" type="short"/>
+ <field name="frame max" type="long"/>
+ <field name="heartbeat" type="short"/>
+ </method>
+ <method name="tune-ok" synchronous="1" index="31">
+ <chassis name="server" implement="MUST"/>
+ <field name="channel max" type="short">
+ <assert check="notnull"/>
+ <assert check="le" method="tune" field="channel max"/>
+ </field>
+ <field name="frame max" type="long"/>
+ <field name="heartbeat" type="short"/>
+ </method>
+ <method name="open" synchronous="1" index="40">
+ <chassis name="server" implement="MUST"/>
+ <response name="open-ok"/>
+ <response name="redirect"/>
+ <field name="virtual host" domain="path">
+ <assert check="regexp" value="^[a-zA-Z0-9/-_]+$"/>
+ </field>
+ <field name="capabilities" type="shortstr"/>
+ <field name="insist" type="bit"/>
+ </method>
+ <method name="open-ok" synchronous="1" index="41">
+ <chassis name="client" implement="MUST"/>
+ <field name="known hosts" domain="known hosts"/>
+ </method>
+ <method name="redirect" synchronous="1" index="50">
+ <chassis name="client" implement="MAY"/>
+ <field name="host" type="shortstr">
+ <assert check="notnull"/>
+ </field>
+ <field name="known hosts" domain="known hosts"/>
+ </method>
+ <method name="close" synchronous="1" index="60">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <response name="close-ok"/>
+ <field name="reply code" domain="reply code"/>
+ <field name="reply text" domain="reply text"/>
+ <field name="class id" domain="class id"/>
+ <field name="method id" domain="class id"/>
+ </method>
+ <method name="close-ok" synchronous="1" index="61">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ </method>
+ </class>
+ <class name="channel" handler="channel" index="20">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <method name="open" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="open-ok"/>
+ <field name="out of band" type="shortstr">
+ <assert check="null"/>
+ </field>
+ </method>
+ <method name="open-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="flow" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <response name="flow-ok"/>
+ <field name="active" type="bit"/>
+ </method>
+ <method name="flow-ok" index="21">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <field name="active" type="bit"/>
+ </method>
+ <method name="alert" index="30">
+ <chassis name="client" implement="MUST"/>
+ <field name="reply code" domain="reply code"/>
+ <field name="reply text" domain="reply text"/>
+ <field name="details" type="table"/>
+ </method>
+ <method name="close" synchronous="1" index="40">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <response name="close-ok"/>
+ <field name="reply code" domain="reply code"/>
+ <field name="reply text" domain="reply text"/>
+ <field name="class id" domain="class id"/>
+ <field name="method id" domain="method id"/>
+ </method>
+ <method name="close-ok" synchronous="1" index="41">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ </method>
+ </class>
+ <class name="access" handler="connection" index="30">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <method name="request" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="request-ok"/>
+ <field name="realm" domain="path"/>
+ <field name="exclusive" type="bit"/>
+ <field name="passive" type="bit"/>
+ <field name="active" type="bit"/>
+ <field name="write" type="bit"/>
+ <field name="read" type="bit"/>
+ </method>
+ <method name="request-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ <field name="ticket" domain="access ticket"/>
+ </method>
+ </class>
+ <class name="exchange" handler="channel" index="40">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <method name="declare" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="declare-ok"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="exchange" domain="exchange name">
+ <assert check="regexp" value="^[a-zA-Z0-9-_.:]+$"/>
+ </field>
+ <field name="type" type="shortstr">
+ <assert check="regexp" value="^[a-zA-Z0-9-_.:]+$"/>
+ </field>
+ <field name="passive" type="bit"/>
+ <field name="durable" type="bit"/>
+ <field name="auto delete" type="bit"/>
+ <field name="internal" type="bit"/>
+ <field name="nowait" type="bit"/>
+ <field name="arguments" type="table"/>
+ </method>
+ <method name="declare-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="delete" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <response name="delete-ok"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="exchange" domain="exchange name">
+ <assert check="notnull"/>
+ </field>
+ <field name="if unused" type="bit"/>
+ <field name="nowait" type="bit"/>
+ </method>
+ <method name="delete-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ </class>
+ <class name="queue" handler="channel" index="50">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <method name="declare" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="declare-ok"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="queue" domain="queue name">
+ <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/>
+ </field>
+ <field name="passive" type="bit"/>
+ <field name="durable" type="bit"/>
+ <field name="exclusive" type="bit"/>
+ <field name="auto delete" type="bit"/>
+ <field name="nowait" type="bit"/>
+ <field name="arguments" type="table"/>
+ </method>
+ <method name="declare-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ <field name="queue" domain="queue name">
+ <assert check="notnull"/>
+ </field>
+ <field name="message count" type="long"/>
+ <field name="consumer count" type="long"/>
+ </method>
+ <method name="bind" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <response name="bind-ok"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="queue" domain="queue name"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" type="shortstr"/>
+ <field name="nowait" type="bit"/>
+ <field name="arguments" type="table"/>
+ </method>
+ <method name="bind-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="unbind" synchronous="1" index="50">
+ <chassis name="server" implement="MUST"/>
+ <response name="unbind-ok"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="queue" domain="queue name"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" domain="shortstr"/>
+ <field name="arguments" domain="table"/>
+ </method>
+ <method name="unbind-ok" synchronous="1" index="51">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="purge" synchronous="1" index="30">
+ <chassis name="server" implement="MUST"/>
+ <response name="purge-ok"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="queue" domain="queue name"/>
+ <field name="nowait" type="bit"/>
+ </method>
+ <method name="purge-ok" synchronous="1" index="31">
+ <chassis name="client" implement="MUST"/>
+ <field name="message count" type="long"/>
+ </method>
+ <method name="delete" synchronous="1" index="40">
+ <chassis name="server" implement="MUST"/>
+ <response name="delete-ok"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="queue" domain="queue name"/>
+ <field name="if unused" type="bit"/>
+ <field name="if empty" type="bit">
+ <test/>
+ </field>
+ <field name="nowait" type="bit"/>
+ </method>
+ <method name="delete-ok" synchronous="1" index="41">
+ <chassis name="client" implement="MUST"/>
+ <field name="message count" type="long"/>
+ </method>
+ </class>
+ <class name="basic" handler="channel" index="60">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MAY"/>
+ <field name="content type" type="shortstr"/>
+ <field name="content encoding" type="shortstr"/>
+ <field name="headers" type="table"/>
+ <field name="delivery mode" type="octet"/>
+ <field name="priority" type="octet"/>
+ <field name="correlation id" type="shortstr"/>
+ <field name="reply to" type="shortstr"/>
+ <field name="expiration" type="shortstr"/>
+ <field name="message id" type="shortstr"/>
+ <field name="timestamp" type="timestamp"/>
+ <field name="type" type="shortstr"/>
+ <field name="user id" type="shortstr"/>
+ <field name="app id" type="shortstr"/>
+ <field name="cluster id" type="shortstr"/>
+ <method name="qos" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="qos-ok"/>
+ <field name="prefetch size" type="long"/>
+ <field name="prefetch count" type="short"/>
+ <field name="global" type="bit"/>
+ </method>
+ <method name="qos-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="consume" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <response name="consume-ok"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="queue" domain="queue name"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ <field name="no local" domain="no local"/>
+ <field name="no ack" domain="no ack"/>
+ <field name="exclusive" type="bit"/>
+ <field name="nowait" type="bit"/>
+ </method>
+ <method name="consume-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ </method>
+ <method name="cancel" synchronous="1" index="30">
+ <chassis name="server" implement="MUST"/>
+ <response name="cancel-ok"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ <field name="nowait" type="bit"/>
+ </method>
+ <method name="cancel-ok" synchronous="1" index="31">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ </method>
+ <method name="publish" content="1" index="40">
+ <chassis name="server" implement="MUST"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" type="shortstr"/>
+ <field name="mandatory" type="bit"/>
+ <field name="immediate" type="bit"/>
+ </method>
+ <method name="return" content="1" index="50">
+ <chassis name="client" implement="MUST"/>
+ <field name="reply code" domain="reply code"/>
+ <field name="reply text" domain="reply text"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" type="shortstr"/>
+ </method>
+ <method name="deliver" content="1" index="60">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ <field name="delivery tag" domain="delivery tag"/>
+ <field name="redelivered" domain="redelivered"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" type="shortstr"/>
+ </method>
+ <method name="get" synchronous="1" index="70">
+ <response name="get-ok"/>
+ <response name="get-empty"/>
+ <chassis name="server" implement="MUST"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="queue" domain="queue name"/>
+ <field name="no ack" domain="no ack"/>
+ </method>
+ <method name="get-ok" synchronous="1" content="1" index="71">
+ <chassis name="client" implement="MAY"/>
+ <field name="delivery tag" domain="delivery tag"/>
+ <field name="redelivered" domain="redelivered"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" type="shortstr"/>
+ <field name="message count" type="long"/>
+ </method>
+ <method name="get-empty" synchronous="1" index="72">
+ <chassis name="client" implement="MAY"/>
+ <field name="cluster id" type="shortstr"/>
+ </method>
+ <method name="ack" index="80">
+ <chassis name="server" implement="MUST"/>
+ <field name="delivery tag" domain="delivery tag"/>
+ <field name="multiple" type="bit"/>
+ </method>
+ <method name="reject" index="90">
+ <chassis name="server" implement="MUST"/>
+ <field name="delivery tag" domain="delivery tag"/>
+ <field name="requeue" type="bit"/>
+ </method>
+ <method name="recover" index="100">
+ <chassis name="server" implement="MUST"/>
+ <field name="requeue" type="bit"/>
+ </method>
+ </class>
+ <class name="file" handler="channel" index="70">
+ <chassis name="server" implement="MAY"/>
+ <chassis name="client" implement="MAY"/>
+ <field name="content type" type="shortstr"/>
+ <field name="content encoding" type="shortstr"/>
+ <field name="headers" type="table"/>
+ <field name="priority" type="octet"/>
+ <field name="reply to" type="shortstr"/>
+ <field name="message id" type="shortstr"/>
+ <field name="filename" type="shortstr"/>
+ <field name="timestamp" type="timestamp"/>
+ <field name="cluster id" type="shortstr"/>
+ <method name="qos" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="qos-ok"/>
+ <field name="prefetch size" type="long"/>
+ <field name="prefetch count" type="short"/>
+ <field name="global" type="bit"/>
+ </method>
+ <method name="qos-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="consume" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <response name="consume-ok"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="queue" domain="queue name"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ <field name="no local" domain="no local"/>
+ <field name="no ack" domain="no ack"/>
+ <field name="exclusive" type="bit"/>
+ <field name="nowait" type="bit"/>
+ </method>
+ <method name="consume-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ </method>
+ <method name="cancel" synchronous="1" index="30">
+ <chassis name="server" implement="MUST"/>
+ <response name="cancel-ok"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ <field name="nowait" type="bit"/>
+ </method>
+ <method name="cancel-ok" synchronous="1" index="31">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ </method>
+ <method name="open" synchronous="1" index="40">
+ <response name="open-ok"/>
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <field name="identifier" type="shortstr"/>
+ <field name="content size" type="longlong"/>
+ </method>
+ <method name="open-ok" synchronous="1" index="41">
+ <response name="stage"/>
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ <field name="staged size" type="longlong"/>
+ </method>
+ <method name="stage" content="1" index="50">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="publish" index="60">
+ <chassis name="server" implement="MUST"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" type="shortstr"/>
+ <field name="mandatory" type="bit"/>
+ <field name="immediate" type="bit"/>
+ <field name="identifier" type="shortstr"/>
+ </method>
+ <method name="return" content="1" index="70">
+ <chassis name="client" implement="MUST"/>
+ <field name="reply code" domain="reply code"/>
+ <field name="reply text" domain="reply text"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" type="shortstr"/>
+ </method>
+ <method name="deliver" index="80">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ <field name="delivery tag" domain="delivery tag"/>
+ <field name="redelivered" domain="redelivered"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" type="shortstr"/>
+ <field name="identifier" type="shortstr"/>
+ </method>
+ <method name="ack" index="90">
+ <chassis name="server" implement="MUST"/>
+ <field name="delivery tag" domain="delivery tag"/>
+ <field name="multiple" type="bit"/>
+ </method>
+ <method name="reject" index="100">
+ <chassis name="server" implement="MUST"/>
+ <field name="delivery tag" domain="delivery tag"/>
+ <field name="requeue" type="bit"/>
+ </method>
+ </class>
+ <class name="stream" handler="channel" index="80">
+ <chassis name="server" implement="MAY"/>
+ <chassis name="client" implement="MAY"/>
+ <field name="content type" type="shortstr"/>
+ <field name="content encoding" type="shortstr"/>
+ <field name="headers" type="table"/>
+ <field name="priority" type="octet"/>
+ <field name="timestamp" type="timestamp"/>
+ <method name="qos" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="qos-ok"/>
+ <field name="prefetch size" type="long"/>
+ <field name="prefetch count" type="short"/>
+ <field name="consume rate" type="long"/>
+ <field name="global" type="bit"/>
+ </method>
+ <method name="qos-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="consume" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <response name="consume-ok"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="queue" domain="queue name"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ <field name="no local" domain="no local"/>
+ <field name="exclusive" type="bit"/>
+ <field name="nowait" type="bit"/>
+ </method>
+ <method name="consume-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ </method>
+ <method name="cancel" synchronous="1" index="30">
+ <chassis name="server" implement="MUST"/>
+ <response name="cancel-ok"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ <field name="nowait" type="bit"/>
+ </method>
+ <method name="cancel-ok" synchronous="1" index="31">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ </method>
+ <method name="publish" content="1" index="40">
+ <chassis name="server" implement="MUST"/>
+ <field name="ticket" domain="access ticket"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" type="shortstr"/>
+ <field name="mandatory" type="bit"/>
+ <field name="immediate" type="bit"/>
+ </method>
+ <method name="return" content="1" index="50">
+ <chassis name="client" implement="MUST"/>
+ <field name="reply code" domain="reply code"/>
+ <field name="reply text" domain="reply text"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="routing key" type="shortstr"/>
+ </method>
+ <method name="deliver" content="1" index="60">
+ <chassis name="client" implement="MUST"/>
+ <field name="consumer tag" domain="consumer tag"/>
+ <field name="delivery tag" domain="delivery tag"/>
+ <field name="exchange" domain="exchange name"/>
+ <field name="queue" domain="queue name">
+ <assert check="notnull"/>
+ </field>
+ </method>
+ </class>
+ <class name="tx" handler="channel" index="90">
+ <chassis name="server" implement="SHOULD"/>
+ <chassis name="client" implement="MAY"/>
+ <method name="select" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="select-ok"/>
+ </method>
+ <method name="select-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="commit" synchronous="1" index="20">
+ <chassis name="server" implement="MUST"/>
+ <response name="commit-ok"/>
+ </method>
+ <method name="commit-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="rollback" synchronous="1" index="30">
+ <chassis name="server" implement="MUST"/>
+ <response name="rollback-ok"/>
+ </method>
+ <method name="rollback-ok" synchronous="1" index="31">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ </class>
+ <class name="dtx" handler="channel" index="100">
+ <chassis name="server" implement="MAY"/>
+ <chassis name="client" implement="MAY"/>
+ <method name="select" synchronous="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <response name="select-ok"/>
+ </method>
+ <method name="select-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ <method name="start" synchronous="1" index="20">
+ <chassis name="server" implement="MAY"/>
+ <response name="start-ok"/>
+ <field name="dtx identifier" type="shortstr">
+ <assert check="notnull"/>
+ </field>
+ </method>
+ <method name="start-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ </method>
+ </class>
+ <class name="tunnel" handler="tunnel" index="110">
+ <chassis name="server" implement="MAY"/>
+ <chassis name="client" implement="MAY"/>
+ <field name="headers" type="table"/>
+ <field name="proxy name" type="shortstr"/>
+ <field name="data name" type="shortstr"/>
+ <field name="durable" type="octet"/>
+ <field name="broadcast" type="octet"/>
+ <method name="request" content="1" index="10">
+ <chassis name="server" implement="MUST"/>
+ <field name="meta data" type="table"/>
+ </method>
+ </class>
+ <class name="test" handler="channel" index="120">
+ <chassis name="server" implement="MUST"/>
+ <chassis name="client" implement="SHOULD"/>
+ <method name="integer" synchronous="1" index="10">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <response name="integer-ok"/>
+ <field name="integer 1" type="octet"/>
+ <field name="integer 2" type="short"/>
+ <field name="integer 3" type="long"/>
+ <field name="integer 4" type="longlong"/>
+ <field name="operation" type="octet">
+ <assert check="enum">
+ <value name="add"/>
+ <value name="min"/>
+ <value name="max"/>
+ </assert>
+ </field>
+ </method>
+ <method name="integer-ok" synchronous="1" index="11">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <field name="result" type="longlong"/>
+ </method>
+ <method name="string" synchronous="1" index="20">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <response name="string-ok"/>
+ <field name="string 1" type="shortstr"/>
+ <field name="string 2" type="longstr"/>
+ <field name="operation" type="octet">
+ <assert check="enum">
+ <value name="add"/>
+ <value name="min"/>
+ <value name="max"/>
+ </assert>
+ </field>
+ </method>
+ <method name="string-ok" synchronous="1" index="21">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <field name="result" type="longstr"/>
+ </method>
+ <method name="table" synchronous="1" index="30">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <response name="table-ok"/>
+ <field name="table" type="table"/>
+ <field name="integer op" type="octet">
+ <assert check="enum">
+ <value name="add"/>
+ <value name="min"/>
+ <value name="max"/>
+ </assert>
+ </field>
+ <field name="string op" type="octet">
+ <assert check="enum">
+ <value name="add"/>
+ <value name="min"/>
+ <value name="max"/>
+ </assert>
+ </field>
+ </method>
+ <method name="table-ok" synchronous="1" index="31">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <field name="integer result" type="longlong"/>
+ <field name="string result" type="longstr"/>
+ </method>
+ <method name="content" synchronous="1" content="1" index="40">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <response name="content-ok"/>
+ </method>
+ <method name="content-ok" synchronous="1" content="1" index="41">
+ <chassis name="client" implement="MUST"/>
+ <chassis name="server" implement="MUST"/>
+ <field name="content checksum" type="long"/>
+ </method>
+ </class>
+</amqp>
=== added directory 'twisted'
=== added directory 'twisted/plugins'
=== added file 'twisted/plugins/maasps.py'
--- twisted/plugins/maasps.py 1970-01-01 00:00:00 +0000
+++ twisted/plugins/maasps.py 2012-01-25 12:26:24 +0000
@@ -0,0 +1,22 @@
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+from __future__ import (
+ absolute_import,
+ print_function,
+ unicode_literals,
+ )
+
+"""Twisted Application Plugin for the Maas provisioning server."""
+
+__metaclass__ = type
+__all__ = []
+
+
+from provisioningserver.plugin import ProvisioningServiceMaker
+
+# Construct objects which *provide* the relevant interfaces. The name of
+# these variables is irrelevant, as long as there are *some* names bound
+# to # providers of IPlugin and IServiceMaker.
+
+service = ProvisioningServiceMaker(...) # TODO: finish
Follow ups