Add VM resize support

Updates in compute with correct mixin will produce a VM resize. The
resize will not be confirmed automatically unless the
resize_confirm_window is configured in nova.

Change-Id: I8b868a8a4fb403e337d3fe6c08b7d3f65736e545
This commit is contained in:
Enol Fernandez 2017-02-13 14:41:51 +00:00 committed by Alvaro Lopez Garcia
parent 65bd940498
commit 8f669d9225
5 changed files with 120 additions and 1 deletions

View File

@ -246,6 +246,28 @@ class Controller(ooi.api.base.Controller):
return collection.Collection(resources=occi_compute_resources)
def update(self, req, id, body):
# get info from server
self.os_helper.get_server(req, id)
parser = req.get_parser()(req.headers, req.body)
scheme = {
"mixins": [
templates.OpenStackResourceTemplate,
],
}
obj = parser.parse()
validator = occi_validator.Validator(obj)
validator.validate(scheme)
# Changes to the flavor (resize)
flavor = obj["schemes"][templates.OpenStackResourceTemplate.scheme][0]
action_args = {"flavorRef": flavor}
self.os_helper.run_action(req, "resize", id, action_args)
# re-use the show function
return self.show(req, id)
def show(self, req, id):
# get info from server
s = self.os_helper.get_server(req, id)

View File

@ -306,7 +306,8 @@ class OpenStackHelper(BaseHelper):
"resume": {"resume": None},
"unpause": {"unpause": None},
"restart": {"reboot": {"type": "SOFT"}},
"save": {"createImage": None}
"save": {"createImage": None},
"resize": {"resize": None},
}
os_action, default_args = actions_map[action].popitem()

View File

@ -711,6 +711,26 @@ class FakeApp(object):
"status": "on-line"}}
return create_fake_json_resp(s)
def _do_resize_server(self, req):
body = req.json_body.copy()
new_flavor = body.popitem()[1]["flavorRef"]
r = self._get_from_routes(req)
# Make sure subsequent calls to the server are up to date
# Some request path knowledge used which should be in this form:
# /v2.1/tenant_id/servers/server_id/action
p = req.path.split("/")
tenant_id = p[2]
server_id = p[4]
for s in servers[tenant_id]:
if s["id"] == server_id:
# do a conversion to avoid current id schemas
s["flavor"]["id"] = int(new_flavor)
break
# And repopulate the objects so they are properly returned
self._populate("/%s" % tenant_id, "server", servers[tenant_id],
actions=True)
return r
def _do_create_attachment(self, req):
v = {"volumeAttachment": {"serverId": "foo",
"volumeId": "bar",
@ -764,6 +784,8 @@ class FakeApp(object):
"removeSecurityGroup",
"addSecurityGroup"]:
return self._get_from_routes(req)
if action[0] == "resize":
return self._do_resize_server(req)
elif req.path_info.endswith("os-volume_attachments"):
return self._do_create_attachment(req)
elif req.path_info.endswith("os-floating-ips"):

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import uuid
from ooi.tests import fakes
@ -239,6 +240,52 @@ class TestComputeController(test_middleware.TestMiddleware):
self.assertDefaults(resp)
self.assertEqual(400, resp.status_code)
def test_modify_vm_flavor(self):
tenant = fakes.tenants["foo"]
app = self.get_app()
flavor_ids = [ids for ids in fakes.flavors]
for server in fakes.servers[tenant["id"]]:
old_flavor = server["flavor"]["id"]
# just pick a different one
new_flavor = flavor_ids[flavor_ids.index(old_flavor) - 1]
headers = {
'Category': (
'%s ;'
'scheme="http://schemas.openstack.org/template/resource#";'
'class="mixin"'
) % new_flavor
}
req = self._build_req("/compute/%s" % server["id"], tenant["id"],
method="PUT", headers=headers)
modified_server = copy.deepcopy(server)
modified_server["flavor"]["id"] = new_flavor
expected = build_occi_server(modified_server)
resp = req.get_response(app)
self.assertDefaults(resp)
self.assertExpectedResult(expected, resp)
self.assertEqual(200, resp.status_code)
def test_modify_vm_wrong_mixin(self):
tenant = fakes.tenants["foo"]
app = self.get_app()
for server in fakes.servers[tenant["id"]]:
headers = {
'Category': (
'foobar;'
'scheme="http://schemas.openstack.org/template/os#";'
'class="mixin"'
)
}
req = self._build_req("/compute/%s" % server["id"], tenant["id"],
method="PUT", headers=headers)
resp = req.get_response(app)
self.assertDefaults(resp)
self.assertEqual(400, resp.status_code)
def test_create_vm(self):
tenant = fakes.tenants["foo"]

View File

@ -787,3 +787,30 @@ class TestComputeController(base.TestController):
block_device_mapping=[],
networks=net)
m_net.assert_called_with(req, obj)
@mock.patch.object(compute.Controller, "show")
@mock.patch.object(helpers.OpenStackHelper, "run_action")
@mock.patch("ooi.occi.validator.Validator")
@mock.patch.object(helpers.OpenStackHelper, "get_server")
def test_update(self, m_server, m_validator, m_run_action, m_show):
tenant = fakes.tenants["foo"]
req = self._build_req(tenant["id"])
obj = {
"schemes": {
templates.OpenStackResourceTemplate.scheme: ["bar"],
},
}
# NOTE(aloga): the mocked call is
# "parser = req.get_parser()(req.headers, req.body)"
req.get_parser = mock.MagicMock()
req.get_parser.return_value.return_value.parse.return_value = obj
m_validator.validate.return_value = True
servers = fakes.servers[tenant["id"]]
for server in servers:
ret = self.controller.update(req, server["id"], None)
m_run_action.assert_called_with(mock.ANY, "resize", server["id"],
{'flavorRef': 'bar'})
m_server.assert_called_with(mock.ANY, server["id"])
m_show.assert_called_with(mock.ANY, server["id"])
self.assertEqual(m_show.return_value, ret)