diff --git a/zvmsdk/database.py b/zvmsdk/database.py index 850be8eda..a868833f8 100755 --- a/zvmsdk/database.py +++ b/zvmsdk/database.py @@ -2271,6 +2271,32 @@ def delete_fcp_template(self, template_id): "template, template_sp_mapping and " "template_fcp_mapping tables" % template_id) + def get_wwpn_phy_from_pchids(self, pchids): + """Get wwpn_phy info of multiple pchids. + + :param pchids: (list) Physical channel ID list of FCP devices + + :return pchid_to_phy_wwpn_dict: (dict) PCHID as key, Physical WWPN as value + for example: + { + '02E4': 'c05076de33002e41', + '021C': 'c05076de330021c1' + } + """ + pchid_to_phy_wwpn_dict = {} + with get_fcp_conn() as conn: + result = conn.execute( + "SELECT DISTINCT pchid, wwpn_phy " + "FROM fcp " + "WHERE pchid IN (%s)" % + ','.join('?' * len(pchids)), + pchids) + + raw = result.fetchall() + for item in raw: + pchid_to_phy_wwpn_dict.update({item['pchid'].upper(): item['wwpn_phy']}) + return pchid_to_phy_wwpn_dict + class ImageDbOperator(object): diff --git a/zvmsdk/tests/unit/test_volumeop.py b/zvmsdk/tests/unit/test_volumeop.py index 420857369..707fad68e 100755 --- a/zvmsdk/tests/unit/test_volumeop.py +++ b/zvmsdk/tests/unit/test_volumeop.py @@ -1408,7 +1408,7 @@ def test_get_fcp_templates_details(self, mock_sync, mock_raw, mock_get_zhypinfo, template_id_2), # unallocated_but_active ('1b01', '', 0, 0, 'c05076de3300d83c', - 'c05076de33002641', '35', '02a4', 'active', 'owner2', + 'c05076de33002642', '35', '02a4', 'active', 'owner2', ''), ('1b02', 'user2', 1, 1, 'c05076de3300d83c', 'c05076de33002641', '27', '02e4', 'active', '', @@ -1420,7 +1420,7 @@ def test_get_fcp_templates_details(self, mock_sync, mock_raw, mock_get_zhypinfo, template_id_2), # unallocated_but_active ('1c02', '', 0, 0, 'c05076de3300d83c', - 'c05076de33002641', '35', '02a4', 'active', 'owner3', + 'c05076de33002642', '35', '02a4', 'active', 'owner3', '')] fcp_id_list_1 = [fcp_info[0] for fcp_info in fcp_info_list_1] fcp_id_list_2 = [fcp_info[0] for fcp_info in fcp_info_list_2] @@ -1458,6 +1458,7 @@ def test_get_fcp_templates_details(self, mock_sync, mock_raw, mock_get_zhypinfo, "lpar": "fake_lpar_name", "hypervisor_hostname": "fake_hypervisor_hostname", "pchids": ["02E4"], + 'pchid_to_phy_wwpn': {'02E4': 'c05076de33002641'}, "statistics": { 0: { "total": "1A00, 1F00", @@ -1505,6 +1506,8 @@ def test_get_fcp_templates_details(self, mock_sync, mock_raw, mock_get_zhypinfo, "lpar": "fake_lpar_name", "hypervisor_hostname": "fake_hypervisor_hostname", "pchids": ["02A4", "02E4"], + 'pchid_to_phy_wwpn': {'02A4': 'c05076de33002642', + '02E4': 'c05076de33002641'}, "statistics": { 0: { "total": "1B00", @@ -1553,6 +1556,8 @@ def test_get_fcp_templates_details(self, mock_sync, mock_raw, mock_get_zhypinfo, "lpar": "fake_lpar_name", "hypervisor_hostname": "fake_hypervisor_hostname", "pchids": ["02A4", "02E4"], + 'pchid_to_phy_wwpn': {'02A4': 'c05076de33002642', + '02E4': 'c05076de33002641'}, "statistics": { 0: { "total": "1C00, 1C02", @@ -1572,6 +1577,20 @@ def test_get_fcp_templates_details(self, mock_sync, mock_raw, mock_get_zhypinfo, 'pchids': {'02E4': '27', '02A4': '35'}} } } + expected_4 = { + "id": template_id_1, + "name": "name1", + "description": "desc1", + "host_default": True, + "storage_providers": ["sp1"], + 'min_fcp_paths_count': 2, + "cpc_sn": "fake_cpc_sn", + "cpc_name": "fake_cpc_name", + "lpar": "fake_lpar_name", + "hypervisor_hostname": "fake_hypervisor_hostname", + "pchids": ["02E4"], + 'pchid_to_phy_wwpn': {'02E4': 'c05076de33002641'} + } expected_all = { "fcp_templates": [expected_1, expected_2, expected_3]} result_all = self.fcpops.get_fcp_templates_details(raw=False, @@ -1595,6 +1614,14 @@ def test_get_fcp_templates_details(self, mock_sync, mock_raw, mock_get_zhypinfo, sync_with_zvm=True) mock_raw.assert_called() mock_sync.assert_called() + + # case4: get_fcp_templates_details when statistics is False + result = self.fcpops.get_fcp_templates_details(template_id_list=[template_id_1], + raw=False, + statistics=False, + sync_with_zvm=False) + expected = {'fcp_templates': [expected_4]} + self.assertDictEqual(result, expected) finally: self.db_op.bulk_delete_from_fcp_table(fcp_id_list_1) self.db_op.bulk_delete_from_fcp_table(fcp_id_list_2) diff --git a/zvmsdk/volumeop.py b/zvmsdk/volumeop.py index a375c8749..b17c48589 100755 --- a/zvmsdk/volumeop.py +++ b/zvmsdk/volumeop.py @@ -1908,19 +1908,10 @@ def get_fcp_templates_details(self, template_id_list=None, raw=False, if template_id in statistics_usage: base_info.update( {"statistics": statistics_usage[template_id]}) - # Add pchids info - pchids = [] - for _, path_detail in statistics_usage[template_id].items(): - if path_detail['pchids']: - pchids.extend(list(path_detail['pchids'].keys())) - pchids = list(set(pchids)) - pchids.sort() - base_info.update({"pchids": pchids}) else: # some templates do not have fcp devices or do not have # valid fcp in zvm, so do not have statistics_usage data base_info.update({"statistics": {}}) - base_info.update({"pchids": []}) # after join statistics info, template_info format is like this: # { # temlate_id: { @@ -1951,6 +1942,12 @@ def get_fcp_templates_details(self, template_id_list=None, raw=False, # Get hypervisor_hostname hypervisor_hostname = zvmutils.get_zvm_name() for item in ret: + # Add pchids info + pchids = self.db.get_pchids_by_fcp_template(item["id"]) + pchids.sort() + item["pchids"] = pchids + # Add pchid_to_phy_wwpn info + item["pchid_to_phy_wwpn"] = self.db.get_wwpn_phy_from_pchids(pchids) # Add cpc_sn info item["cpc_sn"] = cpc_sn # Add cpc_name info