154 lines
6.7 KiB
Python
Executable File
154 lines
6.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
import curses
|
||
import subprocess
|
||
|
||
stdscr = None
|
||
|
||
def init_screen():
|
||
global stdscr
|
||
stdscr = curses.initscr()
|
||
stdscr.refresh()
|
||
curses.noecho()
|
||
curses.cbreak()
|
||
stdscr.keypad(True)
|
||
curses.curs_set(0)
|
||
|
||
init_screen()
|
||
|
||
class Menu:
|
||
def __init__(self, name, rows, begin_x):
|
||
self.name = name # заголовок окна
|
||
self.rows = rows
|
||
self.begin_x = begin_x
|
||
self.win = curses.newwin(curses.LINES, curses.COLS // 3, 0, begin_x)
|
||
self.win.box()
|
||
self.win.addstr(1, 2, self.name)
|
||
for index, row in enumerate(self.rows):
|
||
self.win.addstr(index + 3, 2, row)
|
||
self.row = 0
|
||
|
||
|
||
# рисуем первое меню
|
||
## готовим контент
|
||
bytes_list = subprocess.check_output("kubectl get ns --no-headers -o template='{{range .items}}{{.metadata.name}} {{end}}'", shell=True).split()
|
||
namespaces = [bytes_list[i].decode('utf-8') for i in range(len(bytes_list))]
|
||
## отрисовываем меню
|
||
menu1 = Menu("Namespaces", namespaces, 0)
|
||
|
||
# рисуем второе меню
|
||
## готовим контент
|
||
api_resources = ["pods", "services", "deployments", "ingresses"]
|
||
## отрисовываем меню
|
||
menu2 = Menu("API resources", api_resources, 0 + curses.COLS // 3)
|
||
|
||
# рисуем третье меню
|
||
## готовим контент
|
||
bytes_list = subprocess.check_output("kubectl get pods -n kube-system --no-headers -o template='{{range .items}}{{.metadata.name}} {{end}}'", shell=True).split()
|
||
pods = [bytes_list[i].decode('utf-8') for i in range(len(bytes_list))]
|
||
## отрисовываем меню
|
||
menu3 = Menu("Resources", pods, 0 + curses.COLS // 3 * 2)
|
||
|
||
menus = [menu1, menu2, menu3]
|
||
|
||
def run_command(command, current_menu, rows=None):
|
||
subprocess.call(command, shell=True)
|
||
init_screen()
|
||
for menu in menus:
|
||
menu.win.clear()
|
||
menu.win.box()
|
||
menu.win.addstr(1, 2, menu.name)
|
||
if rows and menu.name == "Resources":
|
||
menu.rows = rows
|
||
menu.row = 0
|
||
for index, row in enumerate(menu.rows):
|
||
menu.win.addstr(index + 3, 2, row)
|
||
menu.win.addstr(menu.row + 3, 2, menu.rows[menu.row], curses.A_REVERSE | curses.A_ITALIC)
|
||
menus[current_menu].win.addstr(1, 2, menus[current_menu].name, curses.A_REVERSE | curses.A_ITALIC)
|
||
|
||
def navigate_horizontally(direction, current_menu):
|
||
if direction == "right":
|
||
increment = 1
|
||
else:
|
||
increment = -1
|
||
menus[current_menu].win.addstr(1, 2, menus[current_menu].name)
|
||
current_menu = (current_menu + increment) % 3
|
||
menus[current_menu].win.addstr(1, 2, menus[current_menu].name, curses.A_REVERSE | curses.A_ITALIC)
|
||
return current_menu
|
||
|
||
def navigate_vertically(direction, current_menu):
|
||
if direction == "up":
|
||
increment = -1
|
||
else:
|
||
increment = 1
|
||
if current_menu == 2 and menus[2].rows[menus[2].row].startswith("No resources"):
|
||
return
|
||
menu = menus[current_menu]
|
||
menu.win.addstr(menu.row + 3, 2, menu.rows[menu.row]) # удаляем выделение с текущей строки
|
||
menu.row = (menu.row + increment) % len(menu.rows) # переходим к предыдущей/следующей строке
|
||
menu.win.addstr(menu.row + 3, 2, menu.rows[menu.row], curses.A_REVERSE | curses.A_ITALIC) # и выделяем её
|
||
if current_menu != 2: # если изменился выбор нэймспейса или апи ресурса
|
||
namespace = menus[0].rows[menus[0].row]
|
||
api_resource = menus[1].rows[menus[1].row]
|
||
command = f"kubectl get {api_resource} -n {namespace} " + "--no-headers -o template='{{range .items}}{{.metadata.name}} {{end}}'"
|
||
bytes_list = subprocess.check_output(command, shell=True).split()
|
||
resources = [bytes_list[i].decode('utf-8') for i in range(len(bytes_list))]
|
||
if not resources:
|
||
resources = [f"No resources found in {namespace} namespace.",]
|
||
run_command(command, current_menu, rows=resources)
|
||
|
||
|
||
def main(stdscr):
|
||
stdscr.refresh()
|
||
running = True
|
||
current_menu = 0
|
||
menus[current_menu].win.addstr(1, 2, menus[current_menu].name, curses.A_REVERSE | curses.A_ITALIC)
|
||
for menu in menus:
|
||
menu.win.addstr(3, 2, menu.rows[menu.row], curses.A_REVERSE | curses.A_ITALIC)
|
||
while running:
|
||
[menu.win.refresh() for menu in menus] # refresh all menus
|
||
key_pressed = stdscr.getkey()
|
||
match key_pressed:
|
||
case 'q':
|
||
running = False
|
||
case 'g':
|
||
if current_menu == 2 and not menus[2].rows[menus[2].row].startswith("No resources"):
|
||
namespace = menus[0].rows[menus[0].row]
|
||
api_resource = menus[1].rows[menus[1].row]
|
||
resource = menus[2].rows[menus[2].row]
|
||
run_command(f"kubectl -n {namespace} get {api_resource} {resource} -o yaml | batcat -l yaml --paging always --style numbers", current_menu)
|
||
case 'd':
|
||
if current_menu == 2 and not menus[2].rows[menus[2].row].startswith("No resources"):
|
||
namespace = menus[0].rows[menus[0].row]
|
||
api_resource = menus[1].rows[menus[1].row]
|
||
resource = menus[2].rows[menus[2].row]
|
||
run_command(f"kubectl -n {namespace} describe {api_resource} {resource} | batcat -l yaml --paging always --style numbers", current_menu)
|
||
case 'l':
|
||
if current_menu == 2 and not menus[2].rows[menus[2].row].startswith("No resources") and menus[1].rows[menus[1].row] == "pods":
|
||
namespace = menus[0].rows[menus[0].row]
|
||
api_resource = menus[1].rows[menus[1].row]
|
||
resource = menus[2].rows[menus[2].row]
|
||
run_command(f"kubectl -n {namespace} logs {resource} | batcat -l log --paging always --style numbers", current_menu)
|
||
case 'e':
|
||
if current_menu == 2 and not menus[2].rows[menus[2].row].startswith("No resources"):
|
||
namespace = menus[0].rows[menus[0].row]
|
||
api_resource = menus[1].rows[menus[1].row]
|
||
resource = menus[2].rows[menus[2].row]
|
||
run_command(f"kubectl edit {api_resource} -n {namespace} {resource}", current_menu)
|
||
case '\t' | "KEY_RIGHT":
|
||
current_menu = navigate_horizontally("right", current_menu)
|
||
case "KEY_BTAB" | "KEY_LEFT":
|
||
current_menu = navigate_horizontally("left", current_menu)
|
||
case "KEY_DOWN":
|
||
navigate_vertically("down", current_menu)
|
||
case "KEY_UP":
|
||
navigate_vertically("up", current_menu)
|
||
|
||
main(stdscr)
|
||
|
||
curses.nocbreak()
|
||
stdscr.keypad(False)
|
||
curses.echo()
|
||
curses.endwin()
|
||
subprocess.call(["clear"])
|
||
|