Skip to content

Commit 36bb175

Browse files
authored
Merge pull request #447 from mincheol-jeong/ablestack-diplo
wwn 개발 완료
2 parents 5ea857b + 7c3f158 commit 36bb175

File tree

3 files changed

+181
-26
lines changed

3 files changed

+181
-26
lines changed

main.html

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@
7575
type="button">외부 스토리지 동기화</button>
7676
</li>
7777
<li class="pf-c-divider" role="separator"></li>
78+
<li>
79+
<button class="pf-c-dropdown__menu-item" type="button"
80+
id="menu-item-gfs-hba-wwn-list">WWN 목록 조회</button>
81+
</li>
82+
<li class="pf-c-divider" role="separator"></li>
7883
<li id="gfs-host-remove">
7984
<button id="button-gfs-host-remove"
8085
class="pf-c-dropdown__menu-item"
@@ -225,6 +230,11 @@
225230
id="menu-item-set-hci-clvm-disk-info">CLVM 디스크 정보</button>
226231
</li>
227232
<li class="pf-c-divider" role="separator"></li>
233+
<li>
234+
<button class="pf-c-dropdown__menu-item" type="button"
235+
id="menu-item-hci-hba-wwn-list">WWN 목록 조회</button>
236+
</li>
237+
<li class="pf-c-divider" role="separator"></li>
228238
<li>
229239
<button class="pf-c-dropdown__menu-item pf-m-disabled" type="button"
230240
id="menu-item-set-auto-shutdown-step-two">전체 시스템 자동 종료</button>
@@ -1938,6 +1948,38 @@ <h1 class="pf-c-modal-box__title"><span class="pf-c-modal-box__title-text">외
19381948
</div>
19391949
</div>
19401950
<!-- 외부 스토리지 동기화 : Modal 영역 끝 -->
1951+
<!-- WWN 목록 조회 : Modal 영역 시작 -->
1952+
<div id="div-modal-hba-wwn-list" class="pf-c-backdrop" style="display:none">
1953+
<div class="pf-l-bullseye">
1954+
<div class="pf-c-modal-box pf-m-md" role="dialog" aria-modal="true" aria-label="GFS CLVM Disk Info">
1955+
<button id="button-close-modal-hba-wwn-list" aria-disabled="false" aria-label="Close"
1956+
class="pf-c-button pf-m-plain" type="button">
1957+
<i class="fas fa-times" aria-hidden="true"></i>
1958+
</button>
1959+
<header class="pf-c-modal-box__header">
1960+
<h1 class="pf-c-modal-box__title">
1961+
<span class="pf-c-modal-box__title-text">WWN 목록</span>
1962+
</h1>
1963+
</header>
1964+
<div class="pf-c-modal-box__body">
1965+
<form novalidate class="pf-c-form pf-m-horizontal">
1966+
<section class="pf-c-form__section">
1967+
<div class="pf-c-form__group" style="display: block;">
1968+
<div class="pf-c-form__group-control pf-m-stack" id="hba-wwn-list"
1969+
style="margin-top:8px;max-height: 400px;overflow-y: auto;">
1970+
</div>
1971+
</div>
1972+
</section>
1973+
</form>
1974+
</div>
1975+
<footer class="pf-c-modal-box__footer">
1976+
<button id="button-execution-modal-hba-wwn-list" aria-disabled="false"
1977+
class="pf-c-button pf-m-primary" type="button" data-ouia-safe="true">확인</button>
1978+
</footer>
1979+
</div>
1980+
</div>
1981+
</div>
1982+
<!-- WWN 목록 조회 : Modal 영역 끝 -->
19411983
<!-- 모달 영역 끝 -->
19421984

19431985
<!-- 클라우드센터VM 용량 변경에 관한 modal : ./src/features/cloud-vm-change.html을 내용으로 load -->

python/clvm/disk_manage.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import subprocess
88
import os
99
import json
10+
import concurrent.futures
1011

1112
from ablestack import *
1213

@@ -334,6 +335,40 @@ def delete_gfs(disks, gfs_name, lv_name, vg_name):
334335
except Exception as e:
335336
ret = createReturn(code=500, val=f"Error: {str(e)}")
336337
return print(json.dumps(json.loads(ret), indent=4))
338+
339+
def list_hba_wwn():
340+
try:
341+
hosts = json_data["clusterConfig"]["hosts"]
342+
343+
def get_hba_wwn(host):
344+
"""개별 호스트에서 HBA WWN 정보를 가져오는 내부 함수"""
345+
try:
346+
ip = host["ablecube"]
347+
hostname = host["hostname"]
348+
ssh_client = connect_to_host(ip)
349+
350+
hba_check = run_command("lspci | grep -i fibre", ssh_client)
351+
wwn_list = []
352+
if hba_check:
353+
wwn_list = run_command("cat /sys/class/fc_host/host*/port_name", ssh_client).split()
354+
355+
ssh_client.close()
356+
return {"hostname": hostname, "wwn": wwn_list}
357+
358+
except Exception as e:
359+
return {"hostname": host["hostname"], "wwn": [], "error": str(e)}
360+
361+
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
362+
results = list(executor.map(get_hba_wwn, hosts))
363+
364+
ret = createReturn(code=200, val=results)
365+
print(json.dumps(json.loads(ret), indent=4))
366+
367+
except Exception as e:
368+
ret = createReturn(code=500, val=f"Error: {str(e)}")
369+
print(json.dumps(json.loads(ret), indent=4))
370+
371+
337372
def main():
338373
parser = argparse.ArgumentParser(description="Cluster configuration script")
339374

@@ -342,6 +377,7 @@ def main():
342377
parser.add_argument('--list-gfs', action='store_true', help='List GFS Volume Groups.')
343378
parser.add_argument('--delete-clvm', action='store_true', help='Delete CLVM Volume Group.')
344379
parser.add_argument('--delete-gfs', action='store_true', help='Delete GFS Disk.')
380+
parser.add_argument('--list-hba-wwn', action='store_true', help='List HBA WWN.')
345381
parser.add_argument('--disks', help='Comma separated list of disks to use.')
346382
parser.add_argument('--gfs-name', help='GFS Name')
347383
parser.add_argument('--lv-names', help='Serveral LV Name.')
@@ -384,5 +420,8 @@ def main():
384420
disks = args.disks.split(',')
385421
delete_gfs(disks, args.gfs_name, args.lv_names, args.vg_names)
386422

423+
if args.list_hba_wwn:
424+
list_hba_wwn()
425+
387426
if __name__ == "__main__":
388427
main()

src/features/main.js

Lines changed: 100 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -141,32 +141,35 @@ $(document).ready(function(){
141141
cockpit.spawn(['/usr/share/cockpit/ablestack/python/license/register_license.py', '--status'])
142142
.then(function(data) {
143143
const result = JSON.parse(data);
144-
if (result.code === '200') {
145-
const licenseInfo = result.val;
146-
$('#license-status').text('활성화');
147-
$('#license-expired').text(licenseInfo.expired);
148-
$('#license-issued').text(licenseInfo.issued); // 시작일 표시 추가
149-
$('#license-file-path').text(licenseInfo.file_path);
150-
} else {
151-
$('#license-status').text('비활성화');
152-
$('#license-expired').text('-');
153-
$('#license-issued').text('-'); // 시작일 표시 추가
154-
$('#license-file-path').text('-');
155-
}
144+
145+
// 라이센스 상태에 따른 UI 업데이트
146+
updateLicenseUI(result);
147+
148+
// 라이센스 버튼은 항상 표시되도록 수정
149+
$('#button-open-modal-license-register').show();
150+
151+
return result;
156152
})
157153
.catch(function(error) {
158-
console.error('라이센스 상태 확인 중 오류:', error);
159-
$('#license-status').text('오류');
160-
$('#license-expired').text('-');
161-
$('#license-issued').text('-'); // 시작일 표시 추가
162-
$('#license-file-path').text('-');
154+
console.error("라이센스 상태 확인 실패:", error);
155+
// 에러 시에도 버튼은 표시
156+
$('#button-open-modal-license-register').show();
157+
158+
// 에러 UI 업데이트
159+
$('#div-license-description').html(`
160+
<div class="license-info error">
161+
<p><i class="fas fa-exclamation-triangle" style="color: var(--pf-global--danger-color--100);"></i> 라이센스 상태를 확인할 수 없습니다.</p>
162+
<p>시스템 오류가 발생했습니다.</p>
163+
</div>
164+
`);
165+
throw error;
163166
});
164167
}
165168

166169
// 라이센스 상태에 따른 UI 업데이트 함수
167170
function updateLicenseUI(result) {
168171
let licenseDescription = '';
169-
172+
170173
if(result.code == "200" && result.val && result.val.status === 'active') {
171174
// 유효한 라이센스가 있는 경우
172175
licenseDescription = `
@@ -195,7 +198,7 @@ $(document).ready(function(){
195198
</div>
196199
`;
197200
}
198-
201+
199202
$('#div-license-description').html(licenseDescription);
200203
}
201204

@@ -235,7 +238,7 @@ $(document).ready(function(){
235238
reader.onload = function(e) {
236239
const fileContent = e.target.result;
237240
const base64Content = btoa(fileContent);
238-
241+
239242
// 라이센스 등록 API 호출
240243
cockpit.spawn([
241244
'python3',
@@ -2332,15 +2335,75 @@ function setDiskAction(type, action){
23322335
</div>
23332336
`;
23342337
}
2335-
} else {
2338+
}else {
23362339
output = '데이터가 존재하지 않습니다.<br>';
23372340
}
23382341

23392342
$('#gfs-disk-delete-list').append(output);
23402343
});
23412344

2345+
}else if (type == "hba" && action == "list") {
2346+
var cmd = ["python3", pluginpath + "/python/clvm/disk_manage.py", "--list-hba-wwn"];
2347+
2348+
cockpit.spawn(cmd).then(function(data) {
2349+
// 초기화
2350+
$('#hba-wwn-list').empty();
2351+
2352+
// JSON 데이터 파싱
2353+
var result = JSON.parse(data);
2354+
2355+
// 결과 리스트 가져오기
2356+
var wwnList = result.val;
2357+
2358+
// 테이블 생성
2359+
var output = `
2360+
<table border="1" style="width: 100%; border-collapse: collapse; text-align: left;">
2361+
<thead>
2362+
<tr>
2363+
<th style="padding: 8px; background-color: #f2f2f2;">호스트명</th>
2364+
<th style="padding: 8px; background-color: #f2f2f2;">WWN</th>
2365+
</tr>
2366+
</thead>
2367+
<tbody>
2368+
`;
2369+
2370+
if (wwnList.length > 0) {
2371+
// 데이터를 순회하면서 테이블 행 추가
2372+
for (var i = 0; i < wwnList.length; i++) {
2373+
var wwn = wwnList[i];
2374+
output += `
2375+
<tr>
2376+
<td style="padding: 8px; border-bottom: 1px solid #ddd;">${wwn.hostname}</td>
2377+
<td style="padding: 8px; border-bottom: 1px solid #ddd;">
2378+
${wwn.wwn.join('<br>')}
2379+
</td>
2380+
</tr>
2381+
`;
2382+
}
2383+
} else {
2384+
output += `
2385+
<tr>
2386+
<td colspan="2" style="padding: 8px; text-align: center;">데이터가 존재하지 않습니다.</td>
2387+
</tr>
2388+
`;
2389+
}
2390+
2391+
// 테이블 닫기
2392+
output += `
2393+
</tbody>
2394+
</table>
2395+
`;
2396+
2397+
// 출력 데이터 추가
2398+
$('#hba-wwn-list').append(output);
2399+
2400+
}).catch(function() {
2401+
createLoggerInfo("setDiskAction error");
2402+
});
23422403
}
2404+
23432405
}
2406+
23442407
$('#menu-item-set-gfs-clvm-disk-add').on('click',function(){
23452408
setDiskAction("clvm","add")
23462409
$('#div-modal-clvm-disk-add').show();
@@ -2352,6 +2415,9 @@ $('#menu-item-set-hci-clvm-disk-add').on('click',function(){
23522415
$('#button-close-modal-clvm-disk-add, #button-cancel-modal-clvm-disk-add').on('click',function(){
23532416
$('#div-modal-clvm-disk-add').hide();
23542417
});
2418+
$('#button-close-modal-hba-wwn-list, #button-execution-modal-hba-wwn-list').on('click', function(){
2419+
$('#div-modal-hba-wwn-list').hide();
2420+
})
23552421
$('#button-execution-modal-clvm-disk-add').on('click',function(){
23562422
$('#div-modal-clvm-disk-add').hide();
23572423
$('#div-modal-spinner-header-txt').text("CLVM 디스크 논리 볼륨을 구성 중입니다.")
@@ -2446,13 +2512,21 @@ $('#div-modal-clvm-disk-delete').on('change', 'input[type=checkbox][name="form-c
24462512
$('#button-execution-modal-clvm-disk-delete').prop('disabled', !isChecked);
24472513
});
24482514
$('#menu-item-set-gfs-clvm-disk-info').on('click',function(){
2449-
setDiskAction("clvm", "list")
2515+
setDiskAction("clvm", "list");
24502516
$('#div-modal-clvm-disk-info').show();
24512517
});
24522518
$('#menu-item-set-hci-clvm-disk-info').on('click',function(){
2453-
setDiskAction("clvm", "list")
2519+
setDiskAction("clvm", "list");
24542520
$('#div-modal-clvm-disk-info').show();
24552521
});
2522+
$('#menu-item-hci-hba-wwn-list').on('click',function(){
2523+
setDiskAction("hba", "list");
2524+
$('#div-modal-hba-wwn-list').show();
2525+
});
2526+
$('#menu-item-gfs-hba-wwn-list').on('click', function(){
2527+
setDiskAction("hba", "list");
2528+
$('#div-modal-hba-wwn-list').show();
2529+
});
24562530
$('#button-execution-modal-clvm-disk-info, #button-close-modal-clvm-disk-info').on('click',function(){
24572531
$('#div-modal-clvm-disk-info').hide();
24582532
});
@@ -3138,7 +3212,7 @@ function updateLicenseStatus() {
31383212
.then(function(data) {
31393213
const result = JSON.parse(data);
31403214
let licenseDescription = '';
3141-
3215+
31423216
if(result.code == "200" && result.val && result.val.status === 'active') {
31433217
// 유효한 라이센스가 있는 경우
31443218
licenseDescription = `
@@ -3167,7 +3241,7 @@ function updateLicenseStatus() {
31673241
</div>
31683242
`;
31693243
}
3170-
3244+
31713245
$('#div-license-description').html(licenseDescription);
31723246
})
31733247
.catch(function(error) {
@@ -3250,7 +3324,7 @@ function initializeLicenseHandlers() {
32503324
reader.onload = function(e) {
32513325
const fileContent = e.target.result;
32523326
const base64Content = btoa(fileContent);
3253-
3327+
32543328
// 라이센스 등록 API 호출
32553329
cockpit.spawn([
32563330
'python3',

0 commit comments

Comments
 (0)