3week - openstack server list 에 field 추가하기

contents

1. openstack server list 의 기본 결과 필드에 "Project ID" 를 추가하기

"server list" 인자 값을 처리하는 파일은 openstackclient/compute/v2/server 모듈에서 ListServer 클래스 이다. ListServer 클래스 take_action 메서드에서 테이블에 출력될 "columns_header" 와 data 를 받아올 columns 가 어떻게 구성되는지 확인해보자.

# openstackclent/compute/v2/server.py ListServer
def take_action(self, parsed_args):
     ...
     if parsed_args.columns:
     # unmodifiable 한 tuple 에서 list로 바꿔야 값을 추가할 수 있다.
     column_headers = list(column_headers)
     columns = list(columns)

     for c in parsed_args.columns:
         if c in ('Project ID', 'project_id'):
             columns.append('tenant_id')
             column_headers.append('Project ID')
         if c in ('User ID', 'user_id'):
             columns.append('user_id')
             column_headers.append('User ID')
         if c in ('Created At', 'created_at'):
             columns.append('created_at')
             column_headers.append('Created At')

     # convert back to tuple
     column_headers = tuple(column_headers)
     columns = tuple(columns)
     ...

take_action 메서드에서 기본적으로 column_headers 와 columns 는 다음과 같이 설정된다.

  • column_headers: ('ID', 'Name', 'Status', 'Networks', 'Image', 'Flavor')

  • columns: ('ID', 'Name', 'Status', 'Networks', 'Image Name', 'Flavor Name')

# openstackclent/compute/v2/server.py ListServer
def take_action(self, parsed_args):
     ...
     # 과정 1
     data = compute_client.servers.list(search_opts=search_opts,
                                                marker=marker_id,
                                                limit=parsed_args.limit)
     ...
     # 과정 2
     table = (
             column_headers,
             (
                 utils.get_item_properties(
                     s, columns,
                     mixed_case_fields=mixed_case_fields,
                     formatters={
                         'OS-EXT-STS:power_state': PowerStateColumn,
                         'Networks': format_columns.DictListColumn,
                         'Metadata': format_columns.DictColumn,
                     },
                 ) for s in data
             ),
         )
     return table

"과정 1" 을 수행 결과 "server list" 에 해당하는 인스턴스들과 해당 인스턴스들의 정보들이 data 에 할당된다. "과정 2" 를 통해 columns 튜플 각 값들에 상응하는 인스턴스에 대한 정보들을 추출하여 colum_header 와 함께 table 을 구성한다.

"과정 2" 에서 colums 값들과 각 인스턴스가 가진 정보(키:값) 키와 비교해서 같다면 해당 값을 추출하여 테이블에 출력하므로 "과정 2" 전에 columns 와 colum_header 튜플에 "tenant_id", "Project ID" 을 각각 추가하자.

# openstackclent/compute/v2/server.py ListServer
def take_action(self, parsed_args):
     ...
     column_headers = list(column_headers)
     columns = list(columns)

     ## server list 기본값에 Project ID 값 추가
     columns.append("tenant_id")
     column_headers.append('Project ID')

     if parsed_args.columns:
         ...

결과

+--------------------------------------+----------------+--------+--------------------------------------------------------+--------------------------+---------+----------------------------------+
| ID                                   | Name           | Status | Networks                                               | Image                    | Flavor  | Project ID                       |
+--------------------------------------+----------------+--------+--------------------------------------------------------+--------------------------+---------+----------------------------------+
| 478eac81-48b0-43b0-a2a7-66c249aa19c9 | test2_instance | ACTIVE | private=10.0.0.23, fdfe:f92c:c853:0:f816:3eff:fef0:317 | Ubuntu-18.04             | ds512M  | 72405027628a419f8485eb218a19b726 |
| 942ebcec-4cd1-4386-99a1-7152e7a7b9be | task2_instance | ACTIVE | public=192.168.100.229, 2001:db8::f1                   | Ubuntu-18.04             | ds512M  | 72405027628a419f8485eb218a19b726 |
| 86256d63-2d36-4aed-a67d-81e6861f12ec | test_instance  | ACTIVE | public=192.168.100.178, 2001:db8::2c7                  | cirros-0.5.2-x86_64-disk | m1.tiny | 72405027628a419f8485eb218a19b726 |
| ec2c6265-3d0a-4ed2-81c2-7a5f748e9d8f | task1_instance | ACTIVE | public=192.168.100.144, 2001:db8::122                  | cirros-0.5.2-x86_64-disk | m1.tiny | 72405027628a419f8485eb218a19b726 |
+--------------------------------------+----------------+--------+--------------------------------------------------------+--------------------------+---------+----------------------------------+

columns 에는 왜 "project_id" 가 아니라 "tenant_id" 를 추가해주나요??

"project" 와 "tenant" 는 같은 개념으로 보면 된다. keystone이 v2 에서 tenant로 갖고 있던 개념을 v3에서 project로 치환했다. domain, user group를 추가해서 좀더 자세하게 관리하기 위해서 용어도 이에 맞는 tenant에서 project르 변경한 거 같다.

결론은 "project", "tenant" 는 같은 개념이다.

2. openstack server list 의 기본 결과 필드에 "Created At"를 추가하기

1 번 문제와 동일한 방법으로 columns, column_header 튜플에 다음과 같은 값을 추가하면 된다.

  • colums 튜플에 “created_at” 추가

  • column_header 튜플에 “Created At” 추가

# openstackclent/compute/v2/server.py ListServer
def take_action(self, parsed_args):
    ...
    # unmodifiable 한 tuple 에서 list로 바꿔야 값을 추가할 수 있다.
    column_headers = list(column_headers)
    columns = list(columns)

    ### server list 기본값에 Created At 값 추가
    columns.append('created')
    column_headers.append('Created At')

    if parsed_args.columns:
    # convert tuple to list to edit them
    column_headers = list(column_headers)
    columns = list(columns)

    for c in parsed_args.columns:
    if c in ('Project ID', 'project_id'):
        columns.append('tenant_id')
        column_headers.append('Project ID')
    if c in ('User ID', 'user_id'):
        columns.append('user_id')
        column_headers.append('User ID')
    if c in ('Created At', 'created_at'):
        columns.append('created_at') # Issue
        column_headers.append('Created At')

    # convert back to tuple
    column_headers = tuple(column_headers)
    columns = tuple(columns)
    ...

결과

+--------------------------------------+----------------+--------+--------------------------------------------------------+--------------------------+---------+----------------------+
| ID                                   | Name           | Status | Networks                                               | Image                    | Flavor  | Created At           |
+--------------------------------------+----------------+--------+--------------------------------------------------------+--------------------------+---------+----------------------+
| 478eac81-48b0-43b0-a2a7-66c249aa19c9 | test2_instance | ACTIVE | private=10.0.0.23, fdfe:f92c:c853:0:f816:3eff:fef0:317 | Ubuntu-18.04             | ds512M  | 2021-08-17T08:27:26Z |
| 942ebcec-4cd1-4386-99a1-7152e7a7b9be | task2_instance | ACTIVE | public=192.168.100.229, 2001:db8::f1                   | Ubuntu-18.04             | ds512M  | 2021-08-15T14:43:10Z |
| 86256d63-2d36-4aed-a67d-81e6861f12ec | test_instance  | ACTIVE | public=192.168.100.178, 2001:db8::2c7                  | cirros-0.5.2-x86_64-disk | m1.tiny | 2021-08-15T13:10:22Z |
| ec2c6265-3d0a-4ed2-81c2-7a5f748e9d8f | task1_instance | ACTIVE | public=192.168.100.144, 2001:db8::122                  | cirros-0.5.2-x86_64-disk | m1.tiny | 2021-08-14T03:21:12Z |
+--------------------------------------+----------------+--------+--------------------------------------------------------+--------------------------+---------+----------------------+

Issue

재용님이 PR 한 Issue 입니다.

# openstackclent/compute/v2/server.py ListServer
 def take_action(self, parsed_args):
     ...
     # 과정 1
         for c in parsed_args.columns:
             ...
             if c in ('Created At', 'created_at'):
                 columns.append('created_at') # Issue
                 column_headers.append('Created At')
     ...
     # 과정 2
     data = compute_client.servers.list(search_opts=search_opts,
                                                marker=marker_id,
                                                limit=parsed_args.limit)
     ...
     # 과정 3
     table = (
             column_headers,
             (
                 utils.get_item_properties(
                     s, columns,
                     mixed_case_fields=mixed_case_fields,
                     formatters={
                         'OS-EXT-STS:power_state': PowerStateColumn,
                         'Networks': format_columns.DictListColumn,
                         'Metadata': format_columns.DictColumn,
                     },
                 ) for s in data
             ),
         )
     return table

“과정 2” 수행 시 command 를 실행하게 되면 data 는 "server list" 에 해당하는 서버 인스턴스들을 가리키는 객체가 된다.

각 인스턴스들의 "Created At" 값이 "created_at" 이 아닌 "created" 키에 값이 저장되어 있다.

openstack server list -c "Created At" 을 수행하게 되면 빈 테이블이 출력된다.

⇒ 이유: “과정 3”에서 columns 튜플에 존재하는 값들과 각 서버 인스턴스들이 가지고 있는 키 값을 비교해 같은 키들만을 테이블에 출력(정확히 말하면 table 구성)한다. columns 에 추가된 값은 "created_at" 이고 서버 인스턴스가 가진 키는 "created" 이므로 매칭이 안되어 출력이 안되는 것이다.

그래서 “과정 1”의 columns.append(‘created_at’) command를 columns.append('created') 로 수정해야한다.