openstack 例項軟重啟和硬重啟
阿新 • • 發佈:2018-12-05
在openstack 中重啟例項有兩種,分別被稱為“軟重啟”和“硬重啟”。所謂的軟重啟會嘗試正常關機並重啟例項,硬重啟會直接將例項“斷電”並重啟。也就是說硬重啟會“關閉”電源。其具體命令如下:
預設情況下,如果您通過nova重啟,執行的是軟重啟。
$ nova reboot SERVER
如果您需要執行硬重啟,新增–hard引數即可:
$ nova reboot --hard SERVER從命令上看,兩者只是引數上有所區別,因此跟蹤具體程式碼研究一下(對應nova 程式碼為L版本的nova-12.0.0)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@wsgi.response(
202
)
@extensions.expected_errors((
404
,
409
))
@wsgi.action(
'reboot'
)
@validation.schema(schema_servers.reboot)
def
_action_reboot(
self
, req,
id
, body):
reboot_type
=
body[
'reboot'
][
'type'
].upper()
context
=
req.environ[
'nova.context'
]
authorize(context, action
=
'reboot'
)
instance
=
self
._get_server(context, req,
id
)
try
:
self .compute_api.reboot(context, instance, reboot_type)
except
exception.InstanceIsLocked as e:
raise
exc.HTTPConflict(explanation
=
e.format_message())
except
exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error,
'reboot'
,
id
)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
@wrap_check_policy
@check_instance_lock
@check_instance_state(vm_state
=
set
(
vm_states.ALLOW_SOFT_REBOOT
+
vm_states.ALLOW_HARD_REBOOT),
task_state
=
[
None
, task_states.REBOOTING,
task_states.REBOOT_PENDING,
task_states.REBOOT_STARTED,
task_states.REBOOTING_HARD,
task_states.RESUMING,
task_states.UNPAUSING,
task_states.PAUSING,
task_states.SUSPENDING])
def
reboot(
self
, context, instance, reboot_type):
"""Reboot the given instance."""
if
(reboot_type
=
=
'SOFT'
and
(instance.vm_state
not
in
vm_states.ALLOW_SOFT_REBOOT)):
raise
exception.InstanceInvalidState(
attr
=
'vm_state'
,
instance_uuid
=
instance.uuid,
state
=
instance.vm_state,
method
=
'soft reboot'
)
if
reboot_type
=
=
'SOFT'
and
instance.task_state
is
not
None
:
raise
exception.InstanceInvalidState(
attr
=
'task_state'
,
instance_uuid
=
instance.uuid,
state
=
instance.task_state,
method
=
'reboot'
)
expected_task_state
=
[
None
]
if
reboot_type
=
=
'HARD'
:
expected_task_state.extend([task_states.REBOOTING,
task_states.REBOOT_PENDING,
task_states.REBOOT_STARTED,
task_states.REBOOTING_HARD,
task_states.RESUMING,
task_states.UNPAUSING,
task_states.SUSPENDING])
state
=
{
'SOFT'
: task_states.REBOOTING,
'HARD'
: task_states.REBOOTING_HARD}[reboot_type]
instance.task_state
=
state
instance.save(expected_task_state
=
expected_task_state)
self
._record_action_start(context, instance, instance_actions.REBOOT)
self
.compute_rpcapi.reboot_instance(context, instance
=
instance,
block_device_info
=
None
,
reboot_type
=
reboot_type)
|
在compute-api的程式碼中,首先注意到在reboot方法上有幾個裝飾函式,其中的check_instance_state方法會檢查當前的虛擬機器是否處於如 task_states.RESUMING這樣的狀態,如果處於的話,則提示 InstanceInvalidState。也就是說 當虛擬機器的任務處於(REBOOTING,REBOOT_PENDING,REBOOT_STARTED,REBOOTING_HARD,RESUMING,UNPAUSING,PAUSING,SUSPENDING)時,軟硬重啟都不允許。詳細內容可以參看裝飾函式的具體實現程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
程式碼位於: nova->compute->api.py
def
check_instance_state(vm_state
=
None
, task_state
=
(
None
,),
must_have_launched
=
True
):
"""Decorator to check VM and/or task state before entry to API functions.
If the instance is in the wrong state, or has not been successfully
started at least once the wrapper will raise an exception.
"""
if
vm_state
is
not
None
and
not
isinstance
(vm_state,
set
):
vm_state
=
set
(vm_state)
if
task_state
is
not
None
and
not
isinstance
(task_state,
set
):
task_state
=
set
(task_state)
def
outer(f):
@functools.wraps(f)
def
inner(
self
, context, instance,
*
args,
*
*
kw):
if
vm_state
is
not
None
and
instance.vm_state
not
in
vm_state:
raise
exception.InstanceInvalidState(
attr
=
'vm_state'
,
instance_uuid
=
instance.uuid,
state
=
instance.vm_state,
method
=
f.__name__)
if (task_state is not None and
instance.task_state
not
in
task_state): (lst: 判斷是否能軟,硬重啟)
raise
exception.InstanceInvalidState(
attr
=
'task_state'
,
instance_uuid
=
instance.uuid,
state
=
instance.task_state,
method
=
f.__name__)
if
must_have_launched
and
not
instance.launched_at:
raise
exception.InstanceInvalidState(
attr
=
'launched_at'
,
instance_uuid
=
instance.uuid,
state
=
instance.launched_at,
method
=
f.__name__)
return
f(
self
, context, instance,
*
args,
*
*
kw)
return
inner
return
outer
|
然後,在回來繼續看compute-api中的reboot的程式碼,此時軟重啟和硬重啟在條件的判斷上就略有區別了。 從程式碼中可以看出
- 如果是軟重啟,則需要繼續判斷虛擬機器當前是否又其他任務,如果有則拋異常。
- 如果操作是硬重啟,則還需要更新expected_task_state的可能擴充套件狀態(task_states.REBOOTING, task_states.REBOOT_PENDING, task_states.REBOOT_STARTED, task_states.REBOOTING_HARD,task_states.RESUMING, task_states.UNPAUSING,task_states.SUSPENDING)做標識,並傳遞下去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
程式碼位於Nova->compute->manager.py:2874行
@wrap_exception()
@reverts_task_state
@wrap_instance_event
@wrap_instance_fault
def
reboot_instance(
self
, context, instance, block_device_info,
reboot_type):
"""Reboot an instance on this host."""
# acknowledge the request made it to the manager
if
reboot_type
=
=
"SOFT"
:
instance.task_state
=
task_states.REBOOT_PENDING
expected_states
=
(task_states.REBOOTING,
task_states.REBOOT_PENDING,
task_states.REBOOT_STARTED)
else
:
instance.task_state
=
task_states.REBOOT_PENDING_HARD
expected_states
=
(task_states.REBOOTING_HARD,
task_states.REBOOT_PENDING_HARD,
task_states.REBOOT_STARTED_HARD)
context
=
context.elevated()
LOG.info(_LI(
"Rebooting instance"
), context
=
context, instance
=
instance)
block_device_info
=
self
._get_instance_block_device_info(context,
instance)
network_info
=
self
.network_api.get_instance_nw_info(context, instance)
self
._notify_about_instance_usage(context, instance,
"reboot.start"
)
instance.power_state
=
self
._get_power_state(context, instance)
instance.save(expected_task_state
=
expected_states)
if
instance.power_state !
=
power_state.RUNNING:
state
=
instance.power_state
running
=
power_state.RUNNING
LOG.warning(_LW(
'trying to reboot a non-running instance:'
' (state: %(state)s expected: %(running)s)'
),
{
'state'
: state,
'running'
: running},
context
=
context, instance
=
instance)
def
bad_volumes_callback(bad_devices):
self
._handle_bad_volumes_detached(
context, instance, bad_devices, block_device_info)
try
:
# Don't change it out of rescue mode
if
instance.vm_state
=
=
vm_states.RESCUED:
new_vm_state
=
vm_states.RESCUED
else
:
new_vm_state
=
vm_states.ACTIVE
new_power_state
=
None
if
reboot_type
=
=
"SOFT"
:
instance.task_state
=
task_states.REBOOT_STARTED
expected_state
=
task_states.REBOOT_PENDING
else
:
instance.task_state
=
task_states.REBOOT_STARTED_HARD
expected_state
=
task_states.REBOOT_PENDING_HARD
instance.save(expected_task_state
=
expected_state)
self
.driver.reboot(context, instance,
network_info,
reboot_type,
block_device_info
=
block_device_info,
bad_volumes_callback
=
bad_volumes_callback)
except
Exception as error:
with excutils.save_and_reraise_exception() as ctxt:
exc_info
=
sys.exc_info()
# if the reboot failed but the VM is running don't
# put it into an error state
new_power_state
=
self
._get_power_state(context, instance)
if
new_power_state
=
=
power_state.RUNNING:
LOG.warning(_LW(
'Reboot failed but instance is running'
),
context
=
context, instance
=
instance)
compute_utils.add_instance_fault_from_exc(context,
instance, error, exc_info)
self
._notify_about_instance_usage(context, instance,
'reboot.error'
, fault
=
error)
ctxt.reraise
=
False
else
:
LOG.error(_LE(
'Cannot reboot instance: %s'
), error,
context
=
context, instance
=
instance)
self
._set_instance_obj_error_state(context, instance)
if
not
new_power_state:
new_power_state
=
self
._get_power_state(context, instance)
try
:
instance.power_state
=
new_power_state
instance.vm_state
=
new_vm_state
instance.task_state
=
None
instance.save()
except
exception.InstanceNotFound:
LOG.warning(_LW(
"Instance disappeared during reboot"
),
context
=
context, instance
=
instance)
self
._notify_about_instance_usage(context, instance,
"reboot.end"
)
|
從上述程式碼可知,根據軟硬重啟的型別不同虛擬機器將置成不同的狀態。完畢後依此獲取塊裝置和網路裝置資訊以及虛擬機器電源狀態,判斷電源狀態是否位於RUNNING狀態,如果不為RUNNING狀態,則將狀態職位職位RUNNING,下面繼續判斷狀態,最終將相關資訊傳遞給driver.reboot。 繼續跟中到driver層: Nova->virt->hyper->driver.py
1 2 3 |
def
reboot(
self
, context, instance, network_info, reboot_type,
block_device_info
=
None
, bad_volumes_callback
=
None
):
self
|