@@ -0,0 +1,133 @@ | |||
# ---> Python | |||
# Byte-compiled / optimized / DLL files | |||
__pycache__/ | |||
*.py[cod] | |||
*$py.class | |||
.vscode/ | |||
*.sqlite3 | |||
ovh.conf | |||
# C extensions | |||
*.so | |||
# Distribution / packaging | |||
.Python | |||
build/ | |||
develop-eggs/ | |||
dist/ | |||
downloads/ | |||
eggs/ | |||
.eggs/ | |||
lib/ | |||
lib64/ | |||
parts/ | |||
sdist/ | |||
var/ | |||
wheels/ | |||
pip-wheel-metadata/ | |||
share/python-wheels/ | |||
*.egg-info/ | |||
.installed.cfg | |||
*.egg | |||
MANIFEST | |||
# PyInstaller | |||
# Usually these files are written by a python script from a template | |||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | |||
*.manifest | |||
*.spec | |||
# Installer logs | |||
pip-log.txt | |||
pip-delete-this-directory.txt | |||
# Unit test / coverage reports | |||
htmlcov/ | |||
.tox/ | |||
.nox/ | |||
.coverage | |||
.coverage.* | |||
.cache | |||
nosetests.xml | |||
coverage.xml | |||
*.cover | |||
*.py,cover | |||
.hypothesis/ | |||
.pytest_cache/ | |||
# Translations | |||
*.mo | |||
*.pot | |||
# Django stuff: | |||
*.log | |||
local_settings.py | |||
db.sqlite3 | |||
db.sqlite3-journal | |||
# Flask stuff: | |||
instance/ | |||
.webassets-cache | |||
# Scrapy stuff: | |||
.scrapy | |||
# Sphinx documentation | |||
docs/_build/ | |||
# PyBuilder | |||
target/ | |||
# Jupyter Notebook | |||
.ipynb_checkpoints | |||
# IPython | |||
profile_default/ | |||
ipython_config.py | |||
# pyenv | |||
.python-version | |||
# pipenv | |||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | |||
# However, in case of collaboration, if having platform-specific dependencies or dependencies | |||
# having no cross-platform support, pipenv may install dependencies that don't work, or not | |||
# install all needed dependencies. | |||
#Pipfile.lock | |||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow | |||
__pypackages__/ | |||
# Celery stuff | |||
celerybeat-schedule | |||
celerybeat.pid | |||
# SageMath parsed files | |||
*.sage.py | |||
# Environments | |||
.env | |||
.venv | |||
env/ | |||
venv/ | |||
ENV/ | |||
env.bak/ | |||
venv.bak/ | |||
# Spyder project settings | |||
.spyderproject | |||
.spyproject | |||
# Rope project settings | |||
.ropeproject | |||
# mkdocs documentation | |||
/site | |||
# mypy | |||
.mypy_cache/ | |||
.dmypy.json | |||
dmypy.json | |||
# Pyre type checker | |||
.pyre/ |
@@ -0,0 +1,132 @@ | |||
# -*- coding: utf-8 -*- | |||
################################################################################ | |||
## Form generated from reading UI file 'users.ui' | |||
## | |||
## Created by: Qt User Interface Compiler version 5.15.2 | |||
## | |||
## WARNING! All changes made in this file will be lost when recompiling UI file! | |||
################################################################################ | |||
from PySide2.QtCore import * | |||
from PySide2.QtGui import * | |||
from PySide2.QtWidgets import * | |||
class Ui_MainWindow(object): | |||
def setupUi(self, MainWindow): | |||
if not MainWindow.objectName(): | |||
MainWindow.setObjectName(u"MainWindow") | |||
MainWindow.resize(722, 440) | |||
self.centralwidget = QWidget(MainWindow) | |||
self.centralwidget.setObjectName(u"centralwidget") | |||
self.userView = QListView(self.centralwidget) | |||
self.userView.setObjectName(u"userView") | |||
self.userView.setGeometry(QRect(10, 40, 260, 350)) | |||
self.userView.setSelectionMode(QAbstractItemView.ExtendedSelection) | |||
self.instanceView = QTableView(self.centralwidget) | |||
self.instanceView.setObjectName(u"instanceView") | |||
self.instanceView.setGeometry(QRect(300, 40, 411, 350)) | |||
self.line = QFrame(self.centralwidget) | |||
self.line.setObjectName(u"line") | |||
self.line.setGeometry(QRect(275, 40, 20, 350)) | |||
self.line.setFrameShape(QFrame.VLine) | |||
self.line.setFrameShadow(QFrame.Sunken) | |||
self.UsersLabel = QLabel(self.centralwidget) | |||
self.UsersLabel.setObjectName(u"UsersLabel") | |||
self.UsersLabel.setGeometry(QRect(10, 10, 260, 20)) | |||
font = QFont() | |||
font.setPointSize(10) | |||
self.UsersLabel.setFont(font) | |||
self.UsersLabel.setAlignment(Qt.AlignCenter) | |||
self.InstancesLabel = QLabel(self.centralwidget) | |||
self.InstancesLabel.setObjectName(u"InstancesLabel") | |||
self.InstancesLabel.setGeometry(QRect(300, 10, 420, 20)) | |||
self.InstancesLabel.setFont(font) | |||
self.InstancesLabel.setAlignment(Qt.AlignCenter) | |||
self.layoutWidget = QWidget(self.centralwidget) | |||
self.layoutWidget.setObjectName(u"layoutWidget") | |||
self.layoutWidget.setGeometry(QRect(10, 400, 267, 30)) | |||
self.horizontalLayout_2 = QHBoxLayout(self.layoutWidget) | |||
self.horizontalLayout_2.setSpacing(5) | |||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") | |||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) | |||
self.addButton = QPushButton(self.layoutWidget) | |||
self.addButton.setObjectName(u"addButton") | |||
self.horizontalLayout_2.addWidget(self.addButton) | |||
self.editButton = QPushButton(self.layoutWidget) | |||
self.editButton.setObjectName(u"editButton") | |||
self.editButton.setEnabled(False) | |||
self.horizontalLayout_2.addWidget(self.editButton) | |||
self.deleteButton = QPushButton(self.layoutWidget) | |||
self.deleteButton.setObjectName(u"deleteButton") | |||
self.deleteButton.setEnabled(False) | |||
self.horizontalLayout_2.addWidget(self.deleteButton) | |||
self.widget = QWidget(self.centralwidget) | |||
self.widget.setObjectName(u"widget") | |||
self.widget.setGeometry(QRect(303, 400, 410, 30)) | |||
self.gridLayout = QGridLayout(self.widget) | |||
self.gridLayout.setObjectName(u"gridLayout") | |||
self.gridLayout.setContentsMargins(0, 0, 0, 0) | |||
self.instanciateButton = QPushButton(self.widget) | |||
self.instanciateButton.setObjectName(u"instanciateButton") | |||
self.instanciateButton.setEnabled(False) | |||
self.gridLayout.addWidget(self.instanciateButton, 0, 0, 1, 1) | |||
self.label = QLabel(self.widget) | |||
self.label.setObjectName(u"label") | |||
self.label.setAlignment(Qt.AlignCenter) | |||
self.gridLayout.addWidget(self.label, 0, 1, 1, 1) | |||
self.regionCombo = QComboBox(self.widget) | |||
self.regionCombo.setObjectName(u"regionCombo") | |||
self.gridLayout.addWidget(self.regionCombo, 0, 2, 1, 1) | |||
self.refreshButton = QPushButton(self.widget) | |||
self.refreshButton.setObjectName(u"refreshButton") | |||
self.gridLayout.addWidget(self.refreshButton, 0, 3, 1, 1) | |||
self.destroyButton = QPushButton(self.widget) | |||
self.destroyButton.setObjectName(u"destroyButton") | |||
self.destroyButton.setEnabled(False) | |||
icon = QIcon() | |||
iconThemeName = u"delete" | |||
if QIcon.hasThemeIcon(iconThemeName): | |||
icon = QIcon.fromTheme(iconThemeName) | |||
else: | |||
icon.addFile(u".", QSize(), QIcon.Normal, QIcon.Off) | |||
self.destroyButton.setIcon(icon) | |||
self.gridLayout.addWidget(self.destroyButton, 0, 4, 1, 1) | |||
MainWindow.setCentralWidget(self.centralwidget) | |||
self.retranslateUi(MainWindow) | |||
QMetaObject.connectSlotsByName(MainWindow) | |||
# setupUi | |||
def retranslateUi(self, MainWindow): | |||
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"Gestion des instances OVH", None)) | |||
self.UsersLabel.setText(QCoreApplication.translate("MainWindow", u"Utilisateurs", None)) | |||
self.InstancesLabel.setText(QCoreApplication.translate("MainWindow", u"Instances", None)) | |||
self.addButton.setText(QCoreApplication.translate("MainWindow", u"&Ajouter", None)) | |||
self.editButton.setText(QCoreApplication.translate("MainWindow", u"&Modifier", None)) | |||
self.deleteButton.setText(QCoreApplication.translate("MainWindow", u"&Supprimer", None)) | |||
self.instanciateButton.setText(QCoreApplication.translate("MainWindow", u"&Instancier", None)) | |||
self.label.setText(QCoreApplication.translate("MainWindow", u"R\u00e9gion :", None)) | |||
self.refreshButton.setText(QCoreApplication.translate("MainWindow", u"Actualise&r", None)) | |||
self.destroyButton.setText(QCoreApplication.translate("MainWindow", u"&D\u00e9truire", None)) | |||
# retranslateUi | |||
@@ -0,0 +1,189 @@ | |||
from PySide2.QtWidgets import QMainWindow, QApplication, QDialog | |||
from PySide2.QtCore import QAbstractListModel, QAbstractTableModel, Qt, Slot | |||
from MainApplication import Ui_MainWindow | |||
from UserDialog import Ui_userDialog | |||
import ovh_api | |||
# Abstract models | |||
class UserModel(QAbstractListModel): | |||
def __init__(self, users=[]): | |||
super().__init__() | |||
self.users = users | |||
def data(self, index, role): | |||
if role == Qt.DisplayRole: | |||
return self.users[index.row()][1] | |||
def rowCount(self, index): | |||
return len(self.users) | |||
class InstanceModel(QAbstractTableModel): | |||
def __init__(self, instances=[]): | |||
super().__init__() | |||
self.instances = instances | |||
def data(self, index, role): | |||
if role == Qt.DisplayRole: | |||
# we don't show id's, so +1 | |||
return self.instances[index.row()][index.column() + 1] | |||
def rowCount(self, index): | |||
return len(self.instances) | |||
def columnCount(self, index): | |||
# we don't show id's, so -1 | |||
if len(self.instances): | |||
return len(self.instances[0]) - 1 | |||
return 0 | |||
# UI Classes | |||
class UserDialog(QDialog, Ui_userDialog): | |||
""" A dialog to add and edit users""" | |||
def __init__(self, user=None): | |||
super().__init__() | |||
self.setupUi(self) | |||
if user: | |||
self.keyid= user[0] | |||
self.username = user[1] | |||
self.publickey = user[2] | |||
self.name.setText(self.username) | |||
self.key.setPlainText(self.publickey) | |||
@Slot() | |||
def accept(self): | |||
QApplication.setOverrideCursor(Qt.WaitCursor) | |||
if self.windowTitle() == 'Ajout': | |||
ovh_api.add_user(self.name.text(), self.key.toPlainText()) | |||
else: | |||
if self.username != self.name.text() or self.publickey != self.key.toPlainText(): | |||
ovh_api.delete_user(self.keyid) | |||
ovh_api.add_user(self.name.text(), self.key.toPlainText()) | |||
QApplication.restoreOverrideCursor() | |||
super().accept() | |||
class MainWindow(QMainWindow, Ui_MainWindow): | |||
""" The main window""" | |||
def __init__(self, *args, obj=None, **kwargs): | |||
super(MainWindow, self).__init__(*args, **kwargs) | |||
self.setupUi(self) | |||
users = ovh_api.get_users() | |||
self.user_model = UserModel(users=users) | |||
self.userView.setModel(self.user_model) | |||
self.userView.selectionModel().selectionChanged.connect(self.change_user_selection) | |||
self.addButton.pressed.connect(self.add_user) | |||
self.deleteButton.pressed.connect(self.delete_user) | |||
self.editButton.pressed.connect(self.edit_user) | |||
self.instanciateButton.pressed.connect(self.instanciate) | |||
self.regionCombo.addItems(ovh_api.regions) | |||
instances = ovh_api.get_instances() | |||
self.instance_model = InstanceModel(instances=instances) | |||
self.instanceView.setModel(self.instance_model) | |||
self.instanceView.selectionModel().selectionChanged.connect(self.change_instance_selection) | |||
self.destroyButton.pressed.connect(self.destroy_instance) | |||
self.refreshButton.pressed.connect(self.refresh_instances) | |||
self.show() | |||
# Instances management methods | |||
@Slot() | |||
def instanciate(self): | |||
region = self.regionCombo.currentText() | |||
selected_idx = self.userView.selectedIndexes() | |||
QApplication.setOverrideCursor(Qt.WaitCursor) | |||
for usr_idx in selected_idx: | |||
row = usr_idx.row() | |||
user = self.user_model.users[row] | |||
user_id = user[0] | |||
username = user[1] | |||
ovh_api.create_instance(user_id, username, region) | |||
self.refresh_instances() | |||
QApplication.restoreOverrideCursor() | |||
@Slot() | |||
def change_instance_selection(self): | |||
selected_rows = self.instanceView.selectionModel().selectedRows() | |||
destroy_active = True if selected_rows else False | |||
self.destroyButton.setEnabled(destroy_active) | |||
@Slot() | |||
def destroy_instance(self): | |||
QApplication.setOverrideCursor(Qt.WaitCursor) | |||
selected_rows = self.instanceView.selectionModel().selectedRows() | |||
for idx in selected_rows: | |||
row = idx.row() | |||
instance_id = self.instance_model.instances[row][0] | |||
ovh_api.delete_instance(instance_id) | |||
self.refresh_instances() | |||
QApplication.restoreOverrideCursor() | |||
@Slot() | |||
def refresh_instances(self): | |||
QApplication.setOverrideCursor(Qt.WaitCursor) | |||
self.instance_model.instances = ovh_api.get_instances() | |||
self.instance_model.layoutChanged.emit() | |||
QApplication.restoreOverrideCursor() | |||
# Users management methods | |||
@Slot() | |||
def change_user_selection(self): | |||
del_active = False | |||
edit_active = False | |||
instanciate_active = False | |||
sel_idxes = self.userView.selectedIndexes() | |||
if sel_idxes: | |||
del_active = True | |||
instanciate_active = True | |||
if len(sel_idxes) == 1: | |||
edit_active = True | |||
self.deleteButton.setEnabled(del_active) | |||
self.editButton.setEnabled(edit_active) | |||
self.instanciateButton.setEnabled(instanciate_active) | |||
@Slot() | |||
def add_user(self): | |||
dlg = UserDialog() | |||
dlg.setWindowTitle('Ajout') | |||
if dlg.exec_(): | |||
self.refresh_users() | |||
@Slot() | |||
def edit_user(self): | |||
usr_idx = self.userView.selectedIndexes()[0] | |||
row = usr_idx.row() | |||
user = self.user_model.users[row] | |||
dlg = UserDialog(user) | |||
dlg.setWindowTitle('Modification') | |||
if dlg.exec_(): | |||
self.refresh_users() | |||
@Slot() | |||
def delete_user(self): | |||
# TODO : confirmation | |||
selected_idx = self.userView.selectedIndexes() | |||
QApplication.setOverrideCursor(Qt.WaitCursor) | |||
for usr_idx in selected_idx: | |||
row = usr_idx.row() | |||
user_id = self.user_model.users[row][0] | |||
res = ovh_api.delete_user(user_id) | |||
print(res) | |||
self.refresh_users() | |||
QApplication.restoreOverrideCursor() | |||
def refresh_users(self): | |||
self.user_model.users = ovh_api.get_users() | |||
self.user_model.layoutChanged.emit() | |||
self.userView.clearSelection() | |||
app = QApplication([]) | |||
window = MainWindow() | |||
app.exec_() |
@@ -0,0 +1,132 @@ | |||
# -*- coding: utf-8 -*- | |||
################################################################################ | |||
## Form generated from reading UI file 'MainApplication.ui' | |||
## | |||
## Created by: Qt User Interface Compiler version 5.15.2 | |||
## | |||
## WARNING! All changes made in this file will be lost when recompiling UI file! | |||
################################################################################ | |||
from PySide2.QtCore import * | |||
from PySide2.QtGui import * | |||
from PySide2.QtWidgets import * | |||
class Ui_MainWindow(object): | |||
def setupUi(self, MainWindow): | |||
if not MainWindow.objectName(): | |||
MainWindow.setObjectName(u"MainWindow") | |||
MainWindow.resize(722, 440) | |||
self.centralwidget = QWidget(MainWindow) | |||
self.centralwidget.setObjectName(u"centralwidget") | |||
self.userView = QListView(self.centralwidget) | |||
self.userView.setObjectName(u"userView") | |||
self.userView.setGeometry(QRect(10, 40, 260, 350)) | |||
self.userView.setSelectionMode(QAbstractItemView.ExtendedSelection) | |||
self.instanceView = QTableView(self.centralwidget) | |||
self.instanceView.setObjectName(u"instanceView") | |||
self.instanceView.setGeometry(QRect(300, 40, 411, 350)) | |||
self.line = QFrame(self.centralwidget) | |||
self.line.setObjectName(u"line") | |||
self.line.setGeometry(QRect(275, 40, 20, 350)) | |||
self.line.setFrameShape(QFrame.VLine) | |||
self.line.setFrameShadow(QFrame.Sunken) | |||
self.UsersLabel = QLabel(self.centralwidget) | |||
self.UsersLabel.setObjectName(u"UsersLabel") | |||
self.UsersLabel.setGeometry(QRect(10, 10, 260, 20)) | |||
font = QFont() | |||
font.setPointSize(10) | |||
self.UsersLabel.setFont(font) | |||
self.UsersLabel.setAlignment(Qt.AlignCenter) | |||
self.InstancesLabel = QLabel(self.centralwidget) | |||
self.InstancesLabel.setObjectName(u"InstancesLabel") | |||
self.InstancesLabel.setGeometry(QRect(300, 10, 420, 20)) | |||
self.InstancesLabel.setFont(font) | |||
self.InstancesLabel.setAlignment(Qt.AlignCenter) | |||
self.layoutWidget = QWidget(self.centralwidget) | |||
self.layoutWidget.setObjectName(u"layoutWidget") | |||
self.layoutWidget.setGeometry(QRect(10, 400, 267, 30)) | |||
self.horizontalLayout_2 = QHBoxLayout(self.layoutWidget) | |||
self.horizontalLayout_2.setSpacing(5) | |||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") | |||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) | |||
self.addButton = QPushButton(self.layoutWidget) | |||
self.addButton.setObjectName(u"addButton") | |||
self.horizontalLayout_2.addWidget(self.addButton) | |||
self.editButton = QPushButton(self.layoutWidget) | |||
self.editButton.setObjectName(u"editButton") | |||
self.editButton.setEnabled(False) | |||
self.horizontalLayout_2.addWidget(self.editButton) | |||
self.deleteButton = QPushButton(self.layoutWidget) | |||
self.deleteButton.setObjectName(u"deleteButton") | |||
self.deleteButton.setEnabled(False) | |||
self.horizontalLayout_2.addWidget(self.deleteButton) | |||
self.widget = QWidget(self.centralwidget) | |||
self.widget.setObjectName(u"widget") | |||
self.widget.setGeometry(QRect(303, 400, 410, 30)) | |||
self.gridLayout = QGridLayout(self.widget) | |||
self.gridLayout.setObjectName(u"gridLayout") | |||
self.gridLayout.setContentsMargins(0, 0, 0, 0) | |||
self.instanciateButton = QPushButton(self.widget) | |||
self.instanciateButton.setObjectName(u"instanciateButton") | |||
self.instanciateButton.setEnabled(False) | |||
self.gridLayout.addWidget(self.instanciateButton, 0, 0, 1, 1) | |||
self.label = QLabel(self.widget) | |||
self.label.setObjectName(u"label") | |||
self.label.setAlignment(Qt.AlignCenter) | |||
self.gridLayout.addWidget(self.label, 0, 1, 1, 1) | |||
self.regionCombo = QComboBox(self.widget) | |||
self.regionCombo.setObjectName(u"regionCombo") | |||
self.gridLayout.addWidget(self.regionCombo, 0, 2, 1, 1) | |||
self.refreshButton = QPushButton(self.widget) | |||
self.refreshButton.setObjectName(u"refreshButton") | |||
self.gridLayout.addWidget(self.refreshButton, 0, 3, 1, 1) | |||
self.destroyButton = QPushButton(self.widget) | |||
self.destroyButton.setObjectName(u"destroyButton") | |||
self.destroyButton.setEnabled(False) | |||
icon = QIcon() | |||
iconThemeName = u"delete" | |||
if QIcon.hasThemeIcon(iconThemeName): | |||
icon = QIcon.fromTheme(iconThemeName) | |||
else: | |||
icon.addFile(u".", QSize(), QIcon.Normal, QIcon.Off) | |||
self.destroyButton.setIcon(icon) | |||
self.gridLayout.addWidget(self.destroyButton, 0, 4, 1, 1) | |||
MainWindow.setCentralWidget(self.centralwidget) | |||
self.retranslateUi(MainWindow) | |||
QMetaObject.connectSlotsByName(MainWindow) | |||
# setupUi | |||
def retranslateUi(self, MainWindow): | |||
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"Gestion des instances OVH", None)) | |||
self.UsersLabel.setText(QCoreApplication.translate("MainWindow", u"Utilisateurs", None)) | |||
self.InstancesLabel.setText(QCoreApplication.translate("MainWindow", u"Instances", None)) | |||
self.addButton.setText(QCoreApplication.translate("MainWindow", u"&Ajouter", None)) | |||
self.editButton.setText(QCoreApplication.translate("MainWindow", u"&Modifier", None)) | |||
self.deleteButton.setText(QCoreApplication.translate("MainWindow", u"&Supprimer", None)) | |||
self.instanciateButton.setText(QCoreApplication.translate("MainWindow", u"&Instancier", None)) | |||
self.label.setText(QCoreApplication.translate("MainWindow", u"R\u00e9gion :", None)) | |||
self.refreshButton.setText(QCoreApplication.translate("MainWindow", u"Actualise&r", None)) | |||
self.destroyButton.setText(QCoreApplication.translate("MainWindow", u"&D\u00e9truire", None)) | |||
# retranslateUi | |||
@@ -0,0 +1,197 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<ui version="4.0"> | |||
<class>MainWindow</class> | |||
<widget class="QMainWindow" name="MainWindow"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>0</x> | |||
<y>0</y> | |||
<width>722</width> | |||
<height>440</height> | |||
</rect> | |||
</property> | |||
<property name="windowTitle"> | |||
<string>Gestion des instances OVH</string> | |||
</property> | |||
<widget class="QWidget" name="centralwidget"> | |||
<widget class="QListView" name="userView"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>10</x> | |||
<y>40</y> | |||
<width>260</width> | |||
<height>350</height> | |||
</rect> | |||
</property> | |||
<property name="selectionMode"> | |||
<enum>QAbstractItemView::ExtendedSelection</enum> | |||
</property> | |||
</widget> | |||
<widget class="QTableView" name="instanceView"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>300</x> | |||
<y>40</y> | |||
<width>411</width> | |||
<height>350</height> | |||
</rect> | |||
</property> | |||
</widget> | |||
<widget class="Line" name="line"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>275</x> | |||
<y>40</y> | |||
<width>20</width> | |||
<height>350</height> | |||
</rect> | |||
</property> | |||
<property name="orientation"> | |||
<enum>Qt::Vertical</enum> | |||
</property> | |||
</widget> | |||
<widget class="QLabel" name="UsersLabel"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>10</x> | |||
<y>10</y> | |||
<width>260</width> | |||
<height>20</height> | |||
</rect> | |||
</property> | |||
<property name="font"> | |||
<font> | |||
<pointsize>10</pointsize> | |||
</font> | |||
</property> | |||
<property name="text"> | |||
<string>Utilisateurs</string> | |||
</property> | |||
<property name="alignment"> | |||
<set>Qt::AlignCenter</set> | |||
</property> | |||
</widget> | |||
<widget class="QLabel" name="InstancesLabel"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>300</x> | |||
<y>10</y> | |||
<width>420</width> | |||
<height>20</height> | |||
</rect> | |||
</property> | |||
<property name="font"> | |||
<font> | |||
<pointsize>10</pointsize> | |||
</font> | |||
</property> | |||
<property name="text"> | |||
<string>Instances</string> | |||
</property> | |||
<property name="alignment"> | |||
<set>Qt::AlignCenter</set> | |||
</property> | |||
</widget> | |||
<widget class="QWidget" name="layoutWidget"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>10</x> | |||
<y>400</y> | |||
<width>267</width> | |||
<height>30</height> | |||
</rect> | |||
</property> | |||
<layout class="QHBoxLayout" name="horizontalLayout_2"> | |||
<property name="spacing"> | |||
<number>5</number> | |||
</property> | |||
<item> | |||
<widget class="QPushButton" name="addButton"> | |||
<property name="text"> | |||
<string>&Ajouter</string> | |||
</property> | |||
</widget> | |||
</item> | |||
<item> | |||
<widget class="QPushButton" name="editButton"> | |||
<property name="enabled"> | |||
<bool>false</bool> | |||
</property> | |||
<property name="text"> | |||
<string>&Modifier</string> | |||
</property> | |||
</widget> | |||
</item> | |||
<item> | |||
<widget class="QPushButton" name="deleteButton"> | |||
<property name="enabled"> | |||
<bool>false</bool> | |||
</property> | |||
<property name="text"> | |||
<string>&Supprimer</string> | |||
</property> | |||
</widget> | |||
</item> | |||
</layout> | |||
</widget> | |||
<widget class="QWidget" name=""> | |||
<property name="geometry"> | |||
<rect> | |||
<x>303</x> | |||
<y>400</y> | |||
<width>410</width> | |||
<height>30</height> | |||
</rect> | |||
</property> | |||
<layout class="QGridLayout" name="gridLayout"> | |||
<item row="0" column="0"> | |||
<widget class="QPushButton" name="instanciateButton"> | |||
<property name="enabled"> | |||
<bool>false</bool> | |||
</property> | |||
<property name="text"> | |||
<string>&Instancier</string> | |||
</property> | |||
</widget> | |||
</item> | |||
<item row="0" column="1"> | |||
<widget class="QLabel" name="label"> | |||
<property name="text"> | |||
<string>Région :</string> | |||
</property> | |||
<property name="alignment"> | |||
<set>Qt::AlignCenter</set> | |||
</property> | |||
</widget> | |||
</item> | |||
<item row="0" column="2"> | |||
<widget class="QComboBox" name="regionCombo"/> | |||
</item> | |||
<item row="0" column="3"> | |||
<widget class="QPushButton" name="refreshButton"> | |||
<property name="text"> | |||
<string>Actualise&r</string> | |||
</property> | |||
</widget> | |||
</item> | |||
<item row="0" column="4"> | |||
<widget class="QPushButton" name="destroyButton"> | |||
<property name="enabled"> | |||
<bool>false</bool> | |||
</property> | |||
<property name="text"> | |||
<string>&Détruire</string> | |||
</property> | |||
<property name="icon"> | |||
<iconset theme="delete"> | |||
<normaloff>.</normaloff>.</iconset> | |||
</property> | |||
</widget> | |||
</item> | |||
</layout> | |||
</widget> | |||
</widget> | |||
</widget> | |||
<resources/> | |||
<connections/> | |||
</ui> |
@@ -0,0 +1,85 @@ | |||
# -*- coding: utf-8 -*- | |||
################################################################################ | |||
## Form generated from reading UI file 'UserDialog.ui' | |||
## | |||
## Created by: Qt User Interface Compiler version 5.15.2 | |||
## | |||
## WARNING! All changes made in this file will be lost when recompiling UI file! | |||
################################################################################ | |||
from PySide2.QtCore import * | |||
from PySide2.QtGui import * | |||
from PySide2.QtWidgets import * | |||
class Ui_userDialog(object): | |||
def setupUi(self, userDialog): | |||
if not userDialog.objectName(): | |||
userDialog.setObjectName(u"userDialog") | |||
userDialog.resize(449, 250) | |||
self.verticalLayout = QVBoxLayout(userDialog) | |||
self.verticalLayout.setObjectName(u"verticalLayout") | |||
self.verticalLayout_2 = QVBoxLayout() | |||
self.verticalLayout_2.setObjectName(u"verticalLayout_2") | |||
self.horizontalLayout = QHBoxLayout() | |||
self.horizontalLayout.setObjectName(u"horizontalLayout") | |||
self.label = QLabel(userDialog) | |||
self.label.setObjectName(u"label") | |||
sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) | |||
sizePolicy.setHorizontalStretch(0) | |||
sizePolicy.setVerticalStretch(0) | |||
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) | |||
self.label.setSizePolicy(sizePolicy) | |||
self.label.setMinimumSize(QSize(90, 25)) | |||
self.horizontalLayout.addWidget(self.label) | |||
self.name = QLineEdit(userDialog) | |||
self.name.setObjectName(u"name") | |||
self.horizontalLayout.addWidget(self.name) | |||
self.verticalLayout_2.addLayout(self.horizontalLayout) | |||
self.horizontalLayout_4 = QHBoxLayout() | |||
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") | |||
self.label_2 = QLabel(userDialog) | |||
self.label_2.setObjectName(u"label_2") | |||
self.label_2.setMinimumSize(QSize(90, 25)) | |||
self.horizontalLayout_4.addWidget(self.label_2, 0, Qt.AlignTop) | |||
self.key = QTextEdit(userDialog) | |||
self.key.setObjectName(u"key") | |||
self.horizontalLayout_4.addWidget(self.key) | |||
self.verticalLayout_2.addLayout(self.horizontalLayout_4) | |||
self.verticalLayout.addLayout(self.verticalLayout_2) | |||
self.buttonBox = QDialogButtonBox(userDialog) | |||
self.buttonBox.setObjectName(u"buttonBox") | |||
self.buttonBox.setOrientation(Qt.Horizontal) | |||
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) | |||
self.verticalLayout.addWidget(self.buttonBox) | |||
self.retranslateUi(userDialog) | |||
self.buttonBox.accepted.connect(userDialog.accept) | |||
self.buttonBox.rejected.connect(userDialog.reject) | |||
QMetaObject.connectSlotsByName(userDialog) | |||
# setupUi | |||
def retranslateUi(self, userDialog): | |||
userDialog.setWindowTitle(QCoreApplication.translate("userDialog", u"Dialog", None)) | |||
self.label.setText(QCoreApplication.translate("userDialog", u"Pr\u00e9nom", None)) | |||
self.label_2.setText(QCoreApplication.translate("userDialog", u"Clef publique", None)) | |||
# retranslateUi | |||
@@ -0,0 +1,114 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<ui version="4.0"> | |||
<class>userDialog</class> | |||
<widget class="QDialog" name="userDialog"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>0</x> | |||
<y>0</y> | |||
<width>449</width> | |||
<height>250</height> | |||
</rect> | |||
</property> | |||
<property name="windowTitle"> | |||
<string>Dialog</string> | |||
</property> | |||
<layout class="QVBoxLayout" name="verticalLayout"> | |||
<item> | |||
<layout class="QVBoxLayout" name="verticalLayout_2"> | |||
<item> | |||
<layout class="QHBoxLayout" name="horizontalLayout"> | |||
<item> | |||
<widget class="QLabel" name="label"> | |||
<property name="sizePolicy"> | |||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed"> | |||
<horstretch>0</horstretch> | |||
<verstretch>0</verstretch> | |||
</sizepolicy> | |||
</property> | |||
<property name="minimumSize"> | |||
<size> | |||
<width>90</width> | |||
<height>25</height> | |||
</size> | |||
</property> | |||
<property name="text"> | |||
<string>Prénom</string> | |||
</property> | |||
</widget> | |||
</item> | |||
<item> | |||
<widget class="QLineEdit" name="name"/> | |||
</item> | |||
</layout> | |||
</item> | |||
<item> | |||
<layout class="QHBoxLayout" name="horizontalLayout_4"> | |||
<item alignment="Qt::AlignTop"> | |||
<widget class="QLabel" name="label_2"> | |||
<property name="minimumSize"> | |||
<size> | |||
<width>90</width> | |||
<height>25</height> | |||
</size> | |||
</property> | |||
<property name="text"> | |||
<string>Clef publique</string> | |||
</property> | |||
</widget> | |||
</item> | |||
<item> | |||
<widget class="QTextEdit" name="key"/> | |||
</item> | |||
</layout> | |||
</item> | |||
</layout> | |||
</item> | |||
<item> | |||
<widget class="QDialogButtonBox" name="buttonBox"> | |||
<property name="orientation"> | |||
<enum>Qt::Horizontal</enum> | |||
</property> | |||
<property name="standardButtons"> | |||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | |||
</property> | |||
</widget> | |||
</item> | |||
</layout> | |||
</widget> | |||
<resources/> | |||
<connections> | |||
<connection> | |||
<sender>buttonBox</sender> | |||
<signal>accepted()</signal> | |||
<receiver>userDialog</receiver> | |||
<slot>accept()</slot> | |||
<hints> | |||
<hint type="sourcelabel"> | |||
<x>248</x> | |||
<y>254</y> | |||
</hint> | |||
<hint type="destinationlabel"> | |||
<x>157</x> | |||
<y>274</y> | |||
</hint> | |||
</hints> | |||
</connection> | |||
<connection> | |||
<sender>buttonBox</sender> | |||
<signal>rejected()</signal> | |||
<receiver>userDialog</receiver> | |||
<slot>reject()</slot> | |||
<hints> | |||
<hint type="sourcelabel"> | |||
<x>316</x> | |||
<y>260</y> | |||
</hint> | |||
<hint type="destinationlabel"> | |||
<x>286</x> | |||
<y>274</y> | |||
</hint> | |||
</hints> | |||
</connection> | |||
</connections> | |||
</ui> |
@@ -0,0 +1,11 @@ | |||
[default] | |||
; general configuration: default endpoint | |||
endpoint=ovh-eu | |||
[ovh-eu] | |||
; configuration specific to 'ovh-eu' endpoint | |||
application_key= | |||
application_secret= | |||
; uncomment following line when writing a script application | |||
; with a single consumer key. | |||
consumer_key= |
@@ -0,0 +1,85 @@ | |||
import ovh | |||
# OVH API specific code | |||
client = ovh.Client() | |||
regions = ['GRA7', 'SBG5', 'DE1', 'UK1', 'BHS5'] | |||
def get_base_url(): | |||
service = client.get('/cloud/project')[0] | |||
return f"/cloud/project/{service}" | |||
base_url = get_base_url() | |||
# User management | |||
# users are actually named ssh_keys | |||
def get_users(): | |||
ssh_keys = client.get(base_url + '/sshkey') | |||
return [ | |||
[ | |||
k['id'], | |||
k['name'].split('_')[1], | |||
k['publicKey'], | |||
] | |||
for k in ssh_keys | |||
if k['name'].startswith('ssh_') | |||
] | |||
def add_user(user, key): | |||
res = client.post(base_url + '/sshkey', | |||
name = 'ssh_' + user, | |||
publicKey = key | |||
) | |||
return res | |||
def delete_user(user_id): | |||
res = client.delete(base_url + '/sshkey/' + user_id) | |||
return res | |||
# Instance management | |||
# Server model for a region | |||
def get_flavor_id(region, name='s1-2'): | |||
flavors = client.get(base_url + '/flavor') | |||
flavorId = [f['id'] for f in flavors if f['name'] | |||
== name and f['region'] == region][0] | |||
return flavorId | |||
# OS image for a region | |||
def get_image_id(region, name='Ubuntu 20.04'): | |||
images = client.get(base_url + '/image') | |||
imageId = [i['id'] for i in images if i['name'] | |||
== name and i['region'] == region][0] | |||
return imageId | |||
def get_instances(): | |||
ovh_instances = client.get(base_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(base_url + '/instance', | |||
name='eica-' + name, | |||
sshKeyId=eleve_id, | |||
flavorId=flavor_id, | |||
imageId=image_id, | |||
region=region | |||
) | |||
def delete_instance(instance_id): | |||
print(base_url + '/instance/' + instance_id) | |||
client.delete(base_url + '/instance/' + instance_id) |