import pandas as pd
from kubernetes import client, config
import logging
import os
import sys
from tabulate import tabulate
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def load_excel_data(file_path):
"""엑셀 파일을 읽고 클러스터별 데이터를 반환"""
try:
logger.info(f"Reading Excel file: {file_path}")
xl = pd.ExcelFile(file_path)
cluster_data = {}
for sheet_name in xl.sheet_names:
df = pd.read_excel(xl, sheet_name=sheet_name)
cluster_data[sheet_name] = df[['hostname', 'ip', '구입 목적']].dropna()
return cluster_data
except Exception as e:
logger.error(f"엑셀 파일 로드 실패: {e}")
return {}
def load_csv_data(file_path):
"""CSV 파일을 읽고 단일 클러스터 데이터를 반환"""
try:
logger.info(f"Reading CSV file: {file_path}")
df = pd.read_csv(file_path)
return {"default_cluster": df[['hostname', 'ip', '구입 목적']].dropna()}
except Exception as e:
logger.error(f"CSV 파일 로드 실패: {e}")
return {}
def get_node_by_ip(v1, target_ip):
"""IP를 기반으로 노드 이름 찾기"""
nodes = v1.list_node().items
for node in nodes:
for address in node.status.addresses:
if address.type == "InternalIP" and address.address == target_ip:
return node.metadata.name
return None
def apply_node_label(v1, node_name, label_key):
"""노드에 라벨 적용"""
try:
body = {
"metadata": {
"labels": {label_key: "true"}
}
}
v1.patch_node(node_name, body)
logger.info(f"노드 {node_name}에 라벨 {label_key}=true 적용 성공")
except Exception as e:
logger.error(f"노드 {node_name} 라벨 적용 실패: {e}")
def list_node_labels(v1):
"""현재 클러스터의 노드 이름과 라벨을 표 형식으로 출력"""
try:
nodes = v1.list_node().items
if not nodes:
logger.info("노드가 없습니다.")
return
all_labels = set()
node_data = {}
for node in nodes:
node_name = node.metadata.name
labels = node.metadata.labels or {}
node_data[node_name] = labels
all_labels.update(labels.keys())
all_labels = sorted(all_labels)
table_data = []
for label in all_labels:
row = [label]
for node in nodes:
node_name = node.metadata.name
row.append(node_data[node_name].get(label, ""))
table_data.append(row)
headers = ["Label"] + [node.metadata.name for node in nodes]
print(tabulate(table_data, headers=headers, tablefmt="grid"))
except Exception as e:
logger.error(f"노드 목록 조회 실패: {e}")
def manage_node_labels(arg, kubeconfig_dir):
"""메인 함수: 인수에 따라 노드 라벨 관리 또는 목록 출력"""
if arg.lower() == "list":
kubeconfig_path = os.path.join(kubeconfig_dir, "default-kubeconfig")
if not os.path.exists(kubeconfig_path):
logger.error(f"default-kubeconfig 파일이 존재하지 않습니다: {kubeconfig_path}")
return
try:
logger.info(f"Loading kubeconfig for list: {kubeconfig_path}")
config.load_kube_config(kubeconfig_path)
v1 = client.CoreV1Api()
list_node_labels(v1)
except Exception as e:
logger.error(f"클러스터 연결 실패: {e}")
else:
file_path = arg
if file_path.endswith('.xlsx'):
cluster_data = load_excel_data(file_path)
elif file_path.endswith('.csv'):
cluster_data = load_csv_data(file_path)
else:
logger.error("지원하지 않는 파일 형식입니다. 엑셀(.xlsx) 또는 CSV(.csv) 파일을 사용하세요.")
return
if not cluster_data:
logger.error("클러스터 데이터 로드 실패. 프로그램 종료.")
return
for cluster_name, df in cluster_data.items():
kubeconfig_path = os.path.join(kubeconfig_dir, f"{cluster_name}-kubeconfig")
if not os.path.exists(kubeconfig_path):
logger.warning(f"{cluster_name}에 대한 kubeconfig 파일 없음 ({kubeconfig_path}). 건너뜀.")
continue
try:
logger.info(f"Loading kubeconfig for {cluster_name}: {kubeconfig_path}")
config.load_kube_config(kubeconfig_path)
v1 = client.CoreV1Api()
logger.info(f"{cluster_name} 클러스터 연결 성공")
except Exception as e:
logger.error(f"{cluster_name} 클러스터 연결 실패: {e}")
continue
for _, row in df.iterrows():
ip = row['ip']
purpose = row['구입 목적']
node_name = get_node_by_ip(v1, ip)
if node_name:
apply_node_label(v1, node_name, purpose)
else:
logger.warning(f"IP {ip}에 해당하는 노드 없음 ({cluster_name})")
if __name__ == "__main__":
if len(sys.argv) < 2:
logger.error("사용법: python script.py <파일 경로 또는 'list'>")
sys.exit(1)
arg = sys.argv[1]
kubeconfig_dir = "./kubeconfigs"
manage_node_labels(arg, kubeconfig_dir)```