제출 내용 1
- TestServerList 클래스에 컬럼 추가
class _TestServerList(TestServer):
columns = (
'ID', 'Name', 'Status', 'Networks', 'Image', 'Flavor',
'User Name',
'Project Name',
)
- Keystone Identity 모킹
def setUp(self):
super().setUp()
def get_user_side_effect(user_id):
return User(id=user_id, name='test-user')
def get_project_side_effect(project_id):
return Project(id=project_id, name='test-project')
self.identity_client.users.get.side_effect = get_user_side_effect
self.identity_client.projects.get.side_effect = get_project_side_effect
- 테스트 데이터 수정
self.data = tuple(
(
s.id,
s.name,
s.status,
server.AddressesColumn(s.addresses),
self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
self.flavor.name,
'test-user',
'test-project',
)
for s in self.servers
)
제출 내용 2
.diff
파일
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index ac29650f..0d16f922 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -2857,6 +2857,16 @@ class ListServer(command.Lister):
columns += ('project_id',)
column_headers += ('Project ID',)
+ # Add user_name and project_name columns
+ columns += (
+ 'user_name',
+ 'project_name',
+ )
+ column_headers += (
+ 'User Name',
+ 'Project Name',
+ )
+
# support for additional columns
if parsed_args.columns:
for c in parsed_args.columns:
@@ -2866,6 +2876,12 @@ class ListServer(command.Lister):
if c in ('User ID', 'user_id'):
columns += ('user_id',)
column_headers += ('User ID',)
+ if c in ('User Name', 'user_name'):
+ columns += ('user_name',)
+ column_headers += ('User Name',)
+ if c in ('Project Name', 'project_name'):
+ columns += ('project_name',)
+ column_headers += ('Project Name',)
if c in ('Created At', 'created_at'):
columns += ('created_at',)
column_headers += ('Created At',)
@@ -3038,6 +3054,31 @@ class ListServer(command.Lister):
else:
s.security_groups_name = []
+ # Add user_name and project_name attributes for each server
+ for s in data:
+ # Add user_name
+ if hasattr(s, 'user_id') and s.user_id:
+ try:
+ user_obj = identity_client.users.get(s.user_id)
+ s.user_name = user_obj.name
+ except Exception:
+ s.user_name = 'N/A'
+ else:
+ s.user_name = "N/A"
+
+ # Add project_name
+ project_id = getattr(s, 'project_id', None) or getattr(
+ s, 'tenant_id', None
+ )
+ if project_id:
+ try:
+ project_obj = identity_client.projects.get(project_id)
+ s.project_name = project_obj.name
+ except Exception:
+ s.project_name = 'N/A'
+ else:
+ s.project_name = "N/A"
+
# The host_status field contains the status of the compute host the
# server is on. It is only returned by the API when the nova-api
# policy allows. Users can look at the host_status field when, for
diff --git a/openstackclient/tests/unit/compute/v2/fakes.py b/openstackclient/tests/unit/compute/v2/fakes.py
index 37f93b77..9b275202 100644
--- a/openstackclient/tests/unit/compute/v2/fakes.py
+++ b/openstackclient/tests/unit/compute/v2/fakes.py
@@ -248,6 +248,8 @@ def create_one_server(attrs=None):
'id': 'flavor-id-' + uuid.uuid4().hex,
},
'OS-EXT-STS:power_state': 1,
+ 'user_id': 'user-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
}
# Overwrite default attributes.
diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py
index 0898c67b..60866f88 100644
--- a/openstackclient/tests/unit/compute/v2/test_server.py
+++ b/openstackclient/tests/unit/compute/v2/test_server.py
@@ -1295,6 +1295,8 @@ class TestServerCreate(TestServer):
'networks': {},
'image': self.image,
'flavor': self.flavor,
+ 'user_id': None,
+ 'project_id': None,
}
self.server = compute_fakes.create_one_server(attrs=attrs)
@@ -4576,6 +4578,8 @@ class _TestServerList(TestServer):
'Networks',
'Image',
'Flavor',
+ 'User Name',
+ 'Project Name',
)
columns_long = (
'ID',
@@ -4593,6 +4597,8 @@ class _TestServerList(TestServer):
'Host',
'Properties',
'Scheduler Hints',
+ 'User Name',
+ 'Project Name',
)
columns_all_projects = (
'ID',
@@ -4602,6 +4608,8 @@ class _TestServerList(TestServer):
'Image',
'Flavor',
'Project ID',
+ 'User Name',
+ 'Project Name',
)
def setUp(self):
@@ -4651,6 +4659,28 @@ class _TestServerList(TestServer):
self.servers = self.setup_sdk_servers_mock(3)
self.compute_client.servers.return_value = self.servers
+ # Keystone Identity에서 사용자 및 프로젝트 조회를 위한 모킹 설정
+ # 실제 OpenStack에서는 Identity API를 호출해
+ # 사용자 이름과 프로젝트 이름을 가져오지만, 테스트에서는 모킹함
+ User = collections.namedtuple('User', 'id name')
+ Project = collections.namedtuple('Project', 'id name')
+
+ # 서로 다른 user_id와 project_id에 대해 각각 다른 객체를 반환하도록 side_effect를 설정
+ def get_user_side_effect(user_id):
+ # 어떤 user_id가 들어와도 해당 ID를 가진 User 객체를 생성하지만
+ # 이름은 항상 'test-user'로 고정
+ return User(id=user_id, name='test-user')
+
+ def get_project_side_effect(project_id):
+ # 어떤 project_id가 들어와도 해당 ID를 가진 Project 객체를 생성하지만
+ # 이름은 항상 'test-project'로 고정
+ return Project(id=project_id, name='test-project')
+
+ # Identity 클라이언트의 users.get()과 projects.get() 메서드를
+ # 위에서 정의한 side_effect 함수로 모킹 설정
+ self.identity_client.users.get.side_effect = get_user_side_effect
+ self.identity_client.projects.get.side_effect = get_project_side_effect
+
# Get the command object to test
self.cmd = server.ListServer(self.app, None)
@@ -4682,6 +4712,8 @@ class TestServerList(_TestServerList):
# Image will be an empty string if boot-from-volume
self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
self.flavor.name,
+ 'test-user',
+ 'test-project',
)
for s in self.servers
)
@@ -4742,6 +4774,8 @@ class TestServerList(_TestServerList):
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
format_columns.DictListColumn(None),
+ 'test-user',
+ 'test-project',
)
for s in self.servers
)
@@ -4775,6 +4809,8 @@ class TestServerList(_TestServerList):
self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
self.flavor.name,
s.project_id,
+ 'test-user',
+ 'test-project',
)
for s in self.servers
)
@@ -4857,6 +4893,8 @@ class TestServerList(_TestServerList):
# Image will be an empty string if boot-from-volume
s.image['id'] if s.image else server.IMAGE_STRING_FOR_BFV,
s.flavor['id'],
+ 'test-user',
+ 'test-project',
)
for s in self.servers
)
@@ -4888,6 +4926,8 @@ class TestServerList(_TestServerList):
# Image will be an empty string if boot-from-volume
s.image['id'] if s.image else server.IMAGE_STRING_FOR_BFV,
s.flavor['id'],
+ 'test-user',
+ 'test-project',
)
for s in self.servers
)
@@ -5259,6 +5299,8 @@ class TestServerList(_TestServerList):
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
format_columns.DictListColumn(s.scheduler_hints),
+ 'test-user',
+ 'test-project',
)
for s in self.servers
)
@@ -5315,6 +5357,8 @@ class TestServerList(_TestServerList):
server.HostColumn(getattr(s, 'hypervisor_hostname')),
format_columns.DictColumn(s.metadata),
format_columns.DictListColumn(s.scheduler_hints),
+ 'test-user',
+ 'test-project',
s.host_status,
)
for s in servers
@@ -5337,6 +5381,8 @@ class TestServerListV273(_TestServerList):
'Networks',
'Image',
'Flavor',
+ 'User Name',
+ 'Project Name',
)
columns_long = (
'ID',
@@ -5353,6 +5399,8 @@ class TestServerListV273(_TestServerList):
'Host',
'Properties',
'Scheduler Hints',
+ 'User Name',
+ 'Project Name',
)
def setUp(self):
@@ -5395,6 +5443,8 @@ class TestServerListV273(_TestServerList):
# Image will be an empty string if boot-from-volume
self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
self.flavor.name,
+ 'test-user',
+ 'test-project',
)
for s in self.servers
)
@@ -5543,6 +5593,8 @@ class TestServerListV273(_TestServerList):
server.AddressesColumn(None),
'',
'',
+ 'N/A',
+ 'test-project',
)
self.assertEqual(expected_row, partial_server)
@@ -8496,6 +8548,7 @@ class TestServerShow(TestServer):
'flavor': {'id': self.flavor.id},
'tenant_id': 'tenant-id-xxx',
'addresses': {'public': ['10.20.30.40', '2001:db8::f']},
+ 'user_id': None,
}
self.compute_client.get_server_diagnostics.return_value = {
'test': 'test'