ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [OpenStack] Nova-Compute IncompatibleObjectVersion 해결하기
    메모/트러블 슈팅 2023. 3. 29. 19:38

    개요

    원래 1개의 데스크탑, 3개의 라즈베리파이에 우분투를 설치하고 개인 서버로 활용하고 있었다.

    솔직히 데스크탑은 공부용, 개발서버용 정도로 쓰고 있었는데 라즈베리파이가 놀고 있는게 맘에 좀 걸렸다.

    그러면서 또 여러 문제가 생겼는데 개인 서버가 있으니 클라우드를 활용하는 빈도가 현저히 적어졌다는 거다.

     

    솔직히 돈도 돈 때문에 안쓴거긴 하지만...

    그러다가 오픈스택을 함 올려볼까 싶었다.

    그래서 고민 끝에 윈도우 데스크탑을 밀고 우분투 서버를 설치했다.

     

    결과적으로 컴퓨팅 노드, 컨트롤 노드로 쓰일 데스크탑 서버 2대와 스토리지 노드로 쓰일 라즈베리파이 3대가 생겼다.

    이걸 클러스터링해서 어떻게 오픈스택을 잘 올려보려고 했다.

     


    문제 발생

    설치 과정이나 개념 정리는 다음에 한번에 적어보기로 하고...

    Keystone, Glance, Placement, Nova까지 잘 설치하고 Nova-compute를 준비할 차례가 됐다.

    구성요소를 작성하고 설정을 적용하기 위해서 nova-compute를 재시작하는데...

     

    openstack compute service list --service nova-compute

     

     

    공식문서에 따르면 컨트롤 노드에서 컴퓨팅 노드에 설치한 Nova-compute 서비스를 찾아야 한다고 한다.

     

    근데 컨트롤 노드에서 컴퓨팅 노드의 서비스를 찾지 못하고 있었다.

    그래서 컴퓨팅 노드에서 nova-compute의 서비스 상태를 확인해보니 서비스를 실행하자마자 비활성화 상태로 죽어버리는 상황이었다.

     

    /var/log/nova/nova-compute.log

    공식문서에 따르면 위 경로에 로그를 저장한다고 해서 로그를 열어봤다.

    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service Traceback (most recent call last):
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service   File "/usr/lib/python3/dist-packages/oslo_service/service.py", line 806, in run_service
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service     service.start()
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service   File "/usr/lib/python3/dist-packages/nova/service.py", line 162, in start
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service     self.manager.init_host(self.service_ref)
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service   File "/usr/lib/python3/dist-packages/nova/compute/manager.py", line 1638, in init_host
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service     evacuated_instances = self._destroy_evacuated_instances(
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service   File "/usr/lib/python3/dist-packages/nova/compute/manager.py", line 805, in _destroy_evacuated_instances
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service     evacuations = objects.MigrationList.get_by_filters(context,
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service   File "/usr/lib/python3/dist-packages/oslo_versionedobjects/base.py", line 175, in wrapper
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service     result = cls.indirection_api.object_class_action_versions(
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service   File "/usr/lib/python3/dist-packages/nova/conductor/rpcapi.py", line 240, in object_class_action_versions
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service     return cctxt.call(context, 'object_class_action_versions',
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service   File "/usr/lib/python3/dist-packages/oslo_messaging/rpc/client.py", line 190, in call
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service     result = self.transport._send(
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service   File "/usr/lib/python3/dist-packages/oslo_messaging/transport.py", line 123, in _send
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service     return self._driver.send(target, ctxt, message,
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service   File "/usr/lib/python3/dist-packages/oslo_messaging/_drivers/amqpdriver.py", line 689, in send
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service     return self._send(target, ctxt, message, wait_for_reply, timeout,
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service   File "/usr/lib/python3/dist-packages/oslo_messaging/_drivers/amqpdriver.py", line 681, in _send
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service     raise result
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service oslo_messaging.rpc.client.RemoteError: Remote error: IncompatibleObjectVersion Version 1.5 of MigrationList is not supported, supported version is 1.4
    2023-03-29 18:28:57.796 8600 ERROR oslo_service.service ['Traceback (most recent call last):\n', 
    '  File "/usr/lib/python3/dist-packages/oslo_messaging/rpc/server.py", line 165, in _process_incoming\n    res = self.dispatcher.dispatch(message)\n', 
    '  File "/usr/lib/python3/dist-packages/oslo_messaging/rpc/dispatcher.py", line 276, in dispatch\n    return self._do_dispatch(endpoint, method, ctxt, args)\n', 
    '  File "/usr/lib/python3/dist-packages/oslo_messaging/rpc/dispatcher.py", line 196, in _do_dispatch\n    result = func(ctxt, **new_args)\n', 
    '  File "/usr/lib/python3/dist-packages/nova/conductor/manager.py", line 145, in object_class_action_versions\n    objclass = nova_object.NovaObject.obj_class_from_name(\n', 
    '  File "/usr/lib/python3/dist-packages/oslo_versionedobjects/base.py", line 383, in obj_class_from_name\n    raise exception.IncompatibleObjectVersion(objname=objname,\n', 'oslo_versionedobjects.exception.IncompatibleObjectVersion: Version 1.5 of MigrationList is not supported, supported version is 1.4\n'].

     

    로그를 열어보니 크리티컬한 오류는 아닌거 같았다.

    대강 보면 MigrationList 라는 오브젝트의 버전이 현재 1.5가 설치되어 있고 1.4 버전이 지원된다는 것이었다.

     


    해결 과정

    첫 시도로 MigrationList가 파이썬에서 제공하는 패키지인지 살펴봤다.

    pip list를 통해서 조회한 파이썬 의존성 패키지에서는 MigrationList를 찾을 수 없었다.

     

     

    그래서 간단하게 코드를 살펴보기로 했다.

    # oslo_versionedobjects/base.py
    # 357라인부터
    
    @classmethod
    def obj_class_from_name(cls, objname, objver):
        """Returns a class from the registry based on a name and version."""
        if objname not in VersionedObjectRegistry.obj_classes():
            LOG.error('Unable to instantiate unregistered object type '
                      '%(objtype)s'), dict(objtype=objname)
            raise exception.UnsupportedObjectError(objtype=objname)
    
        # NOTE(comstud): If there's not an exact match, return the highest
        # compatible version. The objects stored in the class are sorted
        # such that highest version is first, so only set compatible_match
        # once below.
        compatible_match = None
    
        for objclass in VersionedObjectRegistry.obj_classes()[objname]:
            if objclass.VERSION == objver:
                return objclass
            if (not compatible_match and
                    vutils.is_compatible(objver, objclass.VERSION)):
                compatible_match = objclass
    
        if compatible_match:
            return compatible_match
    
        # As mentioned above, latest version is always first in the list.
        latest_ver = VersionedObjectRegistry.obj_classes()[objname][0].VERSION
        raise exception.IncompatibleObjectVersion(objname=objname,   ##  <- 요기
                                                  objver=objver,
                                                  supported=latest_ver)
    # oslo_versionedobjects/exception.py
    
    class IncompatibleObjectVersion(VersionedObjectsException):
        msg_fmt = _('Version %(objver)s of %(objname)s is not supported, '
                    'supported version is %(supported)s')

     

    에러가 발생한 메서드 내부에서 objclassVERSION 프로퍼티나 compatible_match의 조건을 통과하지 못하면 IncompatibleObjectVersion 예외처리를 발생시킨다.

     

    그런데 위의 코드에서 보면 오브젝트 클래스의 버전을 VersionedObjectRegistry에서 끌고온다.

    물론 이 클래스를 직접 살펴봐도 큰 정보는 얻을 수 없었다.

     

     

    어쨌건 oslo라는 레지스트리에서 관리하는 MigrationList라는 객체가 버전 불일치로 오류가 발생했다는 것까지는 알았다.

     

     

    GitHub - openstack/nova: OpenStack Compute (Nova). Mirror of code maintained at opendev.org.

    OpenStack Compute (Nova). Mirror of code maintained at opendev.org. - GitHub - openstack/nova: OpenStack Compute (Nova). Mirror of code maintained at opendev.org.

    github.com

    여기서부터 열심히 구글링을 하고 있었는데...

    우연히 Nova의 객체 클래스의 코드를 보게 되었다.

    ...
    
    @base.NovaObjectRegistry.register
    class ImageMeta(base.NovaObject):
        # Version 1.0: Initial version
        # Version 1.1: updated ImageMetaProps
        # Version 1.2: ImageMetaProps version 1.2
        # Version 1.3: ImageMetaProps version 1.3
        # Version 1.4: ImageMetaProps version 1.4
        # Version 1.5: ImageMetaProps version 1.5
        # Version 1.6: ImageMetaProps version 1.6
        # Version 1.7: ImageMetaProps version 1.7
        # Version 1.8: ImageMetaProps version 1.8
        VERSION = '1.8'
    
    
    ...

    VersionedObjectRegistry와 유사한 객체 레지스트리에서 객체 클래스의 버전을 위와 같이 관리하고 있었다.

     

    여기서 힌트를 얻었다.

    분명 MigrationList라는 객체 클래스가 의존성 패키지들 어딘가에 파이썬 코드로 존재할 것이고 그 코드에서 버전을 수정할 수 있다는 생각을 했다.

     

    그런데 나는 olso 하위의 패키지에서 이 클래스를 찾고 있었다. 하지만 위 코드는 nova 패키지 하위에 존재한다.

    nova/objects

    nova 패키지 하위에는 objects를 모아놓은 디렉터리가 있었고 그 경로 아래에서 migrate, migration의 키워드를 가진 코드를 찾았다.

     

    @base.NovaObjectRegistry.register
    class MigrationList(base.ObjectListBase, base.NovaObject):
        # Version 1.0: Initial version
        #              Migration <= 1.1
        # Version 1.1: Added use_slave to get_unconfirmed_by_dest_compute
        # Version 1.2: Migration version 1.2
        # Version 1.3: Added a new function to get in progress migrations
        #              for an instance.
        # Version 1.4: Added sort_keys, sort_dirs, limit, marker kwargs to
        #              get_by_filters for migrations pagination support.
        # Version 1.5: Added a new function to get in progress migrations
        #              and error migrations for a given host + node.
        VERSION = '1.5' ## <--- 요기
    
        fields = {
            'objects': fields.ListOfObjectsField('Migration'),
            }
    
        ...

    그리고 migration.py 내부에서 MigrationList 클래스를 찾았다!

     

    클래스 내부엔 버전이 1.5로 명시되어있었다.

    해당 값을 1.4로 변경하고나서...

     

     


    결과

    컨트롤 노드에서 컴퓨팅 노드를 찾을 수 있게 됐다!

     


    결론

    사실 근본적으로 적합한 버전을 설치했다면 이런 일이 없었을 것이다.

    버전도 강제로 변경했기에 다른 오류가 생길 수도 있지 않을까 싶었다.

    하지만 구글링에서도 명확한 해답을 찾지 못했다는데 코드 하나하나 찾아가보면서 직접 오류를 고쳐보니 좀 성취감이 있긴 하다.

    댓글

Designed by Tistory.