summaryrefslogtreecommitdiffstats
path: root/moon-abe/swift_mock
diff options
context:
space:
mode:
Diffstat (limited to 'moon-abe/swift_mock')
-rw-r--r--moon-abe/swift_mock/README.rst11
-rw-r--r--moon-abe/swift_mock/swift_mock.py253
2 files changed, 264 insertions, 0 deletions
diff --git a/moon-abe/swift_mock/README.rst b/moon-abe/swift_mock/README.rst
new file mode 100644
index 00000000..f3e22d0b
--- /dev/null
+++ b/moon-abe/swift_mock/README.rst
@@ -0,0 +1,11 @@
+install cherrypy
+----------------
+
+sudo pip3 install cherrypy
+
+
+launch application
+------------------
+
+python3 swift_mock.py
+
diff --git a/moon-abe/swift_mock/swift_mock.py b/moon-abe/swift_mock/swift_mock.py
new file mode 100644
index 00000000..25914d68
--- /dev/null
+++ b/moon-abe/swift_mock/swift_mock.py
@@ -0,0 +1,253 @@
+#!/usr/bin/env python3
+"""<h1>Swift mock</h1>
+
+<pre>
+
+author: Thomas Duval
+
+mail: thomas.duval@orange.com
+
+version: 0.1
+
+API:
+
+- GET /info List activated capabilities
+
+- GET /v1/{account} Show account details and list containers
+- POST /v1/{account} Create, update, or delete account metadata
+- HEAD /v1/{account} Show account metadata
+
+- GET /v1/{account}/{container} Show container details and list objects
+- PUT /v1/{account}/{container} Create container
+- DELETE /v1/{account}/{container} Delete container
+- POST /v1/{account}/{container} Create, update, or delete container metadata
+- HEAD /v1/{account}/{container} Show container metadata
+
+- GET /v1/{account}/{container}/{object} Get object content and metadata
+- PUT /v1/{account}/{container}/{object} Create or replace object
+- COPY /v1/{account}/{container}/{object} Copy object
+- DELETE /v1/{account}/{container}/{object} Delete object
+- COPY /v1/{account}/{container}/{object} Copy object
+- HEAD /v1/{account}/{container}/{object} Show object metadata
+- POST /v1/{account}/{container}/{object} Create or update object metadata
+</pre>
+
+<p>
+Locally, the datastore is based on directories in /tmp/swift_dir,
+those directories are built with the following structure:
+{data_dir}/{account}/{container}/{object}.
+</p>
+
+<p>
+For more information on SWIFT API:
+<a href="http://developer.openstack.org/api-ref-objectstorage-v1.html">api-ref-objectstorage-v1.html</a>
+</p>
+"""
+import cherrypy
+import json
+import os
+import glob
+import shutil
+import time
+import hashlib
+
+
+TEMPLATE_HTML = """
+<html>
+<head><title>{title}</title></head>
+<body>
+{body}
+</body>
+</html>
+"""
+
+
+@cherrypy.popargs('account', 'container', 'object')
+class Swift(object):
+
+ def __init__(self):
+ if os.path.isdir('/tmp'):
+ self.data_dir = "/tmp/swift_data"
+ else:
+ self.data_dir = "data"
+ cherrypy.log("Data dir set to {}".format(self.data_dir))
+ try:
+ os.mkdir(self.data_dir)
+ except FileExistsError:
+ cherrypy.log("Data dir already exist")
+
+ def __get_json(self):
+ cl = cherrypy.request.headers['Content-Length']
+ rawbody = cherrypy.request.body.read(int(cl))
+ return json.loads(rawbody.decode("utf-8"))
+
+ def __get_rawdata(self):
+ cl = cherrypy.request.headers['Content-Length']
+ rawbody = cherrypy.request.body.read(int(cl))
+ return rawbody
+
+ @cherrypy.expose
+ def index(self, account="", container="", object=""):
+ return __doc__
+
+ @cherrypy.expose
+ def info(self, account="", container="", object=""):
+ info_dict = {
+ "swift": {
+ "version": "1.11.0"
+ },
+ "staticweb": {},
+ "tempurl": {}
+ }
+ return json.dumps(info_dict)
+
+ @cherrypy.expose
+ def v1(self, account="", container="", object=""):
+ print("v1", account, container, object)
+ if account and not container and not object:
+ if cherrypy.request.method == "GET":
+ return self.show_account(account)
+ elif cherrypy.request.method == "POST":
+ return self.create_account(account)
+ elif cherrypy.request.method == "HEAD":
+ return self.show_account_metadata(account)
+
+ elif account and container and not object:
+ if cherrypy.request.method == "GET":
+ return self.show_container(account, container)
+ elif cherrypy.request.method == "PUT":
+ return self.create_container(account, container)
+ elif cherrypy.request.method == "DELETE":
+ return self.delete_container(account, container)
+ elif cherrypy.request.method == "POST":
+ return self.modify_container(account, container)
+ elif cherrypy.request.method == "HEAD":
+ return self.show_container_metadata(account, container)
+
+ elif account and container and object:
+ if cherrypy.request.method == "GET":
+ return self.show_object(account, container, object)
+ elif cherrypy.request.method == "PUT":
+ return self.create_object(account, container, object)
+ elif cherrypy.request.method == "DELETE":
+ return self.delete_object(account, container, object)
+ elif cherrypy.request.method == "COPY":
+ return self.copy_object(account, container, object)
+ elif cherrypy.request.method == "POST":
+ return self.modify_object(account, container, object)
+ elif cherrypy.request.method == "HEAD":
+ return self.show_object_metadata(account, container, object)
+
+ raise cherrypy.HTTPError(500, "Request not supported ({} - {})".format(
+ cherrypy.request.method, cherrypy.request.query_string))
+
+ def show_account(self, account):
+ list_dir = glob.glob(os.path.join(self.data_dir, account, "*"))
+ data_list = list()
+ for _container in list_dir:
+ _objects = glob.glob(os.path.join(self.data_dir, account, _container, "*"))
+ data_list.append({
+ "count": len(_objects),
+ "bytes": 0,
+ "name": os.path.basename(_container)
+ })
+ return json.dumps(data_list)
+
+ def create_account(self, account):
+ if not os.path.isdir(os.path.join(self.data_dir, account)):
+ os.mkdir(os.path.join(self.data_dir, account))
+ cherrypy.response.status = 204
+ return "OK"
+ raise cherrypy.HTTPError(500, "Account already created")
+
+ def show_account_metadata(self, account):
+ if not os.path.isdir(os.path.join(self.data_dir, account)):
+ raise cherrypy.HTTPError(404)
+ # TODO: header
+ raise cherrypy.HTTPError(500, "Not implemented")
+
+ def show_container(self, account, container):
+ list_dir = glob.glob(os.path.join(self.data_dir, account, container, "*"))
+ data_list = list()
+ for _object in list_dir:
+ data_list.append({
+ "hash": hashlib.sha256(str.encode(_object)).hexdigest(),
+ "last_modified": time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(os.path.getmtime(_object))),
+ "bytes": os.stat(_object).st_size,
+ "name": os.path.basename(_object),
+ "content_type": "application/octet-stream"
+ })
+ return json.dumps(data_list)
+
+ def create_container(self, account, container):
+ if not os.path.isdir(os.path.join(self.data_dir, account, container)):
+ os.mkdir(os.path.join(self.data_dir, account, container))
+ cherrypy.response.status = 204
+ return
+ raise cherrypy.HTTPError(500, "Container already created")
+
+ def delete_container(self, account, container):
+ if not os.path.isdir(os.path.join(self.data_dir, account, container)):
+ raise cherrypy.HTTPError(404, "Container not found")
+ try:
+ os.rmdir(os.path.join(self.data_dir, account, container))
+ except OSError:
+ raise cherrypy.HTTPError(409, "Conflict")
+ cherrypy.response.status = 204
+ return "OK"
+ # shutil.rmtree((os.path.join(self.data_dir, account)))
+
+ def modify_container(self, account, container):
+ # TODO: modifications in header
+ return "modify_container {} {}".format(account, container)
+
+ def show_container_metadata(self, account, container):
+ if os.path.isdir(os.path.join(self.data_dir, account, container)):
+ # TODO: modifications in header
+ return "OK"
+ raise cherrypy.HTTPError(404, "Container not found")
+
+ def show_object(self, account, container, object):
+ if os.path.isfile(os.path.join(self.data_dir, account, container, object)):
+ # TODO: put metadata in headers
+ return open(os.path.join(self.data_dir, account, container, object), "rb").read()
+ raise cherrypy.HTTPError(404, "Object not found")
+
+ def create_object(self, account, container, object):
+ if not os.path.isdir(os.path.join(self.data_dir, account)):
+ raise cherrypy.HTTPError(404, "Account not found")
+ if not os.path.isdir(os.path.join(self.data_dir, account, container)):
+ raise cherrypy.HTTPError(404, "Container not found")
+ open(os.path.join(self.data_dir, account, container, object), "wb").write(self.__get_rawdata())
+ cherrypy.response.status = 201
+ return
+
+ def delete_object(self, account, container, object):
+ if not os.path.isfile(os.path.join(self.data_dir, account, container, object)):
+ raise cherrypy.HTTPError(404, "Object not found")
+ os.remove(os.path.join(self.data_dir, account, container, object))
+ cherrypy.response.status = 204
+ return
+
+ def copy_object(self, account, container, object):
+ if not os.path.isfile(os.path.join(self.data_dir, account, container, object)):
+ raise cherrypy.HTTPError(404, "Object not found")
+ # TODO: need to implement headers
+ raise cherrypy.HTTPError(500, "Not implemented")
+
+ def modify_object(self, account, container, object):
+ # TODO headers
+ raise cherrypy.HTTPError(500, "Not implemented")
+
+ def show_object_metadata(self, account, container, object):
+ # TODO headers
+ raise cherrypy.HTTPError(500, "Not implemented")
+
+
+application = Swift()
+
+cherrypy.config.update({
+ 'server.socket_host': '127.0.0.1',
+ 'server.socket_port': 8080,
+ })
+cherrypy.quickstart(application)