Compare commits

6 Commits

Author SHA1 Message Date
8a45c99efb Merge branch 'main' of https://github.com/OVERLORD7F/SVMU 2025-09-25 16:13:15 +03:00
9592382966 fixed #30 2025-09-25 16:12:52 +03:00
754db8ff41 Update README.md 2025-09-25 13:32:16 +03:00
d6642c62f4 Fix #29 2025-09-25 12:59:53 +03:00
dfff6c74e6 changed ico 2025-09-25 12:36:29 +03:00
22b746e7a8 SVMU exe logos 2025-09-25 11:55:27 +03:00
4 changed files with 30 additions and 71 deletions

View File

@@ -7,7 +7,8 @@ Written in python, uses [SpaceVM API](https://spacevm.ru/docs/6.5/api/) to colle
>[!NOTE]
>_This utility is focused on managing virtual disks_<br>
>_Works with SpaceVM 6.5.5 / 6.5.6 / 6.5.7_
>_Works with SpaceVM 6.5.5 / 6.5.6 / 6.5.7_ <br>
> [:file_folder:_Repo Mirror Available Here_:clipboard:](https://gt.7fproject.com/OVERLORD/SVMU)
# Requirements
- Fully setup SpaceVM cluster with VMs
@@ -17,8 +18,9 @@ Written in python, uses [SpaceVM API](https://spacevm.ru/docs/6.5/api/) to colle
> Utility is only tested on Windows 10
- For Windows 10 - [New Microsoft Terminal](https://github.com/microsoft/terminal) is highly recommended (correct colors, menus, etc)
# Utility usage
Clone repository or use compiled .exe from [Releases Tab](https://github.com/OVERLORD7F/SpaceVM_VM_Utility/releases)
# Utility usage options:
+ Clone repository, run `main.py` using python
+ Use precompiled .exe from [Releases Tab](https://github.com/OVERLORD7F/SpaceVM_VM_Utility/releases)
## Config / Profile File
Directory _./profiles_ contains all configured profiles with necessary data for utility.

BIN
assets/images/SVMU.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
assets/images/SVMU.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -53,7 +53,7 @@ def config_menu(base_url, api_key, config_relative_path):
needs_reload = True
if sub_choice == "7":
change_vm_uuids(config_relative_path)
change_vm_uuids(config_relative_path, base_url, api_key)
needs_reload = True
if sub_choice == "8":
@@ -137,27 +137,24 @@ def config_import(config_relative_path):
def change_startup_option(config_relative_path):
cls()
#console.print("[yellow bold]Skip start-up splash ?")
# Ask the user once and normalize the answer
new_value = Prompt.ask("[yellow bold]Skip start-up splash ?[/]", choices=["Y", "N"], default="N", case_sensitive=False)
if new_value == "Y" or new_value == "y":
if new_value.lower() == "y":
startup_option = "yes"
if new_value == "N" or new_value == "n":
startup_option = "no"
new_value = Prompt.ask("[yellow bold]Skip start-up splash ?[/]", choices=["Y", "N"], default="N", case_sensitive=False)
if new_value == "Y" or new_value == "y":
startup_option = "yes"
if new_value == "N" or new_value == "n":
else:
startup_option = "no"
config = configparser.ConfigParser()
config.read(config_relative_path)
if config.has_section('General'):
config.set('General', 'skip_startup_splash', startup_option)
# Ensure General section exists so we can write the option
if not config.has_section('General'):
config.add_section('General')
config.set('General', 'skip_startup_splash', startup_option)
with open(config_relative_path, 'w') as config_file:
config.write(config_file)
console.print(f"[green bold]Option set to: {new_value}")
else:
console.print("[red bold]No section 'General' in config file")
def change_data_pool(base_url, api_key, config_relative_path): #change selected data pool in config
cls()
@@ -186,7 +183,7 @@ def change_iso_uuid(config_relative_path):
print("No 'VM_Options' section in config file..")
config_show(config_relative_path)
def change_vm_uuids(config_relative_path): #change selected VM uuids in config
def change_vm_uuids(config_relative_path, base_url, api_key): #change selected VM uuids in config
config = configparser.ConfigParser()
config.read(config_relative_path)
# Remove old VM_List section if it exists, then add a fresh one
@@ -200,6 +197,11 @@ def change_vm_uuids(config_relative_path): #change selected VM uuids in config
vm_input = console.input("[bold yellow]>> [/]" )
if not vm_input:
break
# validate only the entered VM UUID via get_vm_name
vm_name = get_vm_name(base_url, "jwt " + api_key, vm_input)
if not vm_name:
console.print("[red bold]Invalid VM UUID (not found)")
continue
x += 1
config.set('VM_List', f'uuid_{x}', vm_input)
@@ -211,56 +213,6 @@ def change_vm_uuids(config_relative_path): #change selected VM uuids in config
config_show(config_relative_path)
def config_edit(config_relative_path):
read_input = Prompt.ask("[bold yellow]Create new config file?[/]", choices=["Y", "N"], default="N", case_sensitive=False)
menu_choice = str(read_input)
if menu_choice == "Y" or menu_choice == "y":
base_url = input("Type SpaceVM Controller IP: ")
while check_ping(base_url) != True:
base_url = console.input("[bold red]No response.\nCheck and type SpaceVM Controller IP again: [/]")
api_key = input("Type your API Key: ")
while check_api_key(base_url, "jwt " + api_key) != 200:
api_key = console.input("[bold red]Check and type SpaceVM Controller API Key again: [/]")
show_data_pools(base_url, "jwt " + api_key)
data_pool_uuid = input("Type Data Pool UUID you wish to use: ")
config = configparser.ConfigParser()
config["General"] = {
"controller_ip": base_url,
"api_key": api_key,
"skip_startup_splash": "no",
}
config["Data_Pool"] = {"data_pool_uuid": data_pool_uuid}
#disk_interface=input("Specify preffered disk interface (virtio / ide / scsi / sata): ")
#preallocation=input("Specify allocation type for virtual disks (none / falloc / full / metadata): ")
#iso_uuid=input("Specify ISO uuid you wish to auto-mount during operations(none - skip this step): ")
#config["VM_Options"] = {
# "disk_interface": disk_interface,
# "preallocation": preallocation,
# "iso_uuid": iso_uuid
#}
with open(config_relative_path, "w") as configfile: #writing everything from above to config file
config.write(configfile)
print("Type VM UUIDs one by one (input ENTER to stop)")
with open(config_relative_path, "a") as file:
file.write("[VM_List]\n") #manually writing section for VMs
vm_input = []
x = 0
while vm_input != "":
vm_input = input(">> ")
if vm_input:
x += 1
file.write(f"uuid_{x} = {vm_input}\n")
console.print("[green bold]VM UUIDs have been written in config :pencil:")
console.print("[green bold]Configuration completed ! :white_check_mark:")
Prompt.ask("[green_yellow bold]Press ENTER to proceed.. :right_arrow_curving_down:")
cls()
def check_config(config_relative_path):
"""Check if config exists and is valid"""
# Only check if the file is empty and needs to be removed
@@ -341,6 +293,11 @@ def create_new_profile():
vm_input = console.input("[bold yellow]>> [/]")
if not vm_input:
break
# validate only the vm_input by fetching VM name
vm_name = get_vm_name(base_url, "jwt " + api_key, vm_input)
if not vm_name:
console.print("[red bold]Invalid VM UUID (not found)")
continue
x += 1
file.write(f"uuid_{x} = {vm_input}\n")