|
@@ -0,0 +1,315 @@ |
|
|
|
|
|
# -*- encoding: utf-8 -*- |
|
|
|
|
|
import PySimpleGUI as sg |
|
|
|
|
|
import ovh |
|
|
|
|
|
|
|
|
|
|
|
client = ovh.Client() |
|
|
|
|
|
service = client.get('/cloud/project')[0] |
|
|
|
|
|
service_url = f'/cloud/project/{service}' |
|
|
|
|
|
|
|
|
|
|
|
# regions = [f['region'] for f in flavors if f['name'] == 's1-2'] |
|
|
|
|
|
regions = ['GRA7', 'SBG5', 'DE1', 'UK1', 'BHS5'] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_flavor_id(region, name='s1-2'): |
|
|
|
|
|
flavors = client.get(service_url + '/flavor') |
|
|
|
|
|
flavorId = [f['id'] for f in flavors if f['name'] == name and f['region']==region][0] |
|
|
|
|
|
return flavorId |
|
|
|
|
|
|
|
|
|
|
|
def get_image_id(region, name='Ubuntu 20.04'): |
|
|
|
|
|
images = client.get(service_url + '/image') |
|
|
|
|
|
imageId = [i['id'] for i in images if i['name']==name and i['region']==region][0] |
|
|
|
|
|
return imageId |
|
|
|
|
|
|
|
|
|
|
|
def get_eleves(): |
|
|
|
|
|
ovh_ssh_keys = client.get(service_url + '/sshkey') |
|
|
|
|
|
liste_eleves = [(k['id'], k['name'].split('_')[1], k['publicKey']) |
|
|
|
|
|
for k in ovh_ssh_keys |
|
|
|
|
|
if k['name'].startswith('ssh_')] |
|
|
|
|
|
return liste_eleves |
|
|
|
|
|
|
|
|
|
|
|
def delete_eleve(eleve_id): |
|
|
|
|
|
client.delete(service_url + '/sshkey/' + eleve_id) |
|
|
|
|
|
|
|
|
|
|
|
def create_eleve(prenom, publicKey): |
|
|
|
|
|
client.post(service_url + '/sshkey', |
|
|
|
|
|
name = 'ssh_' + prenom, |
|
|
|
|
|
publicKey = publicKey |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
def get_instances(): |
|
|
|
|
|
ovh_instances = client.get(service_url + '/instance') |
|
|
|
|
|
instances = [] |
|
|
|
|
|
for i in ovh_instances: |
|
|
|
|
|
id_inst = i['id'] |
|
|
|
|
|
name = i['name'] |
|
|
|
|
|
if not name.startswith('eica-'): |
|
|
|
|
|
continue |
|
|
|
|
|
if i['ipAddresses']: |
|
|
|
|
|
ip = i['ipAddresses'][0]['ip'] |
|
|
|
|
|
else: |
|
|
|
|
|
ip = 'Waiting...' |
|
|
|
|
|
region = i['region'] |
|
|
|
|
|
status = i['status'] |
|
|
|
|
|
instances.append((id_inst, name, ip, region, status,)) |
|
|
|
|
|
return instances |
|
|
|
|
|
|
|
|
|
|
|
def create_instance(eleve_id, name, region): |
|
|
|
|
|
image_id = get_image_id(region) |
|
|
|
|
|
flavor_id = get_flavor_id(region) |
|
|
|
|
|
client.post(service_url + '/instance', |
|
|
|
|
|
name = 'eica-' + name, |
|
|
|
|
|
sshKeyId = eleve_id, |
|
|
|
|
|
flavorId = flavor_id, |
|
|
|
|
|
imageId = image_id, |
|
|
|
|
|
region = region |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
def delete_instance(instance_id): |
|
|
|
|
|
print(service_url + '/instance/' + instance_id) |
|
|
|
|
|
client.delete(service_url + '/instance/' + instance_id) |
|
|
|
|
|
|
|
|
|
|
|
def make_main_window(): |
|
|
|
|
|
liste_eleves = get_eleves() |
|
|
|
|
|
liste_instances = get_instances() |
|
|
|
|
|
col = [ |
|
|
|
|
|
[sg.Button('Ajouter', size=(12, 1))], |
|
|
|
|
|
[sg.Button('Modifier', size=(12, 1))], |
|
|
|
|
|
[sg.Button('Supprimer', size=(12, 1))], |
|
|
|
|
|
[sg.Combo(regions, size=(12, 1), default_value=regions[0], k='region')], |
|
|
|
|
|
[sg.Button('Instancier', size=(12, 1), button_color=('white', 'green'))], |
|
|
|
|
|
[sg.Button('Quitter', size=(12, 1))], |
|
|
|
|
|
] |
|
|
|
|
|
col1 = [ |
|
|
|
|
|
[sg.Table(values=liste_instances, |
|
|
|
|
|
headings=['id', 'Nom', 'Adresse IP', 'Région', 'Statut'], |
|
|
|
|
|
max_col_width=25, |
|
|
|
|
|
col_widths=[0, 15, 12, 10, 10], |
|
|
|
|
|
hide_vertical_scroll=True, |
|
|
|
|
|
background_color='light blue', |
|
|
|
|
|
text_color='black', |
|
|
|
|
|
auto_size_columns=False, |
|
|
|
|
|
justification='right', |
|
|
|
|
|
num_rows=len(liste_instances), |
|
|
|
|
|
alternating_row_color='lightyellow', |
|
|
|
|
|
key='table_instances', |
|
|
|
|
|
tooltip='Liste des instances actives')], |
|
|
|
|
|
] |
|
|
|
|
|
col2 = [ |
|
|
|
|
|
[sg.Button('Détruire', size=(12, 1), button_color=('white', 'red'))], |
|
|
|
|
|
[sg.Button('Actualiser', size=(12, 1))], |
|
|
|
|
|
] |
|
|
|
|
|
layout = [ |
|
|
|
|
|
[sg.Text('Liste des élèves')], |
|
|
|
|
|
[sg.Table(values=liste_eleves, |
|
|
|
|
|
headings=['', 'Prénom', ''], |
|
|
|
|
|
max_col_width=25, |
|
|
|
|
|
col_widths=[0, 20, 0], |
|
|
|
|
|
hide_vertical_scroll=True, |
|
|
|
|
|
background_color='light blue', |
|
|
|
|
|
text_color='black', |
|
|
|
|
|
auto_size_columns=False, |
|
|
|
|
|
justification='right', |
|
|
|
|
|
num_rows=len(liste_eleves), |
|
|
|
|
|
alternating_row_color='lightyellow', |
|
|
|
|
|
key='table_eleves', |
|
|
|
|
|
tooltip='Liste des élèves'), |
|
|
|
|
|
sg.Column(col), |
|
|
|
|
|
sg.Column(col1), |
|
|
|
|
|
sg.Column(col2)], |
|
|
|
|
|
|
|
|
|
|
|
] |
|
|
|
|
|
window = sg.Window('OVH - Gestion des instances', |
|
|
|
|
|
layout=layout, |
|
|
|
|
|
size=(900, 300), |
|
|
|
|
|
finalize=True) |
|
|
|
|
|
window.liste_eleves = liste_eleves |
|
|
|
|
|
window.liste_instances = liste_instances |
|
|
|
|
|
return window |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def make_add_window(caption, role='create', initial_values=None): |
|
|
|
|
|
if initial_values: |
|
|
|
|
|
eleve_id, prenom, pk = initial_values |
|
|
|
|
|
else: |
|
|
|
|
|
eleve_id = prenom = pk = '' |
|
|
|
|
|
layout = [ |
|
|
|
|
|
[sg.InputText(eleve_id, k='eleve_id', visible=True)], |
|
|
|
|
|
[sg.Text(text='Prénom', size=(10, 2)), sg.InputText( |
|
|
|
|
|
default_text=prenom, size=(20, 2), k='prenom')], |
|
|
|
|
|
[sg.Text(text='Clé publique', size=(10, 2)), sg.InputText( |
|
|
|
|
|
default_text=pk, size=(20, 2), k='pk')], |
|
|
|
|
|
[sg.Button('Valider', bind_return_key=True), |
|
|
|
|
|
sg.Button('Annuler', bind_return_key=True)] |
|
|
|
|
|
] |
|
|
|
|
|
window = sg.Window(caption, |
|
|
|
|
|
layout=layout, |
|
|
|
|
|
finalize=True) |
|
|
|
|
|
window.role = role |
|
|
|
|
|
return window |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
window1, window2 = make_main_window(), None |
|
|
|
|
|
|
|
|
|
|
|
while True: |
|
|
|
|
|
window, event, values = sg.read_all_windows() |
|
|
|
|
|
print(f'window : {window}, event : {event}, values : {values}') |
|
|
|
|
|
if window == window1: |
|
|
|
|
|
if event in (sg.WIN_CLOSED, 'Quitter'): |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
if event == 'Ajouter': |
|
|
|
|
|
window2 = make_add_window('Ajouter', role='create') |
|
|
|
|
|
window2.make_modal() |
|
|
|
|
|
|
|
|
|
|
|
if event == 'Supprimer': |
|
|
|
|
|
try: |
|
|
|
|
|
# dans le cas d'un tableau, la valeur est un tableau de(s) |
|
|
|
|
|
# index sélectionnés. On garde le premier quoi qu'il arrive |
|
|
|
|
|
selected_line = values['table_eleves'][0] |
|
|
|
|
|
# la colonne id est cachée au niveau de l'affichage |
|
|
|
|
|
id_eleve = window1.liste_eleves[selected_line][0] |
|
|
|
|
|
except IndexError: |
|
|
|
|
|
sg.popup_ok( |
|
|
|
|
|
'Veuillez sélectionner un enregistrement à supprimer') |
|
|
|
|
|
continue |
|
|
|
|
|
confirmation = sg.popup("Confirmez-vous la suppression ?", |
|
|
|
|
|
button_type=sg.POPUP_BUTTONS_OK_CANCEL, |
|
|
|
|
|
custom_text=("Oui", "Non")) |
|
|
|
|
|
if confirmation == "Non": |
|
|
|
|
|
continue |
|
|
|
|
|
sg.PopupAnimated("sablier.png") |
|
|
|
|
|
|
|
|
|
|
|
delete_eleve(id_eleve) |
|
|
|
|
|
liste_eleves = get_eleves() |
|
|
|
|
|
|
|
|
|
|
|
sg.PopupAnimated(None) |
|
|
|
|
|
window1['table_eleves'].update(values=liste_eleves, |
|
|
|
|
|
num_rows=len(liste_eleves)) |
|
|
|
|
|
window1.liste_eleves = liste_eleves |
|
|
|
|
|
|
|
|
|
|
|
if event == 'Modifier': |
|
|
|
|
|
try: |
|
|
|
|
|
# voir 'Supprimer' pour une explication |
|
|
|
|
|
selected_line = values['table_eleves'][0] |
|
|
|
|
|
id_eleve, prenom, pk = window1.liste_eleves[selected_line] |
|
|
|
|
|
except IndexError: |
|
|
|
|
|
sg.popup_ok( |
|
|
|
|
|
'Veuillez sélectionner un enregistrement à modifier') |
|
|
|
|
|
continue |
|
|
|
|
|
window2 = make_add_window('Modifier', |
|
|
|
|
|
initial_values=[id_eleve, prenom, pk], |
|
|
|
|
|
role='modify') |
|
|
|
|
|
window2.make_modal() |
|
|
|
|
|
|
|
|
|
|
|
if event == 'Instancier': |
|
|
|
|
|
selected_lines = values['table_eleves'] |
|
|
|
|
|
if len(selected_lines) == 0: |
|
|
|
|
|
sg.popup_ok( |
|
|
|
|
|
'Veuillez sélectionner un élève') |
|
|
|
|
|
continue |
|
|
|
|
|
eleves = [] |
|
|
|
|
|
for row in selected_lines: |
|
|
|
|
|
id_eleve = window1.liste_eleves[row][0] |
|
|
|
|
|
prenom = window1.liste_eleves[row][1] |
|
|
|
|
|
eleves.append((id_eleve, prenom,)) |
|
|
|
|
|
nb_inst = len(eleves) |
|
|
|
|
|
confirmation = sg.popup(f"Confirmez-vous le lancement de {nb_inst} instances ?", |
|
|
|
|
|
button_type=sg.POPUP_BUTTONS_OK_CANCEL, |
|
|
|
|
|
custom_text=("Oui", "Non")) |
|
|
|
|
|
if confirmation == "Non": |
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
sg.PopupAnimated("sablier.png") |
|
|
|
|
|
|
|
|
|
|
|
for el in eleves: |
|
|
|
|
|
active_instances_names = [i[1].split('-')[1] for i in window1.liste_instances] |
|
|
|
|
|
if not el[1] in active_instances_names: |
|
|
|
|
|
create_instance(el[0], el[1], values['region']) |
|
|
|
|
|
|
|
|
|
|
|
liste_instances = get_instances() |
|
|
|
|
|
|
|
|
|
|
|
sg.PopupAnimated(None) |
|
|
|
|
|
|
|
|
|
|
|
window1['table_instances'].update(values=liste_instances, |
|
|
|
|
|
num_rows=len(liste_instances)) |
|
|
|
|
|
window1.liste_instances = liste_instances |
|
|
|
|
|
|
|
|
|
|
|
if event == 'Détruire': |
|
|
|
|
|
selected_lines = values['table_instances'] |
|
|
|
|
|
if len(selected_lines) == 0: |
|
|
|
|
|
sg.popup_ok( |
|
|
|
|
|
'Veuillez sélectionner une instance au moins') |
|
|
|
|
|
continue |
|
|
|
|
|
instances = [] |
|
|
|
|
|
for row in selected_lines: |
|
|
|
|
|
instances.append(window1.liste_instances[row][0]) |
|
|
|
|
|
nb_inst = len(instances) |
|
|
|
|
|
confirmation = sg.popup(f"Confirmez-vous la suppression de {nb_inst} instances ?", |
|
|
|
|
|
button_type=sg.POPUP_BUTTONS_OK_CANCEL, |
|
|
|
|
|
custom_text=("Oui", "Non")) |
|
|
|
|
|
if confirmation == "Non": |
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
sg.PopupAnimated("sablier.png") |
|
|
|
|
|
|
|
|
|
|
|
for id_inst in instances: |
|
|
|
|
|
delete_instance(id_inst) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
liste_instances = get_instances() |
|
|
|
|
|
|
|
|
|
|
|
sg.PopupAnimated(None) |
|
|
|
|
|
|
|
|
|
|
|
window1['table_instances'].update(values=liste_instances, |
|
|
|
|
|
num_rows=len(liste_instances)) |
|
|
|
|
|
window1.liste_instances = liste_instances |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if event == 'Actualiser': |
|
|
|
|
|
sg.PopupAnimated("sablier.png") |
|
|
|
|
|
liste_instances = get_instances() |
|
|
|
|
|
sg.PopupAnimated(None) |
|
|
|
|
|
window1['table_instances'].update(values=liste_instances, |
|
|
|
|
|
num_rows=len(liste_instances)) |
|
|
|
|
|
window1.liste_instances = liste_instances |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if window == window2: |
|
|
|
|
|
if event in (sg.WIN_CLOSED, 'Annuler'): |
|
|
|
|
|
window2.close() |
|
|
|
|
|
window2 = None |
|
|
|
|
|
|
|
|
|
|
|
if event == 'Valider' and window.role == 'create': |
|
|
|
|
|
prenom = values['prenom'].lower() # TODO : accents ? |
|
|
|
|
|
pk = values['pk'] |
|
|
|
|
|
create_eleve(prenom, pk) |
|
|
|
|
|
liste_eleves = get_eleves() |
|
|
|
|
|
window1['table_eleves'].update(values=liste_eleves, |
|
|
|
|
|
num_rows=len(liste_eleves)) |
|
|
|
|
|
window1.liste_eleves = liste_eleves |
|
|
|
|
|
window2.close() |
|
|
|
|
|
window2 = None |
|
|
|
|
|
|
|
|
|
|
|
if event == 'Valider' and window.role == 'modify': |
|
|
|
|
|
confirmation = sg.popup("Confirmez-vous la modification ?", |
|
|
|
|
|
button_type=sg.POPUP_BUTTONS_OK_CANCEL, |
|
|
|
|
|
custom_text=("Oui", "Non")) |
|
|
|
|
|
if confirmation == "Non": |
|
|
|
|
|
continue |
|
|
|
|
|
prenom = values['prenom'].lower() |
|
|
|
|
|
pk = values['pk'] |
|
|
|
|
|
eleve_id = values['eleve_id'] |
|
|
|
|
|
delete_eleve(eleve_id) |
|
|
|
|
|
create_eleve(prenom, pk) |
|
|
|
|
|
liste_eleves = get_eleves() |
|
|
|
|
|
window1['table_eleves'].update(values=liste_eleves, |
|
|
|
|
|
num_rows=len(liste_eleves)) |
|
|
|
|
|
window1.liste_eleves = liste_eleves |
|
|
|
|
|
window2.close() |
|
|
|
|
|
window2 = None |
|
|
|
|
|
|
|
|
|
|
|
window1.close() |
|
|
|
|
|
if window2 is not None: |
|
|
|
|
|
window2.close() |
|
|
|
|
|
|
|
|
|
|
|
print('Bye !') |