Add extensions for flavor swap and rxtx_factor

The swap and flavor attributes of a flavor are not in the spec. This
moves the properties so they are generated by extensions. The output
will not be changed if all extensions are enabled (by default), but
we now have a way to document these extra attributes and disable them.

DocImpact

Change-Id: Iee1cb1b1ee4116a38b90db581c38468d3d92afaf
This commit is contained in:
Vishvananda Ishaya 2012-08-31 12:51:52 -07:00
parent 2a5da84eb6
commit 30d89919b5
21 changed files with 449 additions and 57 deletions

View File

@ -37,6 +37,8 @@
"compute_extension:extended_status": [],
"compute_extension:flavor_access": [],
"compute_extension:flavor_disabled": [],
"compute_extension:flavor_rxtx": [],
"compute_extension:flavor_swap": [],
"compute_extension:flavorextradata": [],
"compute_extension:flavorextraspecs": [],
"compute_extension:flavormanage": [["rule:admin_api"]],

View File

@ -0,0 +1,87 @@
# Copyright 2012 Nebula, Inc.
#
# 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.
"""The Flavor Rxtx API extension."""
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'flavor_rxtx')
class FlavorRxtxController(wsgi.Controller):
def _extend_flavors(self, req, flavors):
for flavor in flavors:
db_flavor = req.get_db_flavor(flavor['id'])
key = 'rxtx_factor'
flavor[key] = db_flavor['rxtx_factor'] or ""
def _show(self, req, resp_obj):
if not authorize(req.environ['nova.context']):
return
if 'flavor' in resp_obj.obj:
resp_obj.attach(xml=FlavorRxtxTemplate())
self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends
def show(self, req, resp_obj, id):
return self._show(req, resp_obj)
@wsgi.extends(action='create')
def create(self, req, resp_obj, body):
return self._show(req, resp_obj)
@wsgi.extends
def detail(self, req, resp_obj):
if not authorize(req.environ['nova.context']):
return
resp_obj.attach(xml=FlavorsRxtxTemplate())
self._extend_flavors(req, list(resp_obj.obj['flavors']))
class Flavor_rxtx(extensions.ExtensionDescriptor):
"""Support to show the rxtx status of a flavor"""
name = "FlavorRxtx"
alias = "os-flavor-rxtx"
namespace = ("http://docs.openstack.org/compute/ext/"
"flavor_rxtx/api/v1.1")
updated = "2012-08-29T00:00:00+00:00"
def get_controller_extensions(self):
controller = FlavorRxtxController()
extension = extensions.ControllerExtension(self, 'flavors', controller)
return [extension]
def make_flavor(elem):
# NOTE(vish): this was originally added without a namespace
elem.set('rxtx_factor', xmlutil.EmptyStringSelector('rxtx_factor'))
class FlavorRxtxTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavor', selector='flavor')
make_flavor(root)
return xmlutil.SlaveTemplate(root, 1)
class FlavorsRxtxTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavors')
elem = xmlutil.SubTemplateElement(root, 'flavor', selector='flavors')
make_flavor(elem)
return xmlutil.SlaveTemplate(root, 1)

View File

@ -0,0 +1,87 @@
# Copyright 2012 Nebula, Inc.
#
# 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.
"""The Flavor Swap API extension."""
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'flavor_swap')
class FlavorSwapController(wsgi.Controller):
def _extend_flavors(self, req, flavors):
for flavor in flavors:
db_flavor = req.get_db_flavor(flavor['id'])
key = 'swap'
flavor[key] = db_flavor['swap'] or ""
def _show(self, req, resp_obj):
if not authorize(req.environ['nova.context']):
return
if 'flavor' in resp_obj.obj:
resp_obj.attach(xml=FlavorSwapTemplate())
self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends
def show(self, req, resp_obj, id):
return self._show(req, resp_obj)
@wsgi.extends(action='create')
def create(self, req, resp_obj, body):
return self._show(req, resp_obj)
@wsgi.extends
def detail(self, req, resp_obj):
if not authorize(req.environ['nova.context']):
return
resp_obj.attach(xml=FlavorsSwapTemplate())
self._extend_flavors(req, list(resp_obj.obj['flavors']))
class Flavor_swap(extensions.ExtensionDescriptor):
"""Support to show the swap status of a flavor"""
name = "FlavorSwap"
alias = "os-flavor-swap"
namespace = ("http://docs.openstack.org/compute/ext/"
"flavor_swap/api/v1.1")
updated = "2012-08-29T00:00:00+00:00"
def get_controller_extensions(self):
controller = FlavorSwapController()
extension = extensions.ControllerExtension(self, 'flavors', controller)
return [extension]
def make_flavor(elem):
# NOTE(vish): this was originally added without a namespace
elem.set('swap', xmlutil.EmptyStringSelector('swap'))
class FlavorSwapTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavor', selector='flavor')
make_flavor(root)
return xmlutil.SlaveTemplate(root, 1)
class FlavorsSwapTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavors')
elem = xmlutil.SubTemplateElement(root, 'flavor', selector='flavors')
make_flavor(elem)
return xmlutil.SlaveTemplate(root, 1)

View File

@ -31,9 +31,7 @@ def make_flavor(elem, detailed=False):
if detailed:
elem.set('ram')
elem.set('disk')
for attr in ("vcpus", "swap", "rxtx_factor"):
elem.set(attr, xmlutil.EmptyStringSelector(attr))
elem.set('vcpus', xmlutil.EmptyStringSelector('vcpus'))
xmlutil.make_links(elem, 'links')

View File

@ -4,8 +4,6 @@
<attribute name="id"> <text/> </attribute>
<attribute name="ram"> <text/> </attribute>
<attribute name="disk"> <text/> </attribute>
<attribute name="rxtx_factor"> <text/> </attribute>
<attribute name="swap"> <text/> </attribute>
<attribute name="vcpus"> <text/> </attribute>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>

View File

@ -41,8 +41,6 @@ class ViewBuilder(common.ViewBuilder):
"ram": flavor["memory_mb"],
"disk": flavor["root_gb"],
"vcpus": flavor.get("vcpus") or "",
"swap": flavor.get("swap") or "",
"rxtx_factor": flavor.get("rxtx_factor") or "",
"links": self._get_links(request,
flavor["flavorid"],
self._collection_name),

View File

@ -1,5 +1,4 @@
# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
# Copyright 2012 Nebula, Inc.
#
# 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

View File

@ -0,0 +1,109 @@
# Copyright 2012 Nebula, Inc.
#
# 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.
from lxml import etree
import webob
from nova.compute import instance_types
from nova import flags
from nova.openstack.common import jsonutils
from nova import test
from nova.tests.api.openstack import fakes
FLAGS = flags.FLAGS
FAKE_FLAVORS = {
'flavor 1': {
"flavorid": '1',
"name": 'flavor 1',
"memory_mb": '256',
"root_gb": '10',
"rxtx_factor": '1.0',
},
'flavor 2': {
"flavorid": '2',
"name": 'flavor 2',
"memory_mb": '512',
"root_gb": '10',
"rxtx_factor": None,
},
}
def fake_instance_type_get_by_flavor_id(flavorid):
return FAKE_FLAVORS['flavor %s' % flavorid]
def fake_instance_type_get_all(*args, **kwargs):
return FAKE_FLAVORS
class FlavorRxtxTest(test.TestCase):
content_type = 'application/json'
prefix = ''
def setUp(self):
super(FlavorRxtxTest, self).setUp()
ext = ('nova.api.openstack.compute.contrib'
'.flavor_rxtx.Flavor_rxtx')
self.flags(osapi_compute_extension=[ext])
fakes.stub_out_nw_api(self.stubs)
self.stubs.Set(instance_types, "get_all_types",
fake_instance_type_get_all)
self.stubs.Set(instance_types,
"get_instance_type_by_flavor_id",
fake_instance_type_get_by_flavor_id)
def _make_request(self, url):
req = webob.Request.blank(url)
req.headers['Accept'] = self.content_type
res = req.get_response(fakes.wsgi_app())
return res
def _get_flavor(self, body):
return jsonutils.loads(body).get('flavor')
def _get_flavors(self, body):
return jsonutils.loads(body).get('flavors')
def assertFlavorRxtx(self, flavor, rxtx):
self.assertEqual(str(flavor.get('%srxtx_factor' % self.prefix)), rxtx)
def test_show(self):
url = '/v2/fake/flavors/1'
res = self._make_request(url)
self.assertEqual(res.status_int, 200)
self.assertFlavorRxtx(self._get_flavor(res.body), '1.0')
def test_detail(self):
url = '/v2/fake/flavors/detail'
res = self._make_request(url)
self.assertEqual(res.status_int, 200)
flavors = self._get_flavors(res.body)
self.assertFlavorRxtx(flavors[0], '1.0')
self.assertFlavorRxtx(flavors[1], '')
class FlavorRxtxXmlTest(FlavorRxtxTest):
content_type = 'application/xml'
def _get_flavor(self, body):
return etree.XML(body)
def _get_flavors(self, body):
return etree.XML(body).getchildren()

View File

@ -0,0 +1,109 @@
# Copyright 2012 Nebula, Inc.
#
# 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.
from lxml import etree
import webob
from nova.compute import instance_types
from nova import flags
from nova.openstack.common import jsonutils
from nova import test
from nova.tests.api.openstack import fakes
FLAGS = flags.FLAGS
FAKE_FLAVORS = {
'flavor 1': {
"flavorid": '1',
"name": 'flavor 1',
"memory_mb": '256',
"root_gb": '10',
"swap": 512,
},
'flavor 2': {
"flavorid": '2',
"name": 'flavor 2',
"memory_mb": '512',
"root_gb": '10',
"swap": None,
},
}
def fake_instance_type_get_by_flavor_id(flavorid):
return FAKE_FLAVORS['flavor %s' % flavorid]
def fake_instance_type_get_all(*args, **kwargs):
return FAKE_FLAVORS
class FlavorSwapTest(test.TestCase):
content_type = 'application/json'
prefix = ''
def setUp(self):
super(FlavorSwapTest, self).setUp()
ext = ('nova.api.openstack.compute.contrib'
'.flavor_swap.Flavor_swap')
self.flags(osapi_compute_extension=[ext])
fakes.stub_out_nw_api(self.stubs)
self.stubs.Set(instance_types, "get_all_types",
fake_instance_type_get_all)
self.stubs.Set(instance_types,
"get_instance_type_by_flavor_id",
fake_instance_type_get_by_flavor_id)
def _make_request(self, url):
req = webob.Request.blank(url)
req.headers['Accept'] = self.content_type
res = req.get_response(fakes.wsgi_app())
return res
def _get_flavor(self, body):
return jsonutils.loads(body).get('flavor')
def _get_flavors(self, body):
return jsonutils.loads(body).get('flavors')
def assertFlavorSwap(self, flavor, swap):
self.assertEqual(str(flavor.get('%sswap' % self.prefix)), swap)
def test_show(self):
url = '/v2/fake/flavors/1'
res = self._make_request(url)
self.assertEqual(res.status_int, 200)
self.assertFlavorSwap(self._get_flavor(res.body), '512')
def test_detail(self):
url = '/v2/fake/flavors/detail'
res = self._make_request(url)
self.assertEqual(res.status_int, 200)
flavors = self._get_flavors(res.body)
self.assertFlavorSwap(flavors[0], '512')
self.assertFlavorSwap(flavors[1], '')
class FlavorSwapXmlTest(FlavorSwapTest):
content_type = 'application/xml'
def _get_flavor(self, body):
return etree.XML(body)
def _get_flavors(self, body):
return etree.XML(body).getchildren()

View File

@ -35,8 +35,6 @@ def fake_get_instance_type_by_flavor_id(flavorid):
'updated_at': None,
'memory_mb': 512,
'vcpus': 1,
'swap': 512,
'rxtx_factor': 1.0,
'extra_specs': {},
'deleted_at': None,
'vcpu_weight': None,
@ -73,8 +71,6 @@ class FlavorextradataTest(test.TestCase):
'vcpus': 1,
'disk': 1,
'OS-FLV-EXT-DATA:ephemeral': 1,
'swap': 512,
'rxtx_factor': 1,
}
}
@ -94,8 +90,6 @@ class FlavorextradataTest(test.TestCase):
'vcpus': 1,
'disk': 1,
'OS-FLV-EXT-DATA:ephemeral': 1,
'swap': 512,
'rxtx_factor': 1,
},
{
'id': '2',
@ -104,8 +98,6 @@ class FlavorextradataTest(test.TestCase):
'vcpus': 1,
'disk': 1,
'OS-FLV-EXT-DATA:ephemeral': 1,
'swap': 512,
'rxtx_factor': 1,
},
]

View File

@ -171,6 +171,8 @@ class ExtensionControllerTest(ExtensionTestCase):
"FlavorExtraSpecs",
"FlavorExtraData",
"FlavorManage",
"FlavorRxtx",
"FlavorSwap",
"FloatingIps",
"FloatingIpDns",
"FloatingIpPools",

View File

@ -44,14 +44,12 @@ FAKE_FLAVORS = {
"name": 'flavor 1',
"memory_mb": '256',
"root_gb": '10',
"disabled": False,
},
'flavor 2': {
"flavorid": '2',
"name": 'flavor 2',
"memory_mb": '512',
"root_gb": '20',
"disabled": False,
},
}
@ -89,6 +87,7 @@ def return_instance_type_not_found(flavor_id):
class FlavorsTest(test.TestCase):
def setUp(self):
super(FlavorsTest, self).setUp()
self.flags(osapi_compute_extension=[])
fakes.stub_out_networking(self.stubs)
fakes.stub_out_rate_limiting(self.stubs)
self.stubs.Set(nova.compute.instance_types, "get_all_types",
@ -116,8 +115,6 @@ class FlavorsTest(test.TestCase):
"name": "flavor 1",
"ram": "256",
"disk": "10",
"rxtx_factor": "",
"swap": "",
"vcpus": "",
"links": [
{
@ -144,8 +141,6 @@ class FlavorsTest(test.TestCase):
"name": "flavor 1",
"ram": "256",
"disk": "10",
"rxtx_factor": "",
"swap": "",
"vcpus": "",
"links": [
{
@ -314,8 +309,6 @@ class FlavorsTest(test.TestCase):
"name": "flavor 1",
"ram": "256",
"disk": "10",
"rxtx_factor": "",
"swap": "",
"vcpus": "",
"links": [
{
@ -333,8 +326,6 @@ class FlavorsTest(test.TestCase):
"name": "flavor 2",
"ram": "512",
"disk": "20",
"rxtx_factor": "",
"swap": "",
"vcpus": "",
"links": [
{
@ -434,8 +425,6 @@ class FlavorsTest(test.TestCase):
"name": "flavor 2",
"ram": "512",
"disk": "20",
"rxtx_factor": "",
"swap": "",
"vcpus": "",
"links": [
{
@ -464,8 +453,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
"name": "asdf",
"ram": "256",
"disk": "10",
"rxtx_factor": "1",
"swap": "",
"vcpus": "",
"links": [
{
@ -481,7 +468,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
}
output = serializer.serialize(fixture)
print output
has_dec = output.startswith("<?xml version='1.0' encoding='UTF-8'?>")
self.assertTrue(has_dec)
@ -494,8 +480,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
"name": "asdf",
"ram": "256",
"disk": "10",
"rxtx_factor": "1",
"swap": "",
"vcpus": "",
"links": [
{
@ -511,7 +495,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
}
output = serializer.serialize(fixture)
print output
root = etree.XML(output)
xmlutil.validate_schema(root, 'flavor')
flavor_dict = fixture['flavor']
@ -534,8 +517,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
"name": "asdf",
"ram": 256,
"disk": 10,
"rxtx_factor": "1",
"swap": "",
"vcpus": "",
"links": [
{
@ -551,7 +532,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
}
output = serializer.serialize(fixture)
print output
root = etree.XML(output)
xmlutil.validate_schema(root, 'flavor')
flavor_dict = fixture['flavor']
@ -575,8 +555,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
"name": "flavor 23",
"ram": "512",
"disk": "20",
"rxtx_factor": "1",
"swap": "",
"vcpus": "",
"links": [
{
@ -594,8 +572,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
"name": "flavor 13",
"ram": "256",
"disk": "10",
"rxtx_factor": "1",
"swap": "",
"vcpus": "",
"links": [
{
@ -612,7 +588,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
}
output = serializer.serialize(fixture)
print output
root = etree.XML(output)
xmlutil.validate_schema(root, 'flavors')
flavor_elems = root.findall('{0}flavor'.format(NS))
@ -639,8 +614,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
"name": "flavor 23",
"ram": "512",
"disk": "20",
"rxtx_factor": "1",
"swap": "",
"vcpus": "",
"links": [
{
@ -658,8 +631,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
"name": "flavor 13",
"ram": "256",
"disk": "10",
"rxtx_factor": "1",
"swap": "",
"vcpus": "",
"links": [
{
@ -676,7 +647,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
}
output = serializer.serialize(fixture)
print output
root = etree.XML(output)
xmlutil.validate_schema(root, 'flavors_index')
flavor_elems = root.findall('{0}flavor'.format(NS))
@ -701,7 +671,6 @@ class FlavorsXMLSerializationTest(test.TestCase):
}
output = serializer.serialize(fixture)
print output
root = etree.XML(output)
xmlutil.validate_schema(root, 'flavors_index')
flavor_elems = root.findall('{0}flavor'.format(NS))

View File

@ -152,6 +152,22 @@
"namespace": "http://docs.openstack.org/compute/ext/flavor_manage/api/v1.1",
"updated": "2012-01-19T00:00:00+00:00"
},
{
"alias": "os-flavor-rxtx",
"description": "Support to show the rxtx status of a flavor",
"links": [],
"name": "FlavorRxtx",
"namespace": "http://docs.openstack.org/compute/ext/flavor_rxtx/api/v1.1",
"updated": "2012-08-29T00:00:00+00:00"
},
{
"alias": "os-flavor-swap",
"description": "Support to show the swap status of a flavor",
"links": [],
"name": "FlavorSwap",
"namespace": "http://docs.openstack.org/compute/ext/flavor_swap/api/v1.1",
"updated": "2012-08-29T00:00:00+00:00"
},
{
"alias": "os-floating-ip-dns",
"description": "Floating IP DNS support",

View File

@ -152,6 +152,22 @@
"namespace": "http://docs.openstack.org/compute/ext/flavor_manage/api/v1.1",
"updated": "%(timestamp)s"
},
{
"alias": "os-flavor-rxtx",
"description": "%(text)s",
"links": [],
"name": "FlavorRxtx",
"namespace": "http://docs.openstack.org/compute/ext/flavor_rxtx/api/v1.1",
"updated": "%(timestamp)s"
},
{
"alias": "os-flavor-swap",
"description": "%(text)s",
"links": [],
"name": "FlavorSwap",
"namespace": "http://docs.openstack.org/compute/ext/flavor_swap/api/v1.1",
"updated": "%(timestamp)s"
},
{
"alias": "os-floating-ip-dns",
"description": "%(text)s",

View File

@ -71,6 +71,12 @@
Flavor create/delete API support
</description>
</extension>
<extension alias="os-flavor-rxtx" updated="2012-08-29T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/flavor_rxtx/api/v1.1" name="FlavorRxtx">
<description>Support to show the rxtx status of a flavor</description>
</extension>
<extension alias="os-flavor-swap" updated="2012-08-29T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/flavor_swap/api/v1.1" name="FlavorSwap">
<description>Support to show the swap status of a flavor</description>
</extension>
<extension alias="os-floating-ip-dns" updated="2011-12-23T00:00:00+00:00" namespace="http://docs.openstack.org/ext/floating_ip_dns/api/v1.1" name="FloatingIpDns">
<description>Floating IP DNS support</description>
</extension>

View File

@ -57,6 +57,12 @@
<extension alias="os-flavor-manage" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/flavor_manage/api/v1.1" name="FlavorManage">
<description>%(text)s</description>
</extension>
<extension alias="os-flavor-rxtx" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/flavor_rxtx/api/v1.1" name="FlavorRxtx">
<description>%(text)s</description>
</extension>
<extension alias="os-flavor-swap" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/flavor_swap/api/v1.1" name="FlavorSwap">
<description>%(text)s</description>
</extension>
<extension alias="os-floating-ip-dns" updated="%(timestamp)s" namespace="http://docs.openstack.org/ext/floating_ip_dns/api/v1.1" name="FloatingIpDns">
<description>%(text)s</description>
</extension>

View File

@ -14,8 +14,6 @@
],
"name": "m1.tiny",
"ram": 512,
"rxtx_factor": 1.0,
"swap": "",
"vcpus": 1
}
}

View File

@ -14,8 +14,6 @@
],
"name": "m1.tiny",
"ram": 512,
"rxtx_factor": 1.0,
"swap": "",
"vcpus": 1
}
}
}

View File

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<flavor xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" name="m1.tiny" ram="512" vcpus="1" swap="" rxtx_factor="1.0" disk="0" id="1">
<flavor xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" disk="0" vcpus="1" ram="512" name="m1.tiny" id="1">
<atom:link href="http://openstack.example.com/v2/openstack/flavors/1" rel="self"/>
<atom:link href="http://openstack.example.com/openstack/flavors/1" rel="bookmark"/>
</flavor>

View File

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<flavor xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" name="m1.tiny" ram="512" vcpus="1" swap="" rxtx_factor="1.0" disk="0" id="1">
<flavor xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" name="m1.tiny" ram="512" vcpus="1" disk="0" id="1">
<atom:link href="http://openstack.example.com/v2/openstack/flavors/1" rel="self"/>
<atom:link href="http://openstack.example.com/openstack/flavors/1" rel="bookmark"/>
</flavor>
</flavor>

View File

@ -94,6 +94,8 @@
"compute_extension:extended_status": [],
"compute_extension:flavor_access": [],
"compute_extension:flavor_disabled": [],
"compute_extension:flavor_rxtx": [],
"compute_extension:flavor_swap": [],
"compute_extension:flavorextradata": [],
"compute_extension:flavorextraspecs": [],
"compute_extension:flavormanage": [],