1. 程式人生 > >openstack 例項軟重啟和硬重啟

openstack 例項軟重啟和硬重啟

在openstack 中重啟例項有兩種,分別被稱為“軟重啟”和“硬重啟”。所謂的軟重啟會嘗試正常關機並重啟例項,硬重啟會直接將例項“斷電”並重啟。也就是說硬重啟會“關閉”電源。其具體命令如下:

預設情況下,如果您通過nova重啟,執行的是軟重啟。

$ nova reboot SERVER

如果您需要執行硬重啟,新增–hard引數即可:

$ nova reboot --hard SERVER
從命令上看,兩者只是引數上有所區別,因此跟蹤具體程式碼研究一下(對應nova 程式碼為L版本的nova-12.0.0)。
    首先找到入口的API 介面函式: Nova->api->openstack->compute->servers.py


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 )

      上述程式碼中第13行( self.compute_api.reboot(context, instance, reboot_type) ), 跳轉到具體實現程式碼: nova->compute->api.py


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)做標識,並傳遞下去。
  但無論是軟重啟還是硬重啟,都重新給虛擬機器state 重新賦值,並通過RPC呼叫reboot_instance(第44行程式碼)。 程式碼跳轉至  Nova->compute->manager.py(注意由於這裡的程式碼實質上是通過RPC遠端呼叫的,所以其實際發生作用的程式碼應該是對應虛擬機器所在Compute節點上了)


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