Add preserve_ephemeral option to rebuild
The preserve_ephemeral option for rebuild will preserve the content of the ephemeral partition, making stateful golden image based deployments possible even when clouds haven't deployed Cinder, or the hypervisor doesn't support Cinder (e.g. BareMetal / Ironic). Partial-Bug: #1174154 blueprint: baremetal-preserve-ephemeral Co-Authored-By: Robert Collins <rbtcollins@hp.com> Change-Id: Id33d5d4107f89814842a3f0b7f33690dd7e3aadc
This commit is contained in:
parent
5c1cac0cde
commit
c557472496
@ -464,6 +464,14 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/networks_associate/api/v2",
|
||||
"updated": "2012-11-19T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-preserve-ephemeral-rebuild",
|
||||
"description": "Allow preservation of the ephemeral partition on rebuild.",
|
||||
"links": [],
|
||||
"name": "PreserveEphemeralOnRebuild",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/preserve_ephemeral_rebuild/api/v2",
|
||||
"updated": "2013-12-17T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-quota-class-sets",
|
||||
"description": "Quota classes management support.",
|
||||
|
@ -194,6 +194,9 @@
|
||||
<extension alias="os-networks-associate" updated="2012-11-19T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/networks_associate/api/v2" name="NetworkAssociationSupport">
|
||||
<description>Network association support.</description>
|
||||
</extension>
|
||||
<extension alias="os-preserve-ephemeral-rebuild" updated="2013-12-17T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/preserve_ephemeral_rebuild/api/v2" name="PreserveEphemeralOnRebuild">
|
||||
<description>Allow preservation of the ephemeral partition on rebuild.</description>
|
||||
</extension>
|
||||
<extension alias="os-quota-class-sets" updated="2012-03-12T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/quota-classes-sets/api/v1.1" name="QuotaClasses">
|
||||
<description>Quota classes management support.</description>
|
||||
</extension>
|
||||
|
@ -0,0 +1,55 @@
|
||||
{
|
||||
"server": {
|
||||
"accessIPv4": "1.2.3.4",
|
||||
"accessIPv6": "fe80::100",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "192.168.0.3",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"adminPass": "seekr3t",
|
||||
"created": "2013-12-30T12:28:14Z",
|
||||
"flavor": {
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/openstack/flavors/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
},
|
||||
"hostId": "ee8ea077f8548ce25c59c2d5020d0f82810c815c210fd68194a5c0f8",
|
||||
"id": "810e78d5-47fe-48bf-9559-bfe5dc918685",
|
||||
"image": {
|
||||
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/openstack/servers/810e78d5-47fe-48bf-9559-bfe5dc918685",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/openstack/servers/810e78d5-47fe-48bf-9559-bfe5dc918685",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"meta var": "meta val"
|
||||
},
|
||||
"name": "foobar",
|
||||
"progress": 0,
|
||||
"status": "ACTIVE",
|
||||
"tenant_id": "openstack",
|
||||
"updated": "2013-12-30T12:28:15Z",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="2013-12-30T12:28:05Z" hostId="29cf2103bf26495b084577ca87c0134abf5e2c46f284403a2637aebf" name="foobar" created="2013-12-30T12:28:04Z" userId="fake" tenantId="openstack" accessIPv4="1.2.3.4" accessIPv6="fe80::100" progress="0" id="26248125-6c64-4ef4-9d14-5f63ba1f8a60" adminPass="seekr3t">
|
||||
<image id="70a599e0-31e7-49b7-b260-868f441e862b">
|
||||
<atom:link href="http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b" rel="bookmark"/>
|
||||
</image>
|
||||
<flavor id="1">
|
||||
<atom:link href="http://openstack.example.com/openstack/flavors/1" rel="bookmark"/>
|
||||
</flavor>
|
||||
<metadata>
|
||||
<meta key="My Server Name">Apache1</meta>
|
||||
</metadata>
|
||||
<addresses>
|
||||
<network id="private">
|
||||
<ip version="4" addr="192.168.0.3"/>
|
||||
</network>
|
||||
</addresses>
|
||||
<atom:link href="http://openstack.example.com/v2/openstack/servers/26248125-6c64-4ef4-9d14-5f63ba1f8a60" rel="self"/>
|
||||
<atom:link href="http://openstack.example.com/openstack/servers/26248125-6c64-4ef4-9d14-5f63ba1f8a60" rel="bookmark"/>
|
||||
</server>
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"rebuild" : {
|
||||
"imageRef" : "http://openstack.example.com/v2/32278/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"name" : "new-server-test",
|
||||
"adminPass" : "seekr3t",
|
||||
"accessIPv4" : "1.2.3.4",
|
||||
"accessIPv6" : "fe80::100",
|
||||
"metadata" : {
|
||||
"meta var" : "meta val"
|
||||
},
|
||||
"personality" : [
|
||||
{
|
||||
"path" : "/etc/banner.txt",
|
||||
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
],
|
||||
"preserve_ephemeral": true
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rebuild
|
||||
xmlns="http://docs.openstack.org/compute/api/v1.1"
|
||||
name="foobar"
|
||||
imageRef="http://openstack.example.com/v1.1/32278/images/70a599e0-31e7-49b7-b260-868f441e862b"
|
||||
accessIPv4="1.2.3.4"
|
||||
accessIPv6="fe80::100"
|
||||
adminPass="seekr3t"
|
||||
preserve_ephemeral="false">
|
||||
<metadata>
|
||||
<meta key="My Server Name">Apache1</meta>
|
||||
</metadata>
|
||||
<personality>
|
||||
<file path="/etc/banner.txt">
|
||||
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||
</file>
|
||||
</personality>
|
||||
</rebuild>
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server" : {
|
||||
"name" : "new-server-test",
|
||||
"imageRef" : "http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"flavorRef" : "http://openstack.example.com/openstack/flavors/1",
|
||||
"metadata" : {
|
||||
"My Server Name" : "Apache1"
|
||||
},
|
||||
"personality" : [
|
||||
{
|
||||
"path" : "/etc/banner.txt",
|
||||
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b" flavorRef="http://openstack.example.com/openstack/flavors/1" name="new-server-test">
|
||||
<metadata>
|
||||
<meta key="My Server Name">Apache1</meta>
|
||||
</metadata>
|
||||
<personality>
|
||||
<file path="/etc/banner.txt">
|
||||
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||
</file>
|
||||
</personality>
|
||||
</server>
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server": {
|
||||
"adminPass": "8SV3AwzrE9Yn",
|
||||
"id": "5b39f651-2c68-48a1-ad26-dab135c4f543",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/openstack/servers/5b39f651-2c68-48a1-ad26-dab135c4f543",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/openstack/servers/5b39f651-2c68-48a1-ad26-dab135c4f543",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="26248125-6c64-4ef4-9d14-5f63ba1f8a60" adminPass="MAvcr8ZtqSHf">
|
||||
<metadata/>
|
||||
<atom:link href="http://openstack.example.com/v2/openstack/servers/26248125-6c64-4ef4-9d14-5f63ba1f8a60" rel="self"/>
|
||||
<atom:link href="http://openstack.example.com/openstack/servers/26248125-6c64-4ef4-9d14-5f63ba1f8a60" rel="bookmark"/>
|
||||
</server>
|
@ -0,0 +1,17 @@
|
||||
{
|
||||
"rebuild" : {
|
||||
"image_ref" : "http://glance.openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"name" : "foobar",
|
||||
"admin_password" : "seekr3t",
|
||||
"metadata" : {
|
||||
"meta_var" : "meta_val"
|
||||
},
|
||||
"personality" : [
|
||||
{
|
||||
"path" : "/etc/banner.txt",
|
||||
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
],
|
||||
"preserve_ephemeral": true
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rebuild
|
||||
xmlns="http://docs.openstack.org/compute/api/v1.1"
|
||||
name="foobar"
|
||||
image_ref="http://glance.openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b"
|
||||
admin_password="seekr3t"
|
||||
preserve_ephemeral="true">
|
||||
<metadata>
|
||||
<meta key="meta_var">meta_val</meta>
|
||||
</metadata>
|
||||
<personality>
|
||||
<file path="/etc/banner.txt">
|
||||
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||
</file>
|
||||
</personality>
|
||||
</rebuild>
|
@ -0,0 +1,23 @@
|
||||
# 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 nova.api.openstack import extensions
|
||||
|
||||
|
||||
class Preserve_ephemeral_rebuild(extensions.ExtensionDescriptor):
|
||||
"""Allow preservation of the ephemeral partition on rebuild."""
|
||||
|
||||
name = "PreserveEphemeralOnRebuild"
|
||||
alias = "os-preserve-ephemeral-rebuild"
|
||||
namespace = ("http://docs.openstack.org/compute/ext/"
|
||||
"preserve_ephemeral_rebuild/api/v2")
|
||||
updated = "2013-12-17T00:00:00+00:00"
|
@ -250,6 +250,10 @@ class ActionDeserializer(CommonDeserializer):
|
||||
if node.hasAttribute("admin_password"):
|
||||
rebuild["admin_password"] = node.getAttribute("admin_password")
|
||||
|
||||
if node.hasAttribute("preserve_ephemeral"):
|
||||
rebuild["preserve_ephemeral"] = strutils.bool_from_string(
|
||||
node.getAttribute("preserve_ephemeral"), strict=True)
|
||||
|
||||
if self.controller:
|
||||
self.controller.server_rebuild_xml_deserialize(node, rebuild)
|
||||
return rebuild
|
||||
@ -1110,10 +1114,15 @@ class ServersController(wsgi.Controller):
|
||||
'metadata': 'metadata',
|
||||
}
|
||||
|
||||
rebuild_kwargs = {}
|
||||
|
||||
if 'name' in rebuild_dict:
|
||||
self._validate_server_name(rebuild_dict['name'])
|
||||
|
||||
rebuild_kwargs = {}
|
||||
if 'preserve_ephemeral' in rebuild_dict:
|
||||
rebuild_kwargs['preserve_ephemeral'] = strutils.bool_from_string(
|
||||
rebuild_dict['preserve_ephemeral'], strict=True)
|
||||
|
||||
if list(self.rebuild_extension_manager):
|
||||
self.rebuild_extension_manager.map(self._rebuild_extension_point,
|
||||
rebuild_dict, rebuild_kwargs)
|
||||
|
@ -413,6 +413,10 @@ class ActionDeserializer(CommonDeserializer):
|
||||
if node.hasAttribute("accessIPv6"):
|
||||
rebuild["accessIPv6"] = node.getAttribute("accessIPv6")
|
||||
|
||||
if node.hasAttribute("preserve_ephemeral"):
|
||||
rebuild["preserve_ephemeral"] = strutils.bool_from_string(
|
||||
node.getAttribute("preserve_ephemeral"), strict=True)
|
||||
|
||||
return rebuild
|
||||
|
||||
def _action_resize(self, node):
|
||||
@ -1319,6 +1323,15 @@ class Controller(wsgi.Controller):
|
||||
'auto_disk_config': 'auto_disk_config',
|
||||
}
|
||||
|
||||
kwargs = {}
|
||||
|
||||
# take the preserve_ephemeral value into account only when the
|
||||
# corresponding extension is active
|
||||
if (self.ext_mgr.is_loaded('os-preserve-ephemeral-rebuild')
|
||||
and 'preserve_ephemeral' in body):
|
||||
kwargs['preserve_ephemeral'] = strutils.bool_from_string(
|
||||
body['preserve_ephemeral'], strict=True)
|
||||
|
||||
if 'accessIPv4' in body:
|
||||
self._validate_access_ipv4(body['accessIPv4'])
|
||||
|
||||
@ -1328,8 +1341,6 @@ class Controller(wsgi.Controller):
|
||||
if 'name' in body:
|
||||
self._validate_server_name(body['name'])
|
||||
|
||||
kwargs = {}
|
||||
|
||||
for request_attribute, instance_attribute in attr_map.items():
|
||||
try:
|
||||
kwargs[instance_attribute] = body[request_attribute]
|
||||
|
@ -577,7 +577,7 @@ class CellsAPI(rpcclient.RpcProxy):
|
||||
def rebuild_instance(self, ctxt, instance, new_pass, injected_files,
|
||||
image_ref, orig_image_ref, orig_sys_metadata, bdms,
|
||||
recreate=False, on_shared_storage=False, host=None,
|
||||
kwargs=None):
|
||||
preserve_ephemeral=False, kwargs=None):
|
||||
if not CONF.cells.enable:
|
||||
return
|
||||
|
||||
@ -585,4 +585,4 @@ class CellsAPI(rpcclient.RpcProxy):
|
||||
cctxt.cast(ctxt, 'rebuild_instance',
|
||||
instance=instance, image_href=image_ref,
|
||||
admin_password=new_pass, files_to_inject=injected_files,
|
||||
kwargs=kwargs)
|
||||
preserve_ephemeral=preserve_ephemeral, kwargs=kwargs)
|
||||
|
@ -2060,6 +2060,7 @@ class API(base.Base):
|
||||
orig_image_ref = instance.image_ref or ''
|
||||
files_to_inject = files_to_inject or []
|
||||
metadata = kwargs.get('metadata', {})
|
||||
preserve_ephemeral = kwargs.get('preserve_ephemeral', False)
|
||||
|
||||
image_id, image = self._get_image(context, image_href)
|
||||
self._check_auto_disk_config(image=image, **kwargs)
|
||||
@ -2122,7 +2123,7 @@ class API(base.Base):
|
||||
new_pass=admin_password, injected_files=files_to_inject,
|
||||
image_ref=image_href, orig_image_ref=orig_image_ref,
|
||||
orig_sys_metadata=orig_sys_metadata, bdms=bdms,
|
||||
kwargs=kwargs)
|
||||
preserve_ephemeral=preserve_ephemeral, kwargs=kwargs)
|
||||
|
||||
@wrap_check_policy
|
||||
@check_instance_lock
|
||||
|
@ -416,7 +416,7 @@ class ComputeVirtAPI(virtapi.VirtAPI):
|
||||
class ComputeManager(manager.Manager):
|
||||
"""Manages the running instances from creation to destruction."""
|
||||
|
||||
RPC_API_VERSION = '3.4'
|
||||
RPC_API_VERSION = '3.5'
|
||||
|
||||
def __init__(self, compute_driver=None, *args, **kwargs):
|
||||
"""Load configuration options and connect to the hypervisor."""
|
||||
@ -2132,7 +2132,13 @@ class ComputeManager(manager.Manager):
|
||||
injected_files, admin_password, bdms,
|
||||
detach_block_devices, attach_block_devices,
|
||||
network_info=None,
|
||||
recreate=False, block_device_info=None):
|
||||
recreate=False, block_device_info=None,
|
||||
preserve_ephemeral=False):
|
||||
if preserve_ephemeral:
|
||||
# The default code path does not support preserving ephemeral
|
||||
# partitions.
|
||||
raise exception.PreserveEphemeralNotSupported()
|
||||
|
||||
detach_block_devices(context, bdms)
|
||||
|
||||
if not recreate:
|
||||
@ -2152,6 +2158,7 @@ class ComputeManager(manager.Manager):
|
||||
admin_password, network_info=network_info,
|
||||
block_device_info=new_block_device_info)
|
||||
|
||||
@rpc_common.client_exceptions(exception.PreserveEphemeralNotSupported)
|
||||
@object_compat
|
||||
@wrap_exception()
|
||||
@reverts_task_state
|
||||
@ -2159,7 +2166,8 @@ class ComputeManager(manager.Manager):
|
||||
@wrap_instance_fault
|
||||
def rebuild_instance(self, context, instance, orig_image_ref, image_ref,
|
||||
injected_files, new_pass, orig_sys_metadata,
|
||||
bdms, recreate, on_shared_storage):
|
||||
bdms, recreate, on_shared_storage,
|
||||
preserve_ephemeral=False):
|
||||
"""Destroy and re-make this instance.
|
||||
|
||||
A 'rebuild' effectively purges all existing data from the system and
|
||||
@ -2177,6 +2185,8 @@ class ComputeManager(manager.Manager):
|
||||
hypervisor it was on failed) - cleanup of old state will be
|
||||
skipped.
|
||||
:param on_shared_storage: True if instance files on shared storage
|
||||
:param preserve_ephemeral: True if the default ephemeral storage
|
||||
partition must be preserved on rebuild
|
||||
"""
|
||||
context = context.elevated()
|
||||
|
||||
@ -2275,7 +2285,8 @@ class ComputeManager(manager.Manager):
|
||||
detach_block_devices=detach_block_devices,
|
||||
attach_block_devices=self._prep_block_device,
|
||||
block_device_info=block_device_info,
|
||||
network_info=network_info)
|
||||
network_info=network_info,
|
||||
preserve_ephemeral=preserve_ephemeral)
|
||||
try:
|
||||
self.driver.rebuild(**kwargs)
|
||||
except NotImplementedError:
|
||||
|
@ -216,6 +216,7 @@ class ComputeAPI(rpcclient.RpcProxy):
|
||||
3.2 - Update get_vnc_console() to take an instance object
|
||||
3.3 - Update validate_console_port() to take an instance object
|
||||
3.4 - Update rebuild_instance() to take an instance object
|
||||
3.5 - Pass preserve_ephemeral flag to rebuild_instance()
|
||||
'''
|
||||
|
||||
#
|
||||
@ -561,15 +562,20 @@ class ComputeAPI(rpcclient.RpcProxy):
|
||||
def rebuild_instance(self, ctxt, instance, new_pass, injected_files,
|
||||
image_ref, orig_image_ref, orig_sys_metadata, bdms,
|
||||
recreate=False, on_shared_storage=False, host=None,
|
||||
kwargs=None):
|
||||
preserve_ephemeral=False, kwargs=None):
|
||||
# NOTE(danms): kwargs is only here for cells compatibility, don't
|
||||
# actually send it to compute
|
||||
if self.can_send_version('3.4'):
|
||||
extra = {}
|
||||
if self.can_send_version('3.5'):
|
||||
version = '3.5'
|
||||
extra['preserve_ephemeral'] = preserve_ephemeral
|
||||
elif self.can_send_version('3.4'):
|
||||
version = '3.4'
|
||||
else:
|
||||
# NOTE(russellb) Havana compat
|
||||
version = self._get_compat_version('3.0', '2.22')
|
||||
instance = jsonutils.to_primitive(instance)
|
||||
|
||||
bdms_p = jsonutils.to_primitive(bdms)
|
||||
cctxt = self.client.prepare(server=_compute_host(host, instance),
|
||||
version=version)
|
||||
@ -578,7 +584,8 @@ class ComputeAPI(rpcclient.RpcProxy):
|
||||
injected_files=injected_files, image_ref=image_ref,
|
||||
orig_image_ref=orig_image_ref,
|
||||
orig_sys_metadata=orig_sys_metadata, bdms=bdms_p,
|
||||
recreate=recreate, on_shared_storage=on_shared_storage)
|
||||
recreate=recreate, on_shared_storage=on_shared_storage,
|
||||
**extra)
|
||||
|
||||
def refresh_provider_fw_rules(self, ctxt, host):
|
||||
# NOTE(russellb) Havana compat
|
||||
|
@ -535,6 +535,11 @@ class ImageNotFound(NotFound):
|
||||
msg_fmt = _("Image %(image_id)s could not be found.")
|
||||
|
||||
|
||||
class PreserveEphemeralNotSupported(Invalid):
|
||||
msg_fmt = _("The current driver does not support "
|
||||
"preserving ephemeral partitions.")
|
||||
|
||||
|
||||
# NOTE(jruzicka): ImageNotFound is not a valid EC2 error code.
|
||||
class ImageNotFoundEC2(ImageNotFound):
|
||||
msg_fmt = _("Image %(image_id)s could not be found. The nova EC2 API "
|
||||
|
@ -566,6 +566,43 @@ class ServerActionsControllerTest(test.TestCase):
|
||||
self.assertEqual(instance_meta['kernel_id'], '1')
|
||||
self.assertEqual(instance_meta['ramdisk_id'], '2')
|
||||
|
||||
def _test_rebuild_preserve_ephemeral(self, value=None):
|
||||
return_server = fakes.fake_instance_get(image_ref='2',
|
||||
vm_state=vm_states.ACTIVE,
|
||||
host='fake_host')
|
||||
self.stubs.Set(db, 'instance_get_by_uuid', return_server)
|
||||
|
||||
body = {
|
||||
"rebuild": {
|
||||
"image_ref": self._image_href,
|
||||
},
|
||||
}
|
||||
if value is not None:
|
||||
body['rebuild']['preserve_ephemeral'] = value
|
||||
|
||||
req = fakes.HTTPRequestV3.blank(self.url)
|
||||
context = req.environ['nova.context']
|
||||
|
||||
self.mox.StubOutWithMock(compute_api.API, 'rebuild')
|
||||
if value is not None:
|
||||
compute_api.API.rebuild(context, mox.IgnoreArg(), self._image_href,
|
||||
mox.IgnoreArg(), preserve_ephemeral=value)
|
||||
else:
|
||||
compute_api.API.rebuild(context, mox.IgnoreArg(), self._image_href,
|
||||
mox.IgnoreArg())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.controller._action_rebuild(req, FAKE_UUID, body)
|
||||
|
||||
def test_rebuild_preserve_ephemeral_true(self):
|
||||
self._test_rebuild_preserve_ephemeral(True)
|
||||
|
||||
def test_rebuild_preserve_ephemeral_false(self):
|
||||
self._test_rebuild_preserve_ephemeral(False)
|
||||
|
||||
def test_rebuild_preserve_ephemeral_default(self):
|
||||
self._test_rebuild_preserve_ephemeral()
|
||||
|
||||
def test_resize_server(self):
|
||||
|
||||
body = dict(resize=dict(flavor_ref="http://localhost/3"))
|
||||
|
@ -4430,6 +4430,24 @@ class TestServerRebuildXMLDeserializer(test.NoDBTestCase):
|
||||
}
|
||||
self.assertThat(request['body'], matchers.DictMatches(expected))
|
||||
|
||||
def test_rebuild_preserve_ephemeral_passed(self):
|
||||
serial_request = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rebuild
|
||||
xmlns="http://docs.openstack.org/compute/api/v1.1"
|
||||
name="new-server-test"
|
||||
image_ref="http://localhost/images/1"
|
||||
preserve_ephemeral="true">
|
||||
</rebuild>"""
|
||||
request = self.deserializer.deserialize(serial_request, 'action')
|
||||
expected = {
|
||||
"rebuild": {
|
||||
"name": "new-server-test",
|
||||
"image_ref": "http://localhost/images/1",
|
||||
"preserve_ephemeral": True,
|
||||
},
|
||||
}
|
||||
self.assertThat(request['body'], matchers.DictMatches(expected))
|
||||
|
||||
|
||||
class FakeExt(extensions.V3APIExtensionBase):
|
||||
name = "AccessIPs"
|
||||
|
@ -100,7 +100,11 @@ class ServerActionsControllerTest(test.TestCase):
|
||||
self.url = '/v2/fake/servers/%s/action' % self.uuid
|
||||
self._image_href = '155d900f-4e14-4e4c-a73d-069cbf4541e6'
|
||||
|
||||
self.controller = servers.Controller()
|
||||
class FakeExtManager(object):
|
||||
def is_loaded(self, ext):
|
||||
return False
|
||||
|
||||
self.controller = servers.Controller(ext_mgr=FakeExtManager())
|
||||
self.compute_api = self.controller.compute_api
|
||||
self.context = context.RequestContext('fake', 'fake')
|
||||
self.app = fakes.wsgi_app(init_only=('servers',),
|
||||
@ -320,6 +324,71 @@ class ServerActionsControllerTest(test.TestCase):
|
||||
self.controller._action_reboot,
|
||||
req, FAKE_UUID, body)
|
||||
|
||||
def test_rebuild_preserve_ephemeral_is_ignored_when_ext_not_loaded(self):
|
||||
return_server = fakes.fake_instance_get(image_ref='2',
|
||||
vm_state=vm_states.ACTIVE,
|
||||
host='fake_host')
|
||||
self.stubs.Set(db, 'instance_get_by_uuid', return_server)
|
||||
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageRef": self._image_href,
|
||||
"preserve_ephemeral": False,
|
||||
},
|
||||
}
|
||||
req = fakes.HTTPRequest.blank(self.url)
|
||||
context = req.environ['nova.context']
|
||||
|
||||
self.mox.StubOutWithMock(compute_api.API, 'rebuild')
|
||||
compute_api.API.rebuild(context, mox.IgnoreArg(), self._image_href,
|
||||
mox.IgnoreArg(), files_to_inject=None)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.controller._action_rebuild(req, FAKE_UUID, body)
|
||||
|
||||
def _test_rebuild_preserve_ephemeral(self, value=None):
|
||||
def fake_is_loaded(ext):
|
||||
return ext == 'os-preserve-ephemeral-rebuild'
|
||||
self.stubs.Set(self.controller.ext_mgr, 'is_loaded', fake_is_loaded)
|
||||
|
||||
return_server = fakes.fake_instance_get(image_ref='2',
|
||||
vm_state=vm_states.ACTIVE,
|
||||
host='fake_host')
|
||||
self.stubs.Set(db, 'instance_get_by_uuid', return_server)
|
||||
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageRef": self._image_href,
|
||||
},
|
||||
}
|
||||
if value is not None:
|
||||
body['rebuild']['preserve_ephemeral'] = value
|
||||
|
||||
req = fakes.HTTPRequest.blank(self.url)
|
||||
context = req.environ['nova.context']
|
||||
|
||||
self.mox.StubOutWithMock(compute_api.API, 'rebuild')
|
||||
|
||||
if value is not None:
|
||||
compute_api.API.rebuild(context, mox.IgnoreArg(), self._image_href,
|
||||
mox.IgnoreArg(), preserve_ephemeral=value,
|
||||
files_to_inject=None)
|
||||
else:
|
||||
compute_api.API.rebuild(context, mox.IgnoreArg(), self._image_href,
|
||||
mox.IgnoreArg(), files_to_inject=None)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.controller._action_rebuild(req, FAKE_UUID, body)
|
||||
|
||||
def test_rebuild_preserve_ephemeral_true(self):
|
||||
self._test_rebuild_preserve_ephemeral(True)
|
||||
|
||||
def test_rebuild_preserve_ephemeral_false(self):
|
||||
self._test_rebuild_preserve_ephemeral(False)
|
||||
|
||||
def test_rebuild_preserve_ephemeral_default(self):
|
||||
self._test_rebuild_preserve_ephemeral()
|
||||
|
||||
def test_rebuild_accepted_minimum(self):
|
||||
return_server = fakes.fake_instance_get(image_ref='2',
|
||||
vm_state=vm_states.ACTIVE, host='fake_host')
|
||||
@ -1361,6 +1430,21 @@ class TestServerActionXMLDeserializer(test.TestCase):
|
||||
serial_request,
|
||||
'action')
|
||||
|
||||
def test_rebuild_preserve_ephemeral_passed(self):
|
||||
serial_request = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rebuild
|
||||
xmlns="http://docs.openstack.org/compute/api/v1.1"
|
||||
imageRef="http://localhost/images/1"
|
||||
preserve_ephemeral="true"/>"""
|
||||
request = self.deserializer.deserialize(serial_request, 'action')
|
||||
expected = {
|
||||
"rebuild": {
|
||||
"imageRef": "http://localhost/images/1",
|
||||
"preserve_ephemeral": True,
|
||||
},
|
||||
}
|
||||
self.assertThat(request['body'], matchers.DictMatches(expected))
|
||||
|
||||
def test_corrupt_xml(self):
|
||||
"""Should throw a 400 error on corrupt xml."""
|
||||
self.assertRaises(
|
||||
|
@ -473,6 +473,7 @@ class ComputeRpcAPITestCase(test.TestCase):
|
||||
reboot_type='type', version='2.32')
|
||||
|
||||
def test_rebuild_instance(self):
|
||||
self.flags(compute='3.4', group='upgrade_levels')
|
||||
self._test_compute_api('rebuild_instance', 'cast', new_pass='None',
|
||||
injected_files='None', image_ref='None', orig_image_ref='None',
|
||||
bdms=[], instance=self.fake_instance, host='new_host',
|
||||
@ -487,6 +488,14 @@ class ComputeRpcAPITestCase(test.TestCase):
|
||||
orig_sys_metadata=None, recreate=True, on_shared_storage=True,
|
||||
version='2.22')
|
||||
|
||||
def test_rebuild_instance_preserve_ephemeral(self):
|
||||
self.flags(compute='3.5', group='upgrade_levels')
|
||||
self._test_compute_api('rebuild_instance', 'cast', new_pass='None',
|
||||
injected_files='None', image_ref='None', orig_image_ref='None',
|
||||
bdms=[], instance=self.fake_instance, host='new_host',
|
||||
orig_sys_metadata=None, recreate=True, on_shared_storage=True,
|
||||
preserve_ephemeral=True, version='3.5')
|
||||
|
||||
def test_reserve_block_device_name(self):
|
||||
self._test_compute_api('reserve_block_device_name', 'call',
|
||||
instance=self.fake_instance, device='device', volume_id='id')
|
||||
|
@ -615,6 +615,14 @@
|
||||
"name": "BareMetalExtStatus",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/baremetal_ext_status/api/v2",
|
||||
"updated": "%(timestamp)s"
|
||||
},
|
||||
{
|
||||
"alias": "os-preserve-ephemeral-rebuild",
|
||||
"description": "%(text)s",
|
||||
"links": [],
|
||||
"name": "PreserveEphemeralOnRebuild",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/preserve_ephemeral_rebuild/api/v2",
|
||||
"updated": "%(timestamp)s"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -230,4 +230,7 @@
|
||||
</extension>
|
||||
<extension alias="os-baremetal-ext-status" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/baremetal_ext_status/api/v2" name="BareMetalExtStatus"> <description>%(text)s</description>
|
||||
</extension>
|
||||
<extension alias="os-preserve-ephemeral-rebuild" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/preserve_ephemeral_rebuild/api/v2" name="PreserveEphemeralOnRebuild">
|
||||
<description>%(text)s</description>
|
||||
</extension>
|
||||
</extensions>
|
||||
|
@ -0,0 +1,55 @@
|
||||
{
|
||||
"server": {
|
||||
"accessIPv4": "%(ip)s",
|
||||
"accessIPv6": "%(ip6)s",
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "%(ip)s",
|
||||
"version": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"adminPass": "%(password)s",
|
||||
"created": "%(timestamp)s",
|
||||
"flavor": {
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/openstack/flavors/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
},
|
||||
"hostId": "%(hostid)s",
|
||||
"id": "%(uuid)s",
|
||||
"image": {
|
||||
"id": "%(uuid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/openstack/images/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v2/openstack/servers/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/openstack/servers/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"meta var": "meta val"
|
||||
},
|
||||
"name": "%(name)s",
|
||||
"progress": 0,
|
||||
"status": "ACTIVE",
|
||||
"tenant_id": "openstack",
|
||||
"updated": "%(timestamp)s",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<server xmlns="http://docs.openstack.org/compute/api/v1.1"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom"
|
||||
id="%(uuid)s"
|
||||
tenantId="openstack" userId="fake"
|
||||
name="%(name)s"
|
||||
hostId="%(hostid)s" progress="0"
|
||||
status="ACTIVE" adminPass="%(password)s"
|
||||
created="%(timestamp)s"
|
||||
updated="%(timestamp)s"
|
||||
accessIPv4="%(ip)s"
|
||||
accessIPv6="%(ip6)s">
|
||||
<image id="%(uuid)s">
|
||||
<atom:link
|
||||
rel="bookmark"
|
||||
href="%(host)s/openstack/images/%(uuid)s"/>
|
||||
</image>
|
||||
<flavor id="1">
|
||||
<atom:link
|
||||
rel="bookmark"
|
||||
href="%(host)s/openstack/flavors/1"/>
|
||||
</flavor>
|
||||
<metadata>
|
||||
<meta key="My Server Name">Apache1</meta>
|
||||
</metadata>
|
||||
<addresses>
|
||||
<network id="private">
|
||||
<ip version="4" addr="%(ip)s"/>
|
||||
</network>
|
||||
</addresses>
|
||||
<atom:link
|
||||
rel="self"
|
||||
href="%(host)s/v2/openstack/servers/%(uuid)s"/>
|
||||
<atom:link
|
||||
rel="bookmark"
|
||||
href="%(host)s/openstack/servers/%(uuid)s"/>
|
||||
</server>
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"rebuild" : {
|
||||
"imageRef" : "%(host)s/v2/32278/images/%(uuid)s",
|
||||
"name" : "%(name)s",
|
||||
"adminPass" : "%(pass)s",
|
||||
"accessIPv4" : "%(ip)s",
|
||||
"accessIPv6" : "%(ip6)s",
|
||||
"metadata" : {
|
||||
"meta var" : "meta val"
|
||||
},
|
||||
"personality" : [
|
||||
{
|
||||
"path" : "/etc/banner.txt",
|
||||
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
],
|
||||
"preserve_ephemeral": %(preserve_ephemeral)s
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rebuild
|
||||
xmlns="http://docs.openstack.org/compute/api/v1.1"
|
||||
name="%(name)s"
|
||||
imageRef="%(host)s/v1.1/32278/images/%(uuid)s"
|
||||
accessIPv4="%(ip)s"
|
||||
accessIPv6="%(ip6)s"
|
||||
adminPass="%(pass)s"
|
||||
preserve_ephemeral="%(preserve_ephemeral)s">
|
||||
<metadata>
|
||||
<meta key="My Server Name">Apache1</meta>
|
||||
</metadata>
|
||||
<personality>
|
||||
<file path="/etc/banner.txt">
|
||||
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||
</file>
|
||||
</personality>
|
||||
</rebuild>
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server" : {
|
||||
"name" : "new-server-test",
|
||||
"imageRef" : "%(host)s/openstack/images/%(image_id)s",
|
||||
"flavorRef" : "%(host)s/openstack/flavors/1",
|
||||
"metadata" : {
|
||||
"My Server Name" : "Apache1"
|
||||
},
|
||||
"personality" : [
|
||||
{
|
||||
"path" : "/etc/banner.txt",
|
||||
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="%(host)s/openstack/images/%(image_id)s" flavorRef="%(host)s/openstack/flavors/1" name="new-server-test">
|
||||
<metadata>
|
||||
<meta key="My Server Name">Apache1</meta>
|
||||
</metadata>
|
||||
<personality>
|
||||
<file path="/etc/banner.txt">
|
||||
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||
</file>
|
||||
</personality>
|
||||
</server>
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server": {
|
||||
"adminPass": "%(password)s",
|
||||
"id": "%(id)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v2/openstack/servers/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/openstack/servers/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="%(id)s" adminPass="%(password)s">
|
||||
<metadata/>
|
||||
<atom:link href="%(host)s/v2/openstack/servers/%(uuid)s" rel="self"/>
|
||||
<atom:link href="%(host)s/openstack/servers/%(uuid)s" rel="bookmark"/>
|
||||
</server>
|
@ -3982,3 +3982,61 @@ class MigrationsSamplesJsonTest(ApiSampleTestBaseV2):
|
||||
|
||||
class MigrationsSamplesXmlTest(MigrationsSamplesJsonTest):
|
||||
ctype = 'xml'
|
||||
|
||||
|
||||
class PreserveEphemeralOnRebuildJsonTest(ServersSampleBase):
|
||||
extension_name = ('nova.api.openstack.compute.contrib.'
|
||||
'preserve_ephemeral_rebuild.'
|
||||
'Preserve_ephemeral_rebuild')
|
||||
|
||||
def _test_server_action(self, uuid, action,
|
||||
subs={}, resp_tpl=None, code=202):
|
||||
subs.update({'action': action})
|
||||
response = self._do_post('servers/%s/action' % uuid,
|
||||
'server-action-%s' % action.lower(),
|
||||
subs)
|
||||
if resp_tpl:
|
||||
subs.update(self._get_regexes())
|
||||
self._verify_response(resp_tpl, subs, response, code)
|
||||
else:
|
||||
self.assertEqual(response.status, code)
|
||||
self.assertEqual(response.read(), "")
|
||||
|
||||
def test_rebuild_server_preserve_ephemeral_false(self):
|
||||
uuid = self._post_server()
|
||||
image = self.api.get_images()[0]['id']
|
||||
subs = {'host': self._get_host(),
|
||||
'uuid': image,
|
||||
'name': 'foobar',
|
||||
'pass': 'seekr3t',
|
||||
'ip': '1.2.3.4',
|
||||
'ip6': 'fe80::100',
|
||||
'hostid': '[a-f0-9]+',
|
||||
'preserve_ephemeral': 'false'}
|
||||
self._test_server_action(uuid, 'rebuild', subs,
|
||||
'server-action-rebuild-resp')
|
||||
|
||||
def test_rebuild_server_preserve_ephemeral_true(self):
|
||||
image = self.api.get_images()[0]['id']
|
||||
subs = {'host': self._get_host(),
|
||||
'uuid': image,
|
||||
'name': 'new-server-test',
|
||||
'pass': 'seekr3t',
|
||||
'ip': '1.2.3.4',
|
||||
'ip6': 'fe80::100',
|
||||
'hostid': '[a-f0-9]+',
|
||||
'preserve_ephemeral': 'true'}
|
||||
|
||||
def fake_rebuild(self_, context, instance, image_href, admin_password,
|
||||
**kwargs):
|
||||
self.assertTrue(kwargs['preserve_ephemeral'])
|
||||
self.stubs.Set(compute_api.API, 'rebuild', fake_rebuild)
|
||||
|
||||
instance_uuid = self._post_server()
|
||||
response = self._do_post('servers/%s/action' % instance_uuid,
|
||||
'server-action-rebuild', subs)
|
||||
self.assertEqual(response.status, 202)
|
||||
|
||||
|
||||
class PreserveEphemeralOnRebuildXmlTest(PreserveEphemeralOnRebuildJsonTest):
|
||||
ctype = 'xml'
|
||||
|
@ -0,0 +1,55 @@
|
||||
{
|
||||
"server": {
|
||||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"addr": "%(ip)s",
|
||||
"version": 4,
|
||||
"mac_addr": "aa:bb:cc:dd:ee:ff",
|
||||
"type": "fixed"
|
||||
}
|
||||
]
|
||||
},
|
||||
"admin_password": "%(password)s",
|
||||
"created": "%(timestamp)s",
|
||||
"flavor": {
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/flavors/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
},
|
||||
"host_id": "%(hostid)s",
|
||||
"id": "%(uuid)s",
|
||||
"image": {
|
||||
"id": "%(uuid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(glance_host)s/images/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v3/servers/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/servers/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"meta_var": "meta_val"
|
||||
},
|
||||
"name": "%(name)s",
|
||||
"progress": 0,
|
||||
"status": "ACTIVE",
|
||||
"tenant_id": "openstack",
|
||||
"updated": "%(timestamp)s",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<server xmlns="http://docs.openstack.org/compute/api/v1.1"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom"
|
||||
id="%(uuid)s"
|
||||
tenant_id="openstack" user_id="fake"
|
||||
name="%(name)s"
|
||||
host_id="%(hostid)s" progress="0"
|
||||
status="ACTIVE" admin_password="%(password)s"
|
||||
created="%(timestamp)s"
|
||||
updated="%(timestamp)s">
|
||||
<image id="%(uuid)s">
|
||||
<atom:link
|
||||
rel="bookmark"
|
||||
href="%(glance_host)s/images/%(uuid)s"/>
|
||||
</image>
|
||||
<flavor id="1">
|
||||
<atom:link
|
||||
rel="bookmark"
|
||||
href="%(host)s/flavors/1"/>
|
||||
</flavor>
|
||||
<metadata>
|
||||
<meta key="meta_var">meta_val</meta>
|
||||
</metadata>
|
||||
<addresses>
|
||||
<network id="private">
|
||||
<ip version="4" addr="%(ip)s" type="fixed" mac_addr="aa:bb:cc:dd:ee:ff"/>
|
||||
</network>
|
||||
</addresses>
|
||||
<atom:link
|
||||
rel="self"
|
||||
href="%(host)s/v3/servers/%(uuid)s"/>
|
||||
<atom:link
|
||||
rel="bookmark"
|
||||
href="%(host)s/servers/%(uuid)s"/>
|
||||
</server>
|
@ -0,0 +1,17 @@
|
||||
{
|
||||
"rebuild" : {
|
||||
"image_ref" : "%(glance_host)s/images/%(uuid)s",
|
||||
"name" : "%(name)s",
|
||||
"admin_password" : "%(pass)s",
|
||||
"metadata" : {
|
||||
"meta_var" : "meta_val"
|
||||
},
|
||||
"personality" : [
|
||||
{
|
||||
"path" : "/etc/banner.txt",
|
||||
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
],
|
||||
"preserve_ephemeral": %(preserve_ephemeral)s
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rebuild
|
||||
xmlns="http://docs.openstack.org/compute/api/v1.1"
|
||||
name="%(name)s"
|
||||
image_ref="%(glance_host)s/images/%(uuid)s"
|
||||
admin_password="%(pass)s"
|
||||
preserve_ephemeral="%(preserve_ephemeral)s">
|
||||
<metadata>
|
||||
<meta key="meta_var">meta_val</meta>
|
||||
</metadata>
|
||||
<personality>
|
||||
<file path="/etc/banner.txt">
|
||||
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||
</file>
|
||||
</personality>
|
||||
</rebuild>
|
@ -14,6 +14,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from nova.compute import api as compute_api
|
||||
from nova.tests.image import fake
|
||||
from nova.tests.integrated.v3 import api_sample_base
|
||||
|
||||
@ -116,6 +117,35 @@ class ServersActionsJsonTest(ServersSampleBase):
|
||||
self._test_server_action(uuid, 'rebuild', subs,
|
||||
'server-action-rebuild-resp')
|
||||
|
||||
def _test_server_rebuild_preserve_ephemeral(self, value):
|
||||
uuid = self._post_server()
|
||||
image = fake.get_valid_image_id()
|
||||
subs = {'host': self._get_host(),
|
||||
'uuid': image,
|
||||
'name': 'foobar',
|
||||
'pass': 'seekr3t',
|
||||
'hostid': '[a-f0-9]+',
|
||||
'preserve_ephemeral': str(value).lower(),
|
||||
'action': 'rebuild',
|
||||
'glance_host': self._get_glance_host(),
|
||||
}
|
||||
|
||||
def fake_rebuild(self_, context, instance, image_href, admin_password,
|
||||
files_to_inject=None, **kwargs):
|
||||
self.assertEqual(kwargs['preserve_ephemeral'], value)
|
||||
self.stubs.Set(compute_api.API, 'rebuild', fake_rebuild)
|
||||
|
||||
response = self._do_post('servers/%s/action' % uuid,
|
||||
'server-action-rebuild-preserve-ephemeral',
|
||||
subs)
|
||||
self.assertEqual(response.status, 202)
|
||||
|
||||
def test_server_rebuild_preserve_ephemeral_true(self):
|
||||
self._test_server_rebuild_preserve_ephemeral(True)
|
||||
|
||||
def test_server_rebuild_preserve_ephemeral_false(self):
|
||||
self._test_server_rebuild_preserve_ephemeral(False)
|
||||
|
||||
def test_server_resize(self):
|
||||
self.flags(allow_resize_to_same_host=True)
|
||||
uuid = self._post_server()
|
||||
|
@ -217,7 +217,8 @@ class ComputeDriver(object):
|
||||
def rebuild(self, context, instance, image_meta, injected_files,
|
||||
admin_password, bdms, detach_block_devices,
|
||||
attach_block_devices, network_info=None,
|
||||
recreate=False, block_device_info=None):
|
||||
recreate=False, block_device_info=None,
|
||||
preserve_ephemeral=False):
|
||||
"""Destroy and re-make this instance.
|
||||
|
||||
A 'rebuild' effectively purges all existing data from the system and
|
||||
@ -250,6 +251,8 @@ class ComputeDriver(object):
|
||||
hypervisor - all the cleanup of old state is skipped.
|
||||
:param block_device_info: Information about block devices to be
|
||||
attached to the instance.
|
||||
:param preserve_ephemeral: True if the default ephemeral storage
|
||||
partition must be preserved on rebuild
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user