Skip to content

Commit

Permalink
Merge pull request #20 from alvarolopez/storage
Browse files Browse the repository at this point in the history
Create and delete methods for storage.
  • Loading branch information
enolfc committed May 28, 2015
2 parents 28d2e95 + f93a412 commit 5f1805c
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 5 deletions.
73 changes: 72 additions & 1 deletion ooi/api/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
# License for the specific language governing permissions and limitations
# under the License.

import json

from ooi.api import base
from ooi import exception
from ooi.occi.core import collection
from ooi.occi.infrastructure import storage
from ooi.occi import validator as occi_validator
from ooi.openstack import helpers


Expand Down Expand Up @@ -47,4 +51,71 @@ def show(self, id, req):
size=v["size"], state=state)
return [st]

# TODO(enolfc): delete, create
def create(self, req, body):
tenant_id = req.environ["keystone.token_auth"].user.project_id
parser = req.get_parser()(req.headers, req.body)
scheme = {"category": storage.StorageResource.kind}
obj = parser.parse()
validator = occi_validator.Validator(obj)
validator.validate(scheme)

attrs = obj.get("attributes", {})
name = attrs.get("occi.core.title", "OCCI Volume")
# TODO(enolfc): this should be handled by the validator
try:
size = attrs["occi.storage.size"]
except KeyError:
raise exception.Invalid()

req_body = {"volume": {
"display_name": name,
"size": size,
}}
req = self._get_req(req, path="/%s/os-volumes" % tenant_id,
body=json.dumps(req_body), method="POST")
response = req.get_response(self.app)
volume = self.get_from_response(response, "volume", {})

st = storage.StorageResource(title=volume["displayName"],
id=volume["id"],
size=volume["size"],
state=helpers.vol_state(volume["status"]))
return collection.Collection(resources=[st])

def _get_storage_ids(self, req):
tenant_id = req.environ["keystone.token_auth"].user.project_id
req = self._get_req(req,
path="/%s/os-volumes" % tenant_id,
method="GET")
response = req.get_response(self.app)
return [v["id"] for v in self.get_from_response(response,
"volumes", [])]

def _delete(self, req, ids):
tenant_id = req.environ["keystone.token_auth"].user.project_id
for id in ids:
req = self._get_req(req,
path="/%s/os-volumes/%s" % (tenant_id, id),
method="DELETE")
response = req.get_response(self.app)
if response.status_int not in [204]:
raise base.exception_from_response(response)
return []

# TODO(enolfc): these two methods could be in the base.Controller
# they are identical to the ones of the Compute
def delete(self, req, id):
return self._delete(req, [id])

def delete_all(self, req):
return self._delete(req, self._get_storage_ids(req))

# TODO(enolfc): implement the actions.
def run_action(self, req, id, body):
action = req.GET.get("action", None)
actions = [a.term for a in storage.StorageResource.actions]

if action is None or action not in actions:
raise exception.InvalidAction(action=action)

raise exception.NotImplemented
21 changes: 17 additions & 4 deletions ooi/tests/fakes.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,15 @@ def _do_create_server(self, req):
"status": "ACTIVE"}}
return create_fake_json_resp(s)

def _do_create_volume(self, req):
# TODO(enolfc): this should check the json is
# semantically correct
s = {"volume": {"id": "foo",
"displayName": "foo",
"size": 1,
"status": "on-line"}}
return create_fake_json_resp(s)

def _do_create_attachment(self, req):
v = {"volumeAttachment": {"serverId": "foo",
"volumeId": "bar",
Expand All @@ -465,6 +474,8 @@ def _do_allocate_ip(self, req):
def _do_post(self, req):
if req.path_info.endswith("servers"):
return self._do_create_server(req)
if req.path_info.endswith("os-volumes"):
return self._do_create_volume(req)
elif req.path_info.endswith("action"):
body = req.json_body.copy()
action = body.popitem()
Expand All @@ -479,10 +490,12 @@ def _do_post(self, req):

def _do_delete(self, req):
self._do_get(req)
if "os-volume_attachments" in req.path_info:
return create_fake_json_resp({}, 202)
if "os-floating-ips" in req.path_info:
return create_fake_json_resp({}, 202)
tested_paths = {"os-volume_attachments": 202,
"os-floating-ips": 202,
"os-volumes": 204}
for p in tested_paths:
if p in req.path_info:
return create_fake_json_resp({}, tested_paths[p])
raise Exception

def _do_get(self, req):
Expand Down
63 changes: 63 additions & 0 deletions ooi/tests/middleware/test_storage_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,69 @@ def test_vol_not_found(self):
resp = req.get_response(app)
self.assertEqual(404, resp.status_code)

def test_create_vol_no_size(self):
tenant = fakes.tenants["foo"]

app = self.get_app()
headers = {
'Category': (
'storage;'
'scheme="http://schemas.ogf.org/occi/infrastructure#";'
'class="kind"')
}
req = self._build_req("/storage", tenant["id"], method="POST",
headers=headers)
resp = req.get_response(app)

self.assertEqual(400, resp.status_code)
self.assertDefaults(resp)

def test_create_vol(self):
tenant = fakes.tenants["foo"]

app = self.get_app()
headers = {
'Category': (
'storage;'
'scheme="http://schemas.ogf.org/occi/infrastructure#";'
'class="kind"'),
'X-OCCI-Attribute': (
'occi.storage.size=1'
)
}
req = self._build_req("/storage", tenant["id"], method="POST",
headers=headers)
resp = req.get_response(app)

expected = [("X-OCCI-Location",
utils.join_url(self.application_url + "/",
"storage/%s" % "foo"))]
self.assertEqual(200, resp.status_code)
self.assertExpectedResult(expected, resp)
self.assertDefaults(resp)

def test_delete_vol(self):
tenant = fakes.tenants["foo"]
app = self.get_app()

for volume in fakes.volumes[tenant["id"]]:
req = self._build_req("/storage/%s" % volume["id"],
tenant["id"], method="DELETE")
resp = req.get_response(app)
self.assertContentType(resp)
self.assertEqual(204, resp.status_code)

# TODO(enolfc): find a way to be sure that all volumes
# are in fact deleted.
def test_delete_all_vols(self):
tenant = fakes.tenants["foo"]
app = self.get_app()

req = self._build_req("/storage/", tenant["id"], method="DELETE")
resp = req.get_response(app)
self.assertContentType(resp)
self.assertEqual(204, resp.status_code)


class StorageControllerTextPlain(test_middleware.TestMiddlewareTextPlain,
TestStorageController):
Expand Down

0 comments on commit 5f1805c

Please sign in to comment.