3주차 과제 - 김윤수

필수 과제

2주차에 진행한 server list 확장 코드에서 tox를 통해 unit test를 실행시키면 Test Failed가 발생합니다.
openstackclient.tests.unit.compute 경로에 있는 server list에 대한 unit test를 수정하여 tox 실행시 모든 unit test에서 성공하도록 해주세요
제출 내용 1: 수정된 unit test code (스크린샷 또는 실제 코드)
제출 내용 2: tox를 통해 모든 unit test 통과한 화면

결과

  1. 모든 self.data에 user_name과 project_name 컬럼 추가
self.data = tuple(
    (
        s.id,
        s.name,
        s.status,
        server.AddressesColumn(s.addresses),
        # Image will be an empty string if boot-from-volume
        self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
        # [YS] Add value
        s.user_name,
        s.project_name,
        self.flavor.name,
    )
    for s in self.servers
)

  1. Test에 사용되는 mock 객체에 추가된 컬럼에 해당되는 값 추가 (현재 테스트는 값만 있으면 되기 때문에 ‘N/A’)
class TestServer(compute_fakes.TestComputev2):
    def setUp(self):
        super().setUp()

        # Set object attributes to be tested. Could be overwritten in subclass.
        self.attrs = {}

    def setup_sdk_servers_mock(self, count):
        servers = compute_fakes.create_servers(
            attrs=self.attrs,
            count=count,
        )
        
        #[YS] Add Value
        for mock_server in servers:
            mock_server.user_name = 'N/A'
            mock_server.project_name = 'N/A'
  1. TestServerList와 TestServerListV273에 사용되는 columns 값 수정

    # [YS] Create new col data
    # Columns to be listed up.
    columns = (
        'ID',
        'Name',
        'Status',
        'Networks',
        'Image',
        'User name',
        'Project name',
        'Flavor',
    )
    # columns = (
    #     'ID',
    #     'Name',
    #     'Status',
    #     'Networks',
    #     'Image',
    #     'Flavor',
    # )
    columns_long = (
        'ID',
        'Name',
        'Status',
        'Task State',
        'Power State',
        'Networks',
        'Image Name',
        'Image ID',
        'User name',
        'Project name',
        'Flavor Name',
        'Flavor ID',
        'Availability Zone',
        'Pinned Availability Zone',
        'Host',
        'Properties',
        'Scheduler Hints',
    )
    # columns_long = (
    #     'ID',
    #     'Name',
    #     'Status',
    #     'Task State',
    #     'Power State',
    #     'Networks',
    #     'Image Name',
    #     'Image ID',
    #     'Flavor Name',
    #     'Flavor ID',
    #     'Availability Zone',
    #     'Pinned Availability Zone',
    #     'Host',
    #     'Properties',
    #     'Scheduler Hints',
    # )
    columns_all_projects = (
        'ID',
        'Name',
        'Status',
        'Networks',
        'Image',
        'User name',
        'Project name',
        'Flavor',
        'Project ID',
    )
  1. 결과


수행 과정

1. Run tox

A. server.py 파일 수정 전

1개 Fail

Failed 1 tests - output below:
==============================

openstackclient.tests.unit.compute.v2.test_server.TestServerCreate.test_server_create_with_block_device_from_file

Captured traceback:
    Traceback (most recent call last):

      File "C:\Users\rladb\contribution-academy\OCA-OpenStack\python-openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 2735, in test_server_create_with_block_device_from_file
    parsed_args = self.check_parser(self.cmd, arglist, verifylist)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

      File "C:\Users\rladb\contribution-academy\OCA-OpenStack\python-openstackclient\openstackclient\tests\unit\utils.py", line 86, in check_parser
    parsed_args = cmd_parser.parse_args(args)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\argparse.py", line 1874, in parse_args
    args, argv = self.parse_known_args(args, namespace)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\argparse.py", line 1907, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\argparse.py", line 2128, in _parse_known_args
    start_index = consume_optional(start_index)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\argparse.py", line 2068, in consume_optional
    take_action(action, args, option_string)

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\argparse.py", line 1983, in take_action
    action(self, namespace, argument_values, option_string)

      File "C:\Users\rladb\contribution-academy\OCA-OpenStack\python-openstackclient\openstackclient\compute\v2\server.py", line 1068, in __call__
    with open(values) as fh:
         ^^^^^^^^^^^^

    PermissionError: [Errno 13] Permission denied: 'C:\\Users\\rladb\\AppData\\Local\\Temp\\tmpzjz1_ewu'


openstackclient.tests.unit.compute.v2.test_server.TestServerListV273.test_server_list_v269_with_partial_constructs


B. server.py 파일 수정 후

26개 Fail

Failed 26 tests   output below:
==============================

openstackclient.tests.unit.compute.v2.test_server.TestServerCreate.test_server_create_with_block_device_from_file
                                                                                                                 

Captured traceback:
                                      
    Traceback (most recent call last):

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 2735, in test_server_create_with_block_device_from_file
    parsed_args = self.check_parser(self.cmd, arglist, verifylist)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\tests\unit\utils.py", line 86, in check_parser
    parsed_args = cmd_parser.parse_args(args)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\argparse.py", line 1874, in parse_args
    args, argv = self.parse_known_args(args, namespace)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\argparse.py", line 1907, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\argparse.py", line 2128, in _parse_known_args
    start_index = consume_optional(start_index)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\argparse.py", line 2068, in consume_optional
    take_action(action, args, option_string)

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\argparse.py", line 1983, in take_action
    action(self, namespace, argument_values, option_string)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\compute\v2\server.py", line 1068, in __call__
    with open(values) as fh:
         ^^^^^^^^^^^^

    PermissionError: [Errno 13] Permission denied: 'C:\\Users\\rladb\\AppData\\Local\\Temp\\tmpzjz1_ewu'


openstackclient.tests.unit.compute.v2.test_server.TestServerListV273.test_server_list_v269_with_partial_constructs
                                                                                                                  

Captured traceback:
                                      
    Traceback (most recent call last):

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 5547, in test_server_list_v269_with_partial_constructs
    self.assertEqual(expected_row, partial_server)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\.tox\py3\Lib\site packages\testtools\testcase.py", line 419, in assertEqual      
    self.assertThat(observed, matcher, message)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\.tox\py3\Lib\site packages\testtools\testcase.py", line 509, in assertThat       
    raise mismatch_error

    testtools.matchers._impl.MismatchError: !=:
reference = ('server id 95a56bfc4xxxxxx28d7e418bfd97813a',
 None,
 'UNKNOWN',
 AddressesColumn({}),
 '',
 '')
actual    = ('server id 95a56bfc4xxxxxx28d7e418bfd97813a',
 None,
 'UNKNOWN',
 AddressesColumn({}),
 '',
 'N/A',
 <Mock name='mock.get().name' id='3079133239440'>,
 '')



openstackclient.tests.unit.compute.v2.test_server.TestServerList.test_server_list_all_projects_option
                                                                                                     

Captured traceback:
                                      
    Traceback (most recent call last):

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 4794, in test_server_list_all_projects_option
    self.assertEqual(self.columns_all_projects, columns)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\.tox\py3\Lib\site packages\testtools\testcase.py", line 419, in assertEqual      
    self.assertThat(observed, matcher, message)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\.tox\py3\Lib\site packages\testtools\testcase.py", line 509, in assertThat       
    raise mismatch_error

    testtools.matchers._impl.MismatchError: !=:
reference = ('ID', 'Name', 'Status', 'Networks', 'Image', 'Flavor', 'Project ID')
actual    = ('ID',
 'Name',
 'Status',
 'Networks',
 'Image',
 'User name',
 'Project name',
 'Flavor',
 'Project ID')



openstackclient.tests.unit.compute.v2.test_server.TestServerListV273.test_server_list_with_changes_before
                                                                                                         

Captured traceback:
                                      
    Traceback (most recent call last):

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 5473, in test_server_list_with_changes_before
    self.assertCountEqual(self.columns, columns)

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\unittest\case.py", line 1233, in assertCountEqual
    self.fail(msg)

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\unittest\case.py", line 703, in fail
    raise self.failureException(msg)

    AssertionError: Element counts were not equal:
First has 0, Second has 1:  'User name'
First has 0, Second has 1:  'Project name'


openstackclient.tests.unit.compute.v2.test_server.TestServerList.test_server_list_long_option
                                                                                             

Captured traceback:
                                      
    Traceback (most recent call last):

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 4764, in test_server_list_long_option
    self.assertEqual(self.columns_long, columns)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\.tox\py3\Lib\site packages\testtools\testcase.py", line 419, in assertEqual      
    self.assertThat(observed, matcher, message)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\.tox\py3\Lib\site packages\testtools\testcase.py", line 509, in assertThat       
    raise mismatch_error

    testtools.matchers._impl.MismatchError: !=:
reference = ('ID',
 'Name',
 'Status',
 'Task State',
 'Power State',
 'Networks',
 'Image Name',
 'Image ID',
 'Flavor Name',
 'Flavor ID',
 'Availability Zone',
 'Pinned Availability Zone',
 'Host',
 'Properties',
 'Scheduler Hints')
actual    = ('ID',
 'Name',
 'Status',
 'Task State',
 'Power State',
 'Networks',
 'Image Name',
 'Image ID',
 'User name',
 'Project name',
 'Flavor Name',
 'Flavor ID',
 'Availability Zone',
 'Pinned Availability Zone',
 'Host',
 'Properties',
 'Scheduler Hints')



openstackclient.tests.unit.compute.v2.test_server.TestServerListV273.test_server_list_with_locked
                                                                                                 

Captured traceback:
                                      
    Traceback (most recent call last):

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 5425, in test_server_list_with_locked
    self.assertCountEqual(self.columns, columns)

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\unittest\case.py", line 1233, in assertCountEqual
    self.fail(msg)

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\unittest\case.py", line 703, in fail
    raise self.failureException(msg)

    AssertionError: Element counts were not equal:
First has 0, Second has 1:  'User name'
First has 0, Second has 1:  'Project name'


openstackclient.tests.unit.compute.v2.test_server.TestServerList.test_server_list_long_with_host_status_v216
                                                                                                            

Captured traceback:
                                      
    Traceback (most recent call last):

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 5278, in test_server_list_long_with_host_status_v216
    self.assertEqual(self.columns_long, columns)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\.tox\py3\Lib\site packages\testtools\testcase.py", line 419, in assertEqual      
    self.assertThat(observed, matcher, message)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\.tox\py3\Lib\site packages\testtools\testcase.py", line 509, in assertThat       
    raise mismatch_error

    testtools.matchers._impl.MismatchError: !=:
reference = ('ID',
 'Name',
 'Status',
 'Task State',
 'Power State',
 'Networks',
 'Image Name',
 'Image ID',
 'Flavor Name',
 'Flavor ID',
 'Availability Zone',
 'Pinned Availability Zone',
 'Host',
 'Properties',
 'Scheduler Hints')
actual    = ('ID',
 'Name',
 'Status',
 'Task State',
 'Power State',
 'Networks',
 'Image Name',
 'Image ID',
 'User name',
 'Project name',
 'Flavor Name',
 'Flavor ID',
 'Availability Zone',
 'Pinned Availability Zone',
 'Host',
 'Properties',
 'Scheduler Hints')



openstackclient.tests.unit.compute.v2.test_server.TestServerList.test_server_list_n_option
                                                                                          

Captured traceback:
                                      
    Traceback (most recent call last):

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 4909, in test_server_list_n_option
    self.assertEqual(self.columns, columns)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\.tox\py3\Lib\site packages\testtools\testcase.py", line 419, in assertEqual      
    self.assertThat(observed, matcher, message)

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\.tox\py3\Lib\site packages\testtools\testcase.py", line 509, in assertThat       
    raise mismatch_error

    testtools.matchers._impl.MismatchError: !=:
reference = ('ID', 'Name', 'Status', 'Networks', 'Image', 'Flavor')
actual    = ('ID',
 'Name',
 'Status',
 'Networks',
 'Image',
 'User name',
 'Project name',
 'Flavor')



openstackclient.tests.unit.compute.v2.test_server.TestServerListV273.test_server_list_with_unlocked_v273
                                                                                                        

Captured traceback:
                                      
    Traceback (most recent call last):

      File "C:\Users\rladb\contribution academy\OCA OpenStack\python openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 5440, in test_server_list_with_unlocked_v273
    self.assertCountEqual(self.columns, columns)

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\unittest\case.py", line 1233, in assertCountEqual
    self.fail(msg)

      File "C:\Users\rladb\AppData\Local\Programs\Python\Python311\Lib\unittest\case.py", line 703, in fail
    raise self.failureException(msg)

    AssertionError: Element counts were not equal:
...

A에서는 1개가 Fail되고 B에서는 26개가 Fail 되었다. 먼저 Server List에 해당하는 B를 고치고 A를 설명하도록 하겠다.

2. Trace back from the fail log

test_server.py에서 발생한 Fail 로그를 살펴보면 2가지 타입이 있다.
Type 1. assert가 expected_row에서 발생하고, mismatch_error로 끝난다.

  File "C:\Users\rladb\contribution-academy\OCA-OpenStack\python-openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 5547, in test_server_list_v269_with_partial_constructs
    self.assertEqual(expected_row, partial_server)

      File "C:\Users\rladb\contribution-academy\OCA-OpenStack\python-openstackclient\.tox\py3\Lib\site-packages\testtools\testcase.py", line 419, in assertEqual      
    self.assertThat(observed, matcher, message)

      File "C:\Users\rladb\contribution-academy\OCA-OpenStack\python-openstackclient\.tox\py3\Lib\site-packages\testtools\testcase.py", line 509, in assertThat       
    raise mismatch_error

    testtools.matchers._impl.MismatchError: !=:
reference = ('server-id-95a56bfc4xxxxxx28d7e418bfd97813a',
 None,
 'UNKNOWN',
 AddressesColumn({}),
 '',
 '')
actual    = ('server-id-95a56bfc4xxxxxx28d7e418bfd97813a',
 None,
 'UNKNOWN',
 AddressesColumn({}),
 '',
 'N/A',
 <Mock name='mock.get().name' id='3079133239440'>,
 '')

Type 2. columns에서 발생하고 mismatch_error로 끝난다.

File "C:\Users\rladb\contribution-academy\OCA-OpenStack\python-openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 4794, in test_server_list_all_projects_option
    self.assertEqual(self.columns_all_projects, columns)

      File "C:\Users\rladb\contribution-academy\OCA-OpenStack\python-openstackclient\.tox\py3\Lib\site-packages\testtools\testcase.py", line 419, in assertEqual      
    self.assertThat(observed, matcher, message)

      File "C:\Users\rladb\contribution-academy\OCA-OpenStack\python-openstackclient\.tox\py3\Lib\site-packages\testtools\testcase.py", line 509, in assertThat       
    raise mismatch_error

    testtools.matchers._impl.MismatchError: !=:
reference = ('ID', 'Name', 'Status', 'Networks', 'Image', 'Flavor', 'Project ID')
actual    = ('ID',
 'Name',
 'Status',
 'Networks',
 'Image',
 'User name',
 'Project name',
 'Flavor',
 'Project ID')

앞서 올려놓은 26개의 로그를 살펴보면 이 두 가지 type의 에러밖에 없다. 따라서 정리해보자면, server.py에서 바꾼 col과 row가 test에서 정상적으로 통과되도록 test_server.py를 수정해야한다.

3. Breakdown function

가장 맨 처음 Error가 발생했던 test_server_list_long_option을 분석해본다.

# --long 옵션과 함께 조회할 때 반환되는 컬럼과 데이터를 검증하는 유닛테스트

    def test_server_list_long_option(self):
  		# self.servers 목록에 있는 서버 객체들을 돌면서 
   		# 필요한 속성들을 튜플 형태로 추출해 self.data를 만든다.
        self.data = tuple(
            (
                s.id,
                s.name,
                s.status,
                getattr(s, 'task_state'),
                server.PowerStateColumn(getattr(s, 'power_state')),
                server.AddressesColumn(s.addresses),
                # Image will be an empty string if boot-from-volume
                self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
                s.image['id'] if s.image else server.IMAGE_STRING_FOR_BFV,
                self.flavor.name,
                s.flavor['id'],
                getattr(s, 'availability_zone'),
                getattr(s, 'pinned_availability_zone', ''),
                server.HostColumn(getattr(s, 'hypervisor_hostname')),
                format_columns.DictColumn(s.metadata),
                format_columns.DictListColumn(None),
            )
            for s in self.servers
        )
   		# self.cmf에 --long을 전달
        arglist = [
            '--long',
        ]
  		# 파싱 결과가 기대한 값으로 나오는지 T/F
        verifylist = [
            ('all_projects', False),
            ('long', True),
        ]
        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
		
   		# 실제 로직 take_action 호출하고 반환 받음 
        columns, data = self.cmd.take_action(parsed_args)
        self.compute_client.servers.assert_called_with(**self.kwargs)
        image_ids = {s.image['id'] for s in self.servers if s.image}
        self.image_client.images.assert_called_once_with(
            id=f'in:{",".join(image_ids)}',
        )
        self.compute_client.flavors.assert_called_once_with(is_public=None)
   		# 출력 columns가 기대한 값 `self.columns_long`과 같은지 확인
        self.assertEqual(self.columns_long, columns)
        self.assertEqual(self.data, tuple(data))

해당 코드에서 에러는 self.columns_long을 확인할 때 발생하므로 해당 인자의 위치를 찾아보았다.

4. self.columns_long 분석하기

# line 4570
class _TestServerList(TestServer):
    # Columns to be listed up.
    columns = (
        'ID',
        'Name',
        'Status',
        'Networks',
        'Image',
        'Flavor',
    )
    columns_long = (
        'ID',
        'Name',
        'Status',
        'Task State',
        'Power State',
        'Networks',
        'Image Name',
        'Image ID',
        'Flavor Name',
        'Flavor ID',
        'Availability Zone',
        'Pinned Availability Zone',
        'Host',
        'Properties',
        'Scheduler Hints',
    )
    columns_all_projects = (
        'ID',
        'Name',
        'Status',
        'Networks',
        'Image',
        'Flavor',
        'Project ID',
    )

self.columns_long은 test에서 지정한 Expected Value이다. 그러나 server.py에서 넘어오는 Actual Value가 달라 문제가 발생한다.

이제 다시 한번 FAIL log를 확인해보자


reference = self.columns_long이고 actual = columns이다.
actual의 값에 Image ID 뒤에 User nameProject name을 확인할 수 있다.

6. Fix expected value

class _TestServerList(TestServer):
    # Columns to be listed up.
    columns = (
        'ID',
        'Name',
        'Status',
        'Networks',
        'Image',
        'User name',
        'Project name',
        'Flavor',
    )
    columns_long = (
        'ID',
        'Name',
        'Status',
        'Task State',
        'Power State',
        'Networks',
        'Image Name',
        'Image ID',
        'User name',
        'Project name',
        'Flavor Name',
        'Flavor ID',
        'Availability Zone',
        'Pinned Availability Zone',
        'Host',
        'Properties',
        'Scheduler Hints',
    )
    columns_all_projects = (
        'ID',
        'Name',
        'Status',
        'Networks',
        'Image',
        'User name',
        'Project name',
        'Flavor',
        'Project ID',
    )

7. Trace back from the fail log

위를 해결하니 아래와 같은 문제가 새로 발생했다.

File "C:\Users\rladb\contribution-academy\OCA-OpenStack\python-openstackclient\openstackclient\tests\unit\compute\v2\test_server.py", line 5008, in test_server_list_with_flavor
    self.assertEqual(self.data, tuple(data))

self.data에 정의된 expected value가 actual value와 다른 문제가 발생했다.

따라서 모든 self.data를 변경해준다. 처음엔 setUp 만 변경해주면 일괄 적용되는 줄 알았는데, 함수 내에서 self.data를 또 고치는 경우가 있어 모두 수정해줘야 한다.

         self.data = tuple(
            (
                s.id,
                s.name,
                s.status,
                server.AddressesColumn(s.addresses),
                # Image will be an empty string if boot-from-volume
                self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
                # [YS] Create new self.data
                s.user_name,
                s.project_name,
                self.flavor.name,
            )
            for s in self.servers
        )

Window라서 발생한 호환 문제

는 천천히 추가하겠습니다!