
기여 내용
GET /v2/zones/{zone_id}/nameserversAPI를 이용하여 Name Server 목록을 불러오는 CLI 명령어 만들기.
designate client는 다음과 같이 사용할 수 있다.
client = self.app.client_manager.dns
출력해보면 <designateclient.v2.client.Client object at 0x1038f35b0>라고 나오는데, designate client를 불러온다는 것을 확인할 수 있다.
print(client.nameservers)
designate client 코드를 보면, nameservers.py 파일에 NameServerController라는 클래스가 존재한다. 이것이 nameserver를 불러오는 클래스라는 것을 직관적으로 알 수 있다. 위처럼 client.nameservers를 출력해보면 <designateclient.v2.nameservers.NameServerController object at 0x110180cd0>임을 알 수 있다.
designateclient의 NameServerController의 코드는 다음과 같다.
class NameServerController(V2Controller):
def list(self, zone):
zone = v2_utils.resolve_by_name(self.client.zones.list, zone)
url = f'/zones/{zone}/nameservers'
return self._get(url, response_key='nameservers')
즉, list라는 메소드를 통해 네임서버 목록을 불러오는 것으로 보인다. 인자 값으로 zone의 id를 함께 보내야 하므로 다음과 같이 코드를 작성할 수 있다.
zones = client.zones.list()
for s in zones:
for t in client.nameservers.list(s['id']):
print(t)
zone의 리스트를 불러와서 그 id를 이용해 네임서버 목록을 불러온다. 결과는 다음과 같다.

columns = ['hostname', 'priority', 'zone_id', 'zone_name']
column_headers = ['Name Server', 'Priority', 'Zone Id', 'Zone Name']
name server의 이름과 priority 뿐만 아니라 zone id랑 name까지 같이 출력하기로 했다.
우선 기존에 상속받는 클래스로 command.Command를 설정했는데, 이것을 ListServer와 동일하게 command.Lister로 변경하자 표 모양이 생성되었다. (그런데, 안에 내용이 채워지지는 않았음)
ListServer에서는 어떤 식으로 표에 내용을 채워넣는 지 알아내기 위해 코드를 분석했고, 다음과 같이 테이블 형태로 결과를 리턴함을 확인하였다.
table = (
column_headers,
(
utils.get_item_properties(
s,
columns,
mixed_case_fields=(
'task_state',
'power_state',
'availability_zone',
host',
,
formatters={
'power_state': PowerStateColumn,
'addresses': AddressesColumn,
'metadata': format_columns.DictColumn,
'security_groups_name': format_columns.ListColumn,
'hypervisor_hostname': HostColumn,
},
)
for s in data
),
)
return table
data는 리스트 형태이고, 이 리스트에서 설정한 columns와 일치하는 것의 값을 가져오는 방식인 것 같다. 그래서 동일하게 data 라는 리스트 내에 딕셔너리 형태로 네임서버를 하나씩 저장하기로 했다. 다음이 네임서버 정보를 data 라는 리스트에 저장하는 코드이다.
data = []
for s in zones:
m = {}
for t in client.nameservers.list(s['id']):
m['zone_id'] = s['id']
m['zone_name'] = s['name']
m['priority'] = t['priority']
m['hostname'] = t['hostname']
data.append(m)
각각의 zone에 대해 id를 이용하여 네임서버 목록을 불러오고, 이를 m 딕셔너리에 하나씩 저장한다. 이러한 딕셔너리를 data 리스트에 추가하면, 결과적으로 다음과 같은 형태가 된다.

현재는 zone도 1개고, nameserver도 1개여서 하나만 출력되는 것을 확인할 수 있다.
이제 이를 위에 table 형태로 추출할 수 있게 해줘야 한다. ListServer에서는 data에 저장된 값이 openstack.compute.v2.server.Server 객체 형태이기 때문에 utils.get_item_properties() 함수를 이용했었다. 그런데 지금은 리스트 내에 dictionary 형태이므로 인식을 하지 못하는 문제가 발생했다. (표에 값이 채워지지 않음) 그래서 utils 모듈에 다른 어떤 함수가 있는지 확인해본 결과, get_dict_properties() 함수를 발견했다. 다음은 해당 함수의 설명이다.
Return a tuple containing the item properties.
:param item: a single dict resource
:param fields: tuple of strings with the desired field names
:param mixed_case_fields: tuple of field names to preserve case
:param formatters: dictionary mapping field names to callables
to format the values
단일 딕셔너리 리소스로부터 tuple을 리턴해주는 함수이다. 딱 내가 원하던 함수! 그래서 바로 적용해보았다.
table = (
column_headers,
(
utils.get_dict_properties(
s,
columns,
)
for s in data
),
)
return table
이렇게 코드를 작성하니 비로소 테이블에 값이 채워졌다.

결과이다! zone 추가했을 때 네임서버도 추가로 출력되는지 확인해보자.
from osc_lib.command import command
from openstackclient.i18n import _
from osc_lib import utils
class ListNameServer(command.Lister):
_description = _("List name servers")
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.dns
zones = client.zones.list()
columns = ['hostname', 'priority', 'zone_id', 'zone_name']
column_headers = ['Name Server', 'Priority', 'Zone Id', 'Zone Name']
data = []
for s in zones:
m = {}
for t in client.nameservers.list(s['id']):
m['zone_id'] = s['id']
m['zone_name'] = s['name']
m['priority'] = t['priority']
m['hostname'] = t['hostname']
data.append(m)
table = (
column_headers,
(
utils.get_dict_properties(
s,
columns,
)
for s in data
),
)
return table