From 9442e4070213ab782911e19019dbef405f191ab6 Mon Sep 17 00:00:00 2001
From: Steven Dake <sdake@redhat.com>
Date: Fri, 21 Nov 2014 15:21:34 -0700
Subject: [PATCH] Add backend processor for AMQP

Backend processors execute the ReST API using a specific backend.  For
example, docker implements the container backends.  k8s implements the pod
and services backends.  If at some later date, someone wants to implement
a fully native backend, that would be possible.  In the short term (next 4-6
weeks) I'd like to focus on backends using k8s and docker only rather then
trying to get native to work.

Change-Id: I77abde65dfe03e12f2931854da52a69f5e618d93
---
 magnum/backend/__init__.py          |   0
 magnum/backend/backend.py           | 106 ++++++++++++++++++++++++++
 magnum/backend/config.py            |  33 +++++++++
 magnum/backend/handlers/__init__.py |   0
 magnum/backend/handlers/docker.py   | 105 ++++++++++++++++++++++++++
 magnum/backend/handlers/k8s.py      | 111 ++++++++++++++++++++++++++++
 magnum/cmd/backend.py               |  48 ++++++++++++
 setup.cfg                           |   1 +
 8 files changed, 404 insertions(+)
 create mode 100644 magnum/backend/__init__.py
 create mode 100644 magnum/backend/backend.py
 create mode 100644 magnum/backend/config.py
 create mode 100644 magnum/backend/handlers/__init__.py
 create mode 100644 magnum/backend/handlers/docker.py
 create mode 100644 magnum/backend/handlers/k8s.py
 create mode 100644 magnum/cmd/backend.py

diff --git a/magnum/backend/__init__.py b/magnum/backend/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/magnum/backend/backend.py b/magnum/backend/backend.py
new file mode 100644
index 0000000000..c3d8a07cc3
--- /dev/null
+++ b/magnum/backend/backend.py
@@ -0,0 +1,106 @@
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+
+"""API for interfacing with Magnum Backend."""
+
+from oslo.config import cfg
+
+from magnum.common.rpc import service
+
+
+# The Backend API class serves as a AMQP client for communicating
+# on a topic exchange specific to the backends.  This allows the ReST
+# API to trigger operations on the backends
+
+class API(service.API):
+    def __init__(self, transport=None, context=None):
+        cfg.CONF.import_opt('topic', 'magnum.backends.config',
+                            group='backends')
+        super(API, self).__init__(transport, context,
+                                  topic=cfg.CONF.backends.topic)
+
+    # Bay Operations
+
+    def bay_create(self, uuid, contents):
+        return self._call('bay_get', contents=contents)
+
+    def bay_list(self):
+        return self._call('bay_list')
+
+    def bay_delete(self, uuid):
+        return self._call('bay_delete', uuid=uuid)
+
+    def bay_show(self, uuid):
+        return self._call('bay_show', uuid=uuid)
+
+    # Service Operations
+
+    def service_create(self, uuid, contents):
+        return self._call('service_create', uuid=uuid, contents=contents)
+
+    def service_list(self):
+        return self._call('service_list')
+
+    def service_delete(self, uuid):
+        return self._call('service_delete', uuid=uuid)
+
+    def service_show(self, uuid):
+        return self._call('service_show', uuid=uuid)
+
+    # Pod Operations
+
+    def pod_create(self, uuid, contents):
+        return self._call('pod_create4', uuid=uuid, contents=contents)
+
+    def pod_list(self):
+        return self._call('pod_list')
+
+    def pod_delete(self, uuid):
+        return self._call('pod_delete', uuid=uuid)
+
+    def pod_show(self, uuid):
+        return self._call('pod_show', uuid=uuid)
+
+    # Container operations
+
+    def container_create(self, uuid, contents):
+        return self._call('container_create', uuid=uuid)
+
+    def container_list(self):
+        return self._call('container_list')
+
+    def container_delete(self, uuid):
+        return self._call('container_delete', uuid=uuid)
+
+    def container_show(self, uuid):
+        return self._call('container_show', uuid=uuid)
+
+    def container_reboot(self, uuid):
+        return self._call('container_reboot', uuid=uuid)
+
+    def container_stop(self, uuid):
+        return self._call('container_stop', uuid=uuid)
+
+    def container_start(self, uuid):
+        return self._call('container_start', uuid=uuid)
+
+    def container_pause(self, uuid):
+        return self._call('container_pause', uuid=uuid)
+
+    def container_unpause(self, uuid):
+        return self._call('container_unpause', uuid=uuid)
+
+    def container_logs(self, uuid):
+        return self._call('container_logs', uuid=uuid)
+
+    def container_execute(self, uuid):
+        return self._call('container_execute', uuid=uuid)
diff --git a/magnum/backend/config.py b/magnum/backend/config.py
new file mode 100644
index 0000000000..0792c4db77
--- /dev/null
+++ b/magnum/backend/config.py
@@ -0,0 +1,33 @@
+# Copyright 2014 - Rackspace Hosting
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+
+"""Config options for Magnum Backend service."""
+
+
+from oslo.config import cfg
+
+SERVICE_OPTS = [
+    cfg.StrOpt('topic',
+               default='magnum-backend',
+               help='The queue to add backend tasks to'),
+    cfg.StrOpt('host',
+               default='localhost',
+               help='The location of the backend rpc queue'),
+]
+
+opt_group = cfg.OptGroup(
+    name='backend',
+    title='Options for the magnum-backend service')
+cfg.CONF.register_group(opt_group)
+cfg.CONF.register_opts(SERVICE_OPTS, opt_group)
diff --git a/magnum/backend/handlers/__init__.py b/magnum/backend/handlers/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/magnum/backend/handlers/docker.py b/magnum/backend/handlers/docker.py
new file mode 100644
index 0000000000..4e1b97a377
--- /dev/null
+++ b/magnum/backend/handlers/docker.py
@@ -0,0 +1,105 @@
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+
+"""Magnum Docker RPC handler."""
+
+from magnum.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+# These are the backend operations.  They are executed by the backend
+# service.  API calls via AMQP (within the ReST API) trigger the handlers to
+# be called.
+
+class Handler(object):
+    def __init__(self):
+        super(Handler, self).__init__()
+
+    # Bay Operations
+
+    def bay_create(uuid, contents):
+        return None
+
+    def bay_list():
+        return None
+
+    def bay_delete(uuid):
+        return None
+
+    def bay_show(uuid):
+        return None
+
+    # Service Operations
+
+    def service_create(uuid, contents):
+        return None
+
+    def service_list():
+        return None
+
+    def service_delete():
+        return None
+
+    def service_show(uuid):
+        return None
+
+    # Pod Operations
+
+    def pod_create(uuid, contents):
+        return None
+
+    def pod_list():
+        return None
+
+    def pod_delete(uuid):
+        return None
+
+    def pod_show(uuid):
+        return None
+
+    # Container operations
+
+    def container_create(uuid, contents):
+        LOG.debug("container_create %s contents=%s" % (uuid, contents))
+
+    def container_list():
+        LOG.debug("container_list")
+        # return container list dict
+
+    def container_delete(uuid):
+        LOG.debug("cotainer_delete %s" % uuid)
+
+    def container_show(uuid):
+        LOG.debug("container_show %s" % uuid)
+        # return container information dict
+
+    def container_reboot(uuid):
+        LOG.debug("container_reboot %s" % uuid)
+
+    def container_stop(uuid):
+        LOG.debug("container_stop %s" % uuid)
+
+    def container_start(uuid):
+        LOG.debug("container_start %s" % uuid)
+
+    def container_pause(uuid):
+        LOG.debug("container_pause %s" % uuid)
+
+    def container_unpause(uuid):
+        LOG.debug("container_unpause %s" % uuid)
+
+    def container_logs(uuid):
+        LOG.debug("container_logs %s" % uuid)
+
+    def container_execute(uuid):
+        LOG.debug("container_execute %s" % uuid)
diff --git a/magnum/backend/handlers/k8s.py b/magnum/backend/handlers/k8s.py
new file mode 100644
index 0000000000..e3ee54d7bd
--- /dev/null
+++ b/magnum/backend/handlers/k8s.py
@@ -0,0 +1,111 @@
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+
+"""Magnum Kubernetes RPC handler."""
+
+from magnum.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+# These are the backend operations.  They are executed by the backend
+# service.  API calls via AMQP (within the ReST API) trigger the handlers to
+# be called.
+
+class Handler(object):
+    def __init__(self):
+        super(Handler, self).__init__()
+
+    # Bay Operations
+
+    def bay_create(uuid, contents):
+        return None
+
+    def bay_list():
+        return None
+
+    def bay_delete(uuid):
+        return None
+
+    def bay_show(uuid):
+        return None
+
+    # Service Operations
+
+    def service_create(uuid, contents):
+        LOG.debug("service_create %s contents %s" % (uuid, contents))
+        return None
+
+    def service_list():
+        LOG.debug("service_list")
+        return None
+
+    def service_delete(uuid):
+        LOG.debug("service_delete %s" % uuid)
+        return None
+
+    def service_show(uuid):
+        LOG.debug("service_show %s" % uuid)
+        return None
+
+    # Pod Operations
+
+    def pod_create(uuid, contents):
+        LOG.debug("pod_create %s contents %s" % (uuid, contents))
+        return None
+
+    def pod_list():
+        LOG.debug("pod_list")
+        return None
+
+    def pod_delete(uuid):
+        LOG.debug("pod_delete %s" % uuid)
+        return None
+
+    def pod_show(uuid):
+        LOG.debug("pod_show %s" % uuid)
+        return None
+
+    # Container operations
+
+    def container_create(uuid, contents):
+        return None
+
+    def container_list():
+        return None
+
+    def container_delete(uuid):
+        return None
+
+    def container_show(uuid):
+        return None
+
+    def container_reboot(uuid):
+        return None
+
+    def container_stop(uuid):
+        return None
+
+    def container_start(uuid):
+        return None
+
+    def container_pause(uuid):
+        return None
+
+    def container_unpause(uuid):
+        return None
+
+    def container_logs(uuid):
+        return None
+
+    def container_execute(uuid):
+        return None
diff --git a/magnum/cmd/backend.py b/magnum/cmd/backend.py
new file mode 100644
index 0000000000..18c29d14c2
--- /dev/null
+++ b/magnum/cmd/backend.py
@@ -0,0 +1,48 @@
+# Copyright 2014 - Rackspace Hosting
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+
+"""Starter script for the Magnum Magnum service."""
+
+import logging as std_logging
+import os
+import sys
+
+from oslo.config import cfg
+
+from magnum.backend.handlers import docker as docker_backend
+from magnum.backend.handlers import k8s as k8s_backend
+from magnum.common.rpc import service
+from magnum.openstack.common._i18n import _
+from magnum.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+def main():
+    cfg.CONF(sys.argv[1:], project='magnum')
+    logging.setup('magnum')
+
+    LOG.info(_('Starting server in PID %s') % os.getpid())
+    LOG.debug("Configuration:")
+    cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
+
+    cfg.CONF.import_opt('topic', 'magnum.backend.config', group='backend')
+    cfg.CONF.import_opt('host', 'magnum.backend.config', group='backend')
+    endpoints = [
+        docker_backend.Handler(),
+        k8s_backend.Handler()
+    ]
+    server = service.Service(cfg.CONF.backend.topic,
+                             cfg.CONF.backend.host, endpoints)
+    server.serve()
diff --git a/setup.cfg b/setup.cfg
index 5f7873276d..1e462c44ed 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -47,6 +47,7 @@ output_file = magnum/locale/magnum.pot
 console_scripts =
     magnum-api = magnum.cmd.api:main
     magnum-conductor = magnum.cmd.conductor:main
+    magnum-backend = magnum.cmd.backend:main
 
 [wheel]
 universal = 1