mirror of https://github.com/Aidaho12/haproxy-wi
v8.0: Delete check_version.html and refactor version checking logic
Removed the `check_version.html` template and moved version checking to `script.js`. This refactoring simplifies the codebase by consolidating version check handling into JavaScript, removing deprecated HTML templates, and enhancing the backend logic and API routes.pull/399/head
parent
7fb1ad4b69
commit
a7a8b4b10d
|
@ -2,13 +2,12 @@ from flask_swagger import swagger
|
||||||
from flask import jsonify, render_template, abort
|
from flask import jsonify, render_template, abort
|
||||||
from flask_pydantic import validate
|
from flask_pydantic import validate
|
||||||
|
|
||||||
from app import app, jwt
|
from app import app
|
||||||
from app.api.routes import bp
|
from app.api.routes import bp
|
||||||
from app.views.install.views import InstallView
|
from app.views.install.views import InstallView
|
||||||
from app.views.server.views import (
|
from app.views.server.views import ServerView, ServerGroupView, ServerGroupsView, ServersView, ServerIPView
|
||||||
ServerView, CredView, CredsView, ServerGroupView, ServerGroupsView, ServersView, ServerIPView
|
from app.views.server.cred_views import CredView, CredsView
|
||||||
)
|
from app.views.server.backup_vews import BackupView, S3BackupView, GitBackupView
|
||||||
from app.views.server.backup_vews import BackupView, S3BackupView
|
|
||||||
from app.views.service.views import ServiceView, ServiceActionView, ServiceBackendView, ServiceConfigView, ServiceConfigVersionsView
|
from app.views.service.views import ServiceView, ServiceActionView, ServiceBackendView, ServiceConfigView, ServiceConfigVersionsView
|
||||||
from app.views.ha.views import HAView, HAVIPView, HAVIPsView
|
from app.views.ha.views import HAView, HAVIPView, HAVIPsView
|
||||||
from app.views.user.views import UserView, UserGroupView, UserRoles
|
from app.views.user.views import UserView, UserGroupView, UserRoles
|
||||||
|
@ -30,20 +29,10 @@ def before_request():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@jwt.expired_token_loader
|
|
||||||
def my_expired_token_callback(jwt_header, jwt_payload):
|
|
||||||
return jsonify(error="Token is expired"), 401
|
|
||||||
|
|
||||||
|
|
||||||
@jwt.unauthorized_loader
|
|
||||||
def custom_unauthorized_response(_err):
|
|
||||||
return jsonify(error="Authorize first"), 401
|
|
||||||
|
|
||||||
|
|
||||||
def register_api(view, endpoint, url, pk='listener_id', pk_type='int'):
|
def register_api(view, endpoint, url, pk='listener_id', pk_type='int'):
|
||||||
view_func = view.as_view(endpoint)
|
view_func = view.as_view(endpoint)
|
||||||
bp.add_url_rule(url, view_func=view_func, methods=['POST'])
|
bp.add_url_rule(url, view_func=view_func, methods=['POST'])
|
||||||
bp.add_url_rule(f'{url}/<{pk_type}:{pk}>', view_func=view_func, methods=['GET', 'PUT', 'DELETE'])
|
bp.add_url_rule(f'{url}/<{pk_type}:{pk}>', view_func=view_func, methods=['GET', 'PUT', 'PATCH', 'DELETE'])
|
||||||
|
|
||||||
|
|
||||||
def register_api_id_ip(view, endpoint, url: str = '', methods: list = ['GET', 'POST']):
|
def register_api_id_ip(view, endpoint, url: str = '', methods: list = ['GET', 'POST']):
|
||||||
|
@ -73,9 +62,10 @@ register_api_id_ip(ServiceActionView, 'service_action', '/<any(start, stop, relo
|
||||||
register_api(ServerView, 'server', '/server', 'server_id')
|
register_api(ServerView, 'server', '/server', 'server_id')
|
||||||
register_api(BackupView, 'backup_fs', '/server/backup/fs', 'backup_id')
|
register_api(BackupView, 'backup_fs', '/server/backup/fs', 'backup_id')
|
||||||
register_api(S3BackupView, 'backup_s3', '/server/backup/s3', 'backup_id')
|
register_api(S3BackupView, 'backup_s3', '/server/backup/s3', 'backup_id')
|
||||||
|
register_api(GitBackupView, 'backup_git', '/server/backup/git', 'backup_id')
|
||||||
bp.add_url_rule('/server/<server_id>/ip', view_func=ServerIPView.as_view('server_ip_ip'), methods=['GET'])
|
bp.add_url_rule('/server/<server_id>/ip', view_func=ServerIPView.as_view('server_ip_ip'), methods=['GET'])
|
||||||
bp.add_url_rule('/server/<int:server_id>/ip', view_func=ServerIPView.as_view('server_ip'), methods=['GET'])
|
bp.add_url_rule('/server/<int:server_id>/ip', view_func=ServerIPView.as_view('server_ip'), methods=['GET'])
|
||||||
register_api(CredView, 'cred', '/server/cred', 'creds_id')
|
register_api(CredView, 'cred', '/server/cred', 'cred_id')
|
||||||
bp.add_url_rule('/server/creds', view_func=CredsView.as_view('creds'), methods=['GET'])
|
bp.add_url_rule('/server/creds', view_func=CredsView.as_view('creds'), methods=['GET'])
|
||||||
bp.add_url_rule('/servers', view_func=ServersView.as_view('servers'), methods=['GET'])
|
bp.add_url_rule('/servers', view_func=ServersView.as_view('servers'), methods=['GET'])
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ def default_values():
|
||||||
print(str(e))
|
print(str(e))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
Groups.insert(name='Default', description='All servers are included in this group by default', group_id=1).on_conflict_ignore().execute()
|
Groups.insert(name='Default', description='All servers are included in this group by default', id=1).on_conflict_ignore().execute()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(str(e))
|
print(str(e))
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import datetime
|
||||||
|
|
||||||
from app import scheduler
|
from app import scheduler
|
||||||
import app.modules.db.sql as sql
|
import app.modules.db.sql as sql
|
||||||
import app.modules.db.user as user_sql
|
|
||||||
import app.modules.db.roxy as roxy_sql
|
import app.modules.db.roxy as roxy_sql
|
||||||
import app.modules.db.history as history_sql
|
import app.modules.db.history as history_sql
|
||||||
import app.modules.roxywi.roxy as roxy
|
import app.modules.roxywi.roxy as roxy
|
||||||
|
|
|
@ -4,7 +4,6 @@ from flask import g
|
||||||
|
|
||||||
import app.modules.db.server as server_sql
|
import app.modules.db.server as server_sql
|
||||||
import app.modules.roxywi.common as roxywi_common
|
import app.modules.roxywi.common as roxywi_common
|
||||||
from app.modules.roxywi.exception import RoxywiResourceNotFound
|
|
||||||
from app.modules.roxywi.class_models import ServerRequest, GroupQuery, CredRequest, ChannelRequest
|
from app.modules.roxywi.class_models import ServerRequest, GroupQuery, CredRequest, ChannelRequest
|
||||||
from app.middleware import get_user_params
|
from app.middleware import get_user_params
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,9 @@ def delete_s3_backups(backup_id: int) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def insert_new_git(server_id, service_id, repo, branch, period, cred, description) -> None:
|
def insert_new_git(server_id, service_id, repo, branch, period, cred, description) -> int:
|
||||||
try:
|
try:
|
||||||
GitSetting.insert(
|
return GitSetting.insert(
|
||||||
server_id=server_id, service_id=service_id, repo=repo, branch=branch, period=period,
|
server_id=server_id, service_id=service_id, repo=repo, branch=branch, period=period,
|
||||||
cred_id=cred, description=description
|
cred_id=cred, description=description
|
||||||
).execute()
|
).execute()
|
||||||
|
@ -58,15 +58,11 @@ def insert_new_git(server_id, service_id, repo, branch, period, cred, descriptio
|
||||||
out_error(e)
|
out_error(e)
|
||||||
|
|
||||||
|
|
||||||
def delete_git(git_id):
|
def delete_git(git_id: int) -> None:
|
||||||
query = GitSetting.delete().where(GitSetting.id == git_id)
|
|
||||||
try:
|
try:
|
||||||
query.execute()
|
GitSetting.delete().where(GitSetting.id == git_id).execute()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
out_error(e)
|
out_error(e)
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def select_gits(**kwargs):
|
def select_gits(**kwargs):
|
||||||
|
|
|
@ -4,7 +4,9 @@ from app.modules.roxywi.exception import RoxywiResourceNotFound
|
||||||
|
|
||||||
|
|
||||||
def select_ssh(**kwargs):
|
def select_ssh(**kwargs):
|
||||||
if kwargs.get("name") is not None:
|
if kwargs.get("group") and kwargs.get("cred_id"):
|
||||||
|
query = Cred.select().where((Cred.id == kwargs.get('cred_id')) & (Cred.group_id == kwargs.get('group')))
|
||||||
|
elif kwargs.get("name") is not None:
|
||||||
query = Cred.select().where(Cred.name == kwargs.get('name'))
|
query = Cred.select().where(Cred.name == kwargs.get('name'))
|
||||||
elif kwargs.get("id") is not None:
|
elif kwargs.get("id") is not None:
|
||||||
query = Cred.select().where(Cred.id == kwargs.get('id'))
|
query = Cred.select().where(Cred.id == kwargs.get('id'))
|
||||||
|
@ -16,6 +18,8 @@ def select_ssh(**kwargs):
|
||||||
query = Cred.select()
|
query = Cred.select()
|
||||||
try:
|
try:
|
||||||
query_res = query.execute()
|
query_res = query.execute()
|
||||||
|
except Cred.DoesNotExist:
|
||||||
|
raise RoxywiResourceNotFound
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
out_error(e)
|
out_error(e)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -25,10 +25,10 @@ def delete_server(server_id):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def update_server(hostname, group, type_ip, enable, master, server_id, cred, port, desc, firewall, protected):
|
def update_server(hostname, ip, group, type_ip, enable, master, server_id, cred, port, desc, firewall, protected):
|
||||||
try:
|
try:
|
||||||
server_update = Server.update(
|
server_update = Server.update(
|
||||||
hostname=hostname, group_id=group, type_ip=type_ip, enabled=enable, master=master, cred_id=cred,
|
hostname=hostname, ip=ip, group_id=group, type_ip=type_ip, enabled=enable, master=master, cred_id=cred,
|
||||||
port=port, description=desc, firewall_enable=firewall, protected=protected
|
port=port, description=desc, firewall_enable=firewall, protected=protected
|
||||||
).where(Server.server_id == server_id)
|
).where(Server.server_id == server_id)
|
||||||
server_update.execute()
|
server_update.execute()
|
||||||
|
|
|
@ -4,7 +4,7 @@ from typing import Optional, Annotated, Union, Literal, Any, Dict, List
|
||||||
|
|
||||||
from shlex import quote
|
from shlex import quote
|
||||||
from pydantic_core import CoreSchema, core_schema
|
from pydantic_core import CoreSchema, core_schema
|
||||||
from pydantic import BaseModel, field_validator, StringConstraints, IPvAnyAddress, AnyUrl, root_validator, GetCoreSchemaHandler
|
from pydantic import BaseModel, Base64Str, StringConstraints, IPvAnyAddress, AnyUrl, root_validator, GetCoreSchemaHandler
|
||||||
|
|
||||||
DomainName = Annotated[str, StringConstraints(pattern=r"^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z0-9-]{0,61}[a-z0-9]$")]
|
DomainName = Annotated[str, StringConstraints(pattern=r"^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z0-9-]{0,61}[a-z0-9]$")]
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ class ServerRequest(BaseModel):
|
||||||
description: Optional[EscapedString] = None
|
description: Optional[EscapedString] = None
|
||||||
group_id: Optional[int] = None
|
group_id: Optional[int] = None
|
||||||
protected: Optional[bool] = 0
|
protected: Optional[bool] = 0
|
||||||
master: Optional[int] = None
|
master: Optional[int] = 0
|
||||||
port: Annotated[int, Gt(1), Le(65535)] = 22
|
port: Annotated[int, Gt(1), Le(65535)] = 22
|
||||||
haproxy: Optional[bool] = 0
|
haproxy: Optional[bool] = 0
|
||||||
nginx: Optional[bool] = 0
|
nginx: Optional[bool] = 0
|
||||||
|
@ -137,7 +137,7 @@ class CredRequest(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class CredUploadRequest(BaseModel):
|
class CredUploadRequest(BaseModel):
|
||||||
private_key: str
|
private_key: Union[Base64Str, str]
|
||||||
passphrase: Optional[EscapedString] = None
|
passphrase: Optional[EscapedString] = None
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,3 +252,14 @@ class S3BackupRequest(BaseModel):
|
||||||
access_key: Optional[EscapedString] = None
|
access_key: Optional[EscapedString] = None
|
||||||
time: Optional[EscapedString] = None
|
time: Optional[EscapedString] = None
|
||||||
description: Optional[EscapedString] = None
|
description: Optional[EscapedString] = None
|
||||||
|
|
||||||
|
|
||||||
|
class GitBackupRequest(BaseModel):
|
||||||
|
server_id: int
|
||||||
|
service_id: int
|
||||||
|
init: Optional[bool] = 0
|
||||||
|
repo: Optional[EscapedString] = None
|
||||||
|
branch: Optional[EscapedString] = 'main'
|
||||||
|
time: Optional[EscapedString] = 'weekly'
|
||||||
|
cred_id: Optional[int] = None
|
||||||
|
description: Optional[EscapedString] = None
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
from packaging import version
|
||||||
|
|
||||||
import distro
|
import distro
|
||||||
import requests
|
import requests
|
||||||
|
@ -26,33 +27,31 @@ def is_docker() -> bool:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def check_ver():
|
def check_ver():
|
||||||
return roxy_sql.get_ver()
|
return roxy_sql.get_ver()
|
||||||
|
|
||||||
|
|
||||||
def versions():
|
def versions():
|
||||||
|
json_data = {
|
||||||
|
'need_update': 0
|
||||||
|
}
|
||||||
try:
|
try:
|
||||||
current_ver = check_ver()
|
current_ver = roxy_sql.get_ver()
|
||||||
current_ver_without_dots = current_ver.split('.')
|
json_data['current_ver'] = roxy_sql.get_ver()
|
||||||
current_ver_without_dots = ''.join(current_ver_without_dots)
|
except Exception as e:
|
||||||
current_ver_without_dots = current_ver_without_dots.replace('\n', '')
|
raise Exception(f'Cannot get current version: {e}')
|
||||||
current_ver_without_dots = int(current_ver_without_dots)
|
|
||||||
except Exception:
|
|
||||||
current_ver = "Cannot get current version"
|
|
||||||
current_ver_without_dots = 0
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_ver = check_new_version('roxy-wi')
|
new_ver = check_new_version('roxy-wi')
|
||||||
new_ver_without_dots = new_ver.split('.')
|
json_data['new_ver'] = new_ver
|
||||||
new_ver_without_dots = ''.join(new_ver_without_dots)
|
|
||||||
new_ver_without_dots = new_ver_without_dots.replace('\n', '')
|
|
||||||
new_ver_without_dots = int(new_ver_without_dots)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
new_ver = "Cannot get a new version"
|
raise Exception(f'Cannot get new version: {e}')
|
||||||
new_ver_without_dots = 0
|
|
||||||
roxywi_common.logging('Roxy-WI server', f' {e}', roxywi=1)
|
|
||||||
|
|
||||||
return current_ver, new_ver, current_ver_without_dots, new_ver_without_dots
|
if version.parse(current_ver) < version.parse(new_ver):
|
||||||
|
json_data['need_update'] = 1
|
||||||
|
|
||||||
|
return json_data
|
||||||
|
|
||||||
|
|
||||||
def check_new_version(service):
|
def check_new_version(service):
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import os
|
import os
|
||||||
|
import base64
|
||||||
from cryptography.fernet import Fernet
|
from cryptography.fernet import Fernet
|
||||||
|
|
||||||
import paramiko
|
import paramiko
|
||||||
from flask import render_template
|
from flask import render_template
|
||||||
|
from playhouse.shortcuts import model_to_dict
|
||||||
|
|
||||||
import app.modules.db.cred as cred_sql
|
import app.modules.db.cred as cred_sql
|
||||||
import app.modules.db.group as group_sql
|
import app.modules.db.group as group_sql
|
||||||
|
@ -153,7 +155,7 @@ def upload_ssh_key(ssh_id: int, key: str, passphrase: str) -> None:
|
||||||
roxywi_common.logging('RMON server', e.args[0], roxywi=1)
|
roxywi_common.logging('RMON server', e.args[0], roxywi=1)
|
||||||
raise Exception(e)
|
raise Exception(e)
|
||||||
|
|
||||||
if passphrase != "''":
|
if passphrase:
|
||||||
try:
|
try:
|
||||||
passphrase = crypt_password(passphrase)
|
passphrase = crypt_password(passphrase)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -244,3 +246,31 @@ def decrypt_password(password: str) -> str:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise Exception(f'error: Cannot decrypt password: {e}')
|
raise Exception(f'error: Cannot decrypt password: {e}')
|
||||||
return decryp_pass
|
return decryp_pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_creds(group_id: int = None, cred_id: int = None) -> list:
|
||||||
|
json_data = []
|
||||||
|
lib_path = get_config.get_config_var('main', 'lib_path')
|
||||||
|
|
||||||
|
if group_id and cred_id:
|
||||||
|
creds = cred_sql.select_ssh(group=group_id, cred_id=cred_id)
|
||||||
|
elif group_id:
|
||||||
|
creds = cred_sql.select_ssh(group=group_id)
|
||||||
|
else:
|
||||||
|
creds = cred_sql.select_ssh()
|
||||||
|
|
||||||
|
for cred in creds:
|
||||||
|
cred_dict = model_to_dict(cred)
|
||||||
|
cred_dict['name'] = cred_dict['name'].replace("'", "")
|
||||||
|
ssh_key_file = f'{lib_path}/keys/{cred_dict["name"]}.pem'
|
||||||
|
if os.path.isfile(ssh_key_file):
|
||||||
|
with open(ssh_key_file, 'rb') as key:
|
||||||
|
cred_dict['private_key'] = base64.b64encode(key.read()).decode('utf-8')
|
||||||
|
else:
|
||||||
|
cred_dict['private_key'] = ''
|
||||||
|
if cred_dict['password']:
|
||||||
|
cred_dict['password'] = decrypt_password(cred_dict['password'])
|
||||||
|
if cred_dict['passphrase']:
|
||||||
|
cred_dict['passphrase'] = decrypt_password(cred_dict['passphrase'])
|
||||||
|
json_data.append(cred_dict)
|
||||||
|
return json_data
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from docutils.parsers.rst.directives import body
|
||||||
from flask import render_template
|
from flask import render_template
|
||||||
|
|
||||||
import app.modules.db.sql as sql
|
import app.modules.db.sql as sql
|
||||||
|
@ -8,7 +9,7 @@ import app.modules.db.service as service_sql
|
||||||
import app.modules.server.ssh as ssh_mod
|
import app.modules.server.ssh as ssh_mod
|
||||||
import app.modules.roxywi.common as roxywi_common
|
import app.modules.roxywi.common as roxywi_common
|
||||||
import app.modules.service.installation as installation_mod
|
import app.modules.service.installation as installation_mod
|
||||||
from app.modules.roxywi.class_models import BackupRequest, IdResponse, IdDataResponse, BaseResponse, S3BackupRequest
|
from app.modules.roxywi.class_models import BackupRequest, IdResponse, IdDataResponse, BaseResponse, S3BackupRequest, GitBackupRequest
|
||||||
|
|
||||||
|
|
||||||
def create_backup_inv(json_data: BackupRequest, del_id: int = 0) -> None:
|
def create_backup_inv(json_data: BackupRequest, del_id: int = 0) -> None:
|
||||||
|
@ -51,6 +52,29 @@ def create_s3_backup_inv(data: S3BackupRequest, tag: str) -> None:
|
||||||
raise Exception(f'error: {e}')
|
raise Exception(f'error: {e}')
|
||||||
|
|
||||||
|
|
||||||
|
def create_git_backup_inv(data: GitBackupRequest, server_ip: str, service: str, del_job: int = 0) -> None:
|
||||||
|
service_config_dir = sql.get_setting(service + '_dir')
|
||||||
|
ssh_settings = ssh_mod.return_ssh_keys_path(server_ip, id=data.cred_id)
|
||||||
|
print('del_job',del_job)
|
||||||
|
inv = {"server": {"hosts": {}}}
|
||||||
|
inv["server"]["hosts"][server_ip] = {
|
||||||
|
"REPO": data.repo,
|
||||||
|
"CONFIG_DIR": service_config_dir,
|
||||||
|
"PERIOD": data.time,
|
||||||
|
"INIT": data.init,
|
||||||
|
"BRANCH": data.branch,
|
||||||
|
"SERVICE": service,
|
||||||
|
"DELJOB": del_job,
|
||||||
|
"KEY": ssh_settings['key']
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
installation_mod.run_ansible(inv, [server_ip], 'git_backup')
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(f'error: {e}')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_backup(json_data: BackupRequest, is_api: bool) -> tuple:
|
def create_backup(json_data: BackupRequest, is_api: bool) -> tuple:
|
||||||
if backup_sql.check_exists_backup(json_data.server):
|
if backup_sql.check_exists_backup(json_data.server):
|
||||||
raise Exception(f'warning: Backup job for {json_data.server} already exists')
|
raise Exception(f'warning: Backup job for {json_data.server} already exists')
|
||||||
|
@ -71,7 +95,6 @@ def create_backup(json_data: BackupRequest, is_api: bool) -> tuple:
|
||||||
return IdDataResponse(data=data, id=last_id).model_dump(mode='json'), 201
|
return IdDataResponse(data=data, id=last_id).model_dump(mode='json'), 201
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def delete_backup(json_data: BackupRequest, backup_id: int) -> tuple:
|
def delete_backup(json_data: BackupRequest, backup_id: int) -> tuple:
|
||||||
create_backup_inv(json_data, backup_id)
|
create_backup_inv(json_data, backup_id)
|
||||||
backup_sql.delete_backups(backup_id)
|
backup_sql.delete_backups(backup_id)
|
||||||
|
@ -88,13 +111,6 @@ def update_backup(json_data: BackupRequest, backup_id: int) -> tuple:
|
||||||
|
|
||||||
|
|
||||||
def create_s3_backup(data: S3BackupRequest, is_api: bool) -> tuple:
|
def create_s3_backup(data: S3BackupRequest, is_api: bool) -> tuple:
|
||||||
# if deljob:
|
|
||||||
# time = ''
|
|
||||||
# secret_key = ''
|
|
||||||
# access_key = ''
|
|
||||||
# tag = 'delete'
|
|
||||||
# else:
|
|
||||||
# tag = 'add'
|
|
||||||
if backup_sql.check_exists_s3_backup(data.server):
|
if backup_sql.check_exists_s3_backup(data.server):
|
||||||
raise Exception(f'Backup job for {data.server} already exists')
|
raise Exception(f'Backup job for {data.server} already exists')
|
||||||
|
|
||||||
|
@ -103,7 +119,6 @@ def create_s3_backup(data: S3BackupRequest, is_api: bool) -> tuple:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
# if not deljob:
|
|
||||||
try:
|
try:
|
||||||
last_id = backup_sql.insert_s3_backup_job(**data.model_dump(mode='json'))
|
last_id = backup_sql.insert_s3_backup_job(**data.model_dump(mode='json'))
|
||||||
roxywi_common.logging('backup ', f'a new S3 backup job for server {data.server} has been created', roxywi=1, login=1)
|
roxywi_common.logging('backup ', f'a new S3 backup job for server {data.server} has been created', roxywi=1, login=1)
|
||||||
|
@ -115,11 +130,6 @@ def create_s3_backup(data: S3BackupRequest, is_api: bool) -> tuple:
|
||||||
else:
|
else:
|
||||||
temp = render_template('ajax/new_s3_backup.html', backups=backup_sql.select_s3_backups(**data.model_dump(mode='json')))
|
temp = render_template('ajax/new_s3_backup.html', backups=backup_sql.select_s3_backups(**data.model_dump(mode='json')))
|
||||||
return IdDataResponse(id=last_id, data=temp).model_dump(mode='json'), 201
|
return IdDataResponse(id=last_id, data=temp).model_dump(mode='json'), 201
|
||||||
# elif deljob:
|
|
||||||
# backup_sql.delete_s3_backups(deljob)
|
|
||||||
# roxywi_common.logging('backup ', f' a S3 backup job for server {server} has been deleted', roxywi=1, login=1)
|
|
||||||
# return 'ok'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def delete_s3_backup(data: S3BackupRequest, backup_id: int) -> None:
|
def delete_s3_backup(data: S3BackupRequest, backup_id: int) -> None:
|
||||||
|
@ -131,46 +141,49 @@ def delete_s3_backup(data: S3BackupRequest, backup_id: int) -> None:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
|
||||||
def git_backup(server_id, service_id, git_init, repo, branch, period, cred, del_job, description, backup_id) -> str:
|
def create_git_backup(data: GitBackupRequest, is_api: bool) -> tuple:
|
||||||
server_ip = server_sql.select_server_ip_by_id(server_id)
|
server_ip = server_sql.select_server_ip_by_id(data.server_id)
|
||||||
service_name = service_sql.select_service_name_by_id(service_id).lower()
|
service_name = service_sql.select_service_name_by_id(data.service_id).lower()
|
||||||
service_config_dir = sql.get_setting(service_name + '_dir')
|
try:
|
||||||
ssh_settings = ssh_mod.return_ssh_keys_path(server_ip, id=cred)
|
create_git_backup_inv(data, server_ip, service_name)
|
||||||
|
except Exception as e:
|
||||||
if repo is None or git_init == '0':
|
raise Exception(e)
|
||||||
repo = ''
|
|
||||||
if branch is None or branch == '0':
|
|
||||||
branch = 'main'
|
|
||||||
|
|
||||||
inv = {"server": {"hosts": {}}}
|
|
||||||
inv["server"]["hosts"][server_ip] = {
|
|
||||||
"REPO": repo,
|
|
||||||
"CONFIG_DIR": service_config_dir,
|
|
||||||
"PERIOD": period,
|
|
||||||
"INIT": git_init,
|
|
||||||
"BRANCH": branch,
|
|
||||||
"SERVICE": service_name,
|
|
||||||
"DELJOB": del_job,
|
|
||||||
"KEY": ssh_settings['key']
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
installation_mod.run_ansible(inv, [server_ip], 'git_backup')
|
last_id = backup_sql.insert_new_git(server_id=data.server_id, service_id=data.service_id, repo=data.repo, branch=data.branch, period=data.time,
|
||||||
|
cred=data.cred_id, description=data.description)
|
||||||
|
roxywi_common.logging(server_ip, 'A new git job has been created', roxywi=1, login=1, keep_history=1,
|
||||||
|
service=service_name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise Exception(f'error: {e}')
|
raise Exception(e)
|
||||||
|
|
||||||
if not del_job:
|
if is_api:
|
||||||
backup_sql.insert_new_git(server_id=server_id, service_id=service_id, repo=repo, branch=branch, period=period, cred=cred, description=description)
|
return IdResponse(id=last_id).model_dump(mode='json'), 201
|
||||||
|
else:
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"gits": backup_sql.select_gits(server_id=server_id, service_id=service_id),
|
"gits": backup_sql.select_gits(server_id=data.server_id, service_id=data.service_id),
|
||||||
"sshs": cred_sql.select_ssh(),
|
"sshs": cred_sql.select_ssh(),
|
||||||
"servers": roxywi_common.get_dick_permit(),
|
"servers": roxywi_common.get_dick_permit(),
|
||||||
"services": service_sql.select_services(),
|
"services": service_sql.select_services(),
|
||||||
"new_add": 1,
|
"new_add": 1,
|
||||||
"lang": roxywi_common.get_user_lang_for_flask()
|
"lang": roxywi_common.get_user_lang_for_flask()
|
||||||
}
|
}
|
||||||
roxywi_common.logging(server_ip, 'A new git job has been created', roxywi=1, login=1, keep_history=1, service=service_name)
|
|
||||||
return render_template('ajax/new_git.html', **kwargs)
|
temp = render_template('ajax/new_git.html', **kwargs)
|
||||||
else:
|
return IdDataResponse(id=last_id, data=temp).model_dump(mode='json'), 201
|
||||||
if backup_sql.delete_git(backup_id):
|
|
||||||
return 'ok'
|
|
||||||
|
def delete_git_backup(data: GitBackupRequest, backup_id: int) -> tuple:
|
||||||
|
server_ip = server_sql.select_server_ip_by_id(data.server_id)
|
||||||
|
service_name = service_sql.select_service_name_by_id(data.service_id).lower()
|
||||||
|
try:
|
||||||
|
create_git_backup_inv(data, server_ip, service_name, 1)
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(e)
|
||||||
|
|
||||||
|
try:
|
||||||
|
backup_sql.delete_git(backup_id)
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(e)
|
||||||
|
|
||||||
|
return BaseResponse().model_dump(mode='json'), 204
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from packaging import version
|
from packaging import version
|
||||||
|
|
||||||
|
import distro
|
||||||
import ansible
|
import ansible
|
||||||
import ansible_runner
|
import ansible_runner
|
||||||
|
|
||||||
|
@ -212,6 +212,8 @@ def run_ansible(inv: dict, server_ips: list, ansible_role: str) -> dict:
|
||||||
proxy = sql.get_setting('proxy')
|
proxy = sql.get_setting('proxy')
|
||||||
proxy_serv = ''
|
proxy_serv = ''
|
||||||
tags = ''
|
tags = ''
|
||||||
|
python_int = '/usr/bin/python3' if distro.id() == 'ubuntu' else '/usr/bin/python3.11'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
agent_pid = server_mod.start_ssh_agent()
|
agent_pid = server_mod.start_ssh_agent()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -261,7 +263,7 @@ def run_ansible(inv: dict, server_ips: list, ansible_role: str) -> dict:
|
||||||
'AWX_DISPLAY': False,
|
'AWX_DISPLAY': False,
|
||||||
'SSH_AUTH_PID': agent_pid['pid'],
|
'SSH_AUTH_PID': agent_pid['pid'],
|
||||||
'SSH_AUTH_SOCK': agent_pid['socket'],
|
'SSH_AUTH_SOCK': agent_pid['socket'],
|
||||||
'ANSIBLE_PYTHON_INTERPRETER': '/usr/bin/python3'
|
'ANSIBLE_PYTHON_INTERPRETER': python_int
|
||||||
}
|
}
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'private_data_dir': '/var/www/haproxy-wi/app/scripts/ansible/',
|
'private_data_dir': '/var/www/haproxy-wi/app/scripts/ansible/',
|
||||||
|
|
|
@ -171,6 +171,7 @@ def send_email(email_to: str, subject: str, message: str) -> None:
|
||||||
def telegram_send_mess(mess, level, **kwargs):
|
def telegram_send_mess(mess, level, **kwargs):
|
||||||
token_bot = ''
|
token_bot = ''
|
||||||
channel_name = ''
|
channel_name = ''
|
||||||
|
proxy = sql.get_setting('proxy')
|
||||||
|
|
||||||
if kwargs.get('channel_id') == 0:
|
if kwargs.get('channel_id') == 0:
|
||||||
return
|
return
|
||||||
|
@ -180,8 +181,6 @@ def telegram_send_mess(mess, level, **kwargs):
|
||||||
else:
|
else:
|
||||||
telegrams = channel_sql.get_receiver_by_ip('telegram', kwargs.get('ip'))
|
telegrams = channel_sql.get_receiver_by_ip('telegram', kwargs.get('ip'))
|
||||||
|
|
||||||
proxy = sql.get_setting('proxy')
|
|
||||||
|
|
||||||
for telegram in telegrams:
|
for telegram in telegrams:
|
||||||
token_bot = telegram.token
|
token_bot = telegram.token
|
||||||
channel_name = telegram.chanel_name
|
channel_name = telegram.chanel_name
|
||||||
|
|
|
@ -16,6 +16,7 @@ import app.modules.roxywi.auth as roxywi_auth
|
||||||
import app.modules.roxywi.common as roxywi_common
|
import app.modules.roxywi.common as roxywi_common
|
||||||
import app.modules.tools.smon as smon_mod
|
import app.modules.tools.smon as smon_mod
|
||||||
import app.modules.tools.common as tools_common
|
import app.modules.tools.common as tools_common
|
||||||
|
import app.modules.server.ssh as ssh_mod
|
||||||
from app.views.admin.views import SettingsView
|
from app.views.admin.views import SettingsView
|
||||||
|
|
||||||
bp.add_url_rule(
|
bp.add_url_rule(
|
||||||
|
@ -41,12 +42,12 @@ def admin():
|
||||||
users = user_sql.select_users()
|
users = user_sql.select_users()
|
||||||
servers = server_sql.select_servers(full=1)
|
servers = server_sql.select_servers(full=1)
|
||||||
masters = server_sql.select_servers(get_master_servers=1)
|
masters = server_sql.select_servers(get_master_servers=1)
|
||||||
sshs = cred_sql.select_ssh()
|
sshs = ssh_mod.get_creds()
|
||||||
else:
|
else:
|
||||||
users = user_sql.select_users(group=user_group)
|
users = user_sql.select_users(group=user_group)
|
||||||
servers = roxywi_common.get_dick_permit(virt=1, disable=0, only_group=1)
|
servers = roxywi_common.get_dick_permit(virt=1, disable=0, only_group=1)
|
||||||
masters = server_sql.select_servers(get_master_servers=1, uuid=g.user_params['user_id'])
|
masters = server_sql.select_servers(get_master_servers=1, uuid=g.user_params['user_id'])
|
||||||
sshs = cred_sql.select_ssh(group=user_group)
|
sshs = ssh_mod.get_creds(group_id=user_group)
|
||||||
|
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'lang': g.user_params['lang'],
|
'lang': g.user_params['lang'],
|
||||||
|
|
|
@ -4,7 +4,7 @@ from flask import render_template, request, g, abort, jsonify, redirect, url_for
|
||||||
from flask_jwt_extended import jwt_required
|
from flask_jwt_extended import jwt_required
|
||||||
from flask_pydantic.exceptions import ValidationError
|
from flask_pydantic.exceptions import ValidationError
|
||||||
|
|
||||||
from app import app, cache
|
from app import app, cache, jwt
|
||||||
from app.routes.main import bp
|
from app.routes.main import bp
|
||||||
import app.modules.db.user as user_sql
|
import app.modules.db.user as user_sql
|
||||||
import app.modules.db.server as server_sql
|
import app.modules.db.server as server_sql
|
||||||
|
@ -26,6 +26,16 @@ def _jinja2_filter_datetime(date, fmt=None):
|
||||||
return common.get_time_zoned_date(date, fmt)
|
return common.get_time_zoned_date(date, fmt)
|
||||||
|
|
||||||
|
|
||||||
|
@jwt.expired_token_loader
|
||||||
|
def my_expired_token_callback(jwt_header, jwt_payload):
|
||||||
|
return jsonify(error="Token is expired"), 401
|
||||||
|
|
||||||
|
|
||||||
|
@jwt.unauthorized_loader
|
||||||
|
def custom_unauthorized_response(_err):
|
||||||
|
return jsonify(error="Authorize first"), 401
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(ValidationError)
|
@app.errorhandler(ValidationError)
|
||||||
def handle_pydantic_validation_errors1(e):
|
def handle_pydantic_validation_errors1(e):
|
||||||
errors = []
|
errors = []
|
||||||
|
@ -70,6 +80,7 @@ def page_is_forbidden(e):
|
||||||
def page_not_found(e):
|
def page_not_found(e):
|
||||||
if 'api' in request.url:
|
if 'api' in request.url:
|
||||||
return jsonify({'error': str(e)}), 404
|
return jsonify({'error': str(e)}), 404
|
||||||
|
get_user_params()
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'user_params': g.user_params,
|
'user_params': g.user_params,
|
||||||
'title': e,
|
'title': e,
|
||||||
|
@ -79,23 +90,15 @@ def page_not_found(e):
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(405)
|
@app.errorhandler(405)
|
||||||
@get_user_params()
|
|
||||||
def method_not_allowed(e):
|
def method_not_allowed(e):
|
||||||
if 'api' in request.url:
|
|
||||||
return jsonify({'error': str(e)}), 405
|
return jsonify({'error': str(e)}), 405
|
||||||
kwargs = {
|
|
||||||
'user_params': g.user_params,
|
|
||||||
'title': e,
|
|
||||||
'e': e
|
|
||||||
}
|
|
||||||
return render_template('error.html', **kwargs), 405
|
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(500)
|
@app.errorhandler(500)
|
||||||
@get_user_params()
|
|
||||||
def internal_error(e):
|
def internal_error(e):
|
||||||
if 'api' in request.url:
|
if 'api' in request.url:
|
||||||
return jsonify({'error': str(e)}), 500
|
return jsonify({'error': str(e)}), 500
|
||||||
|
get_user_params()
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'user_params': g.user_params,
|
'user_params': g.user_params,
|
||||||
'title': e,
|
'title': e,
|
||||||
|
@ -224,4 +227,4 @@ def service_history(service, server_ip):
|
||||||
@bp.route('/internal/show_version')
|
@bp.route('/internal/show_version')
|
||||||
@cache.cached()
|
@cache.cached()
|
||||||
def show_roxywi_version():
|
def show_roxywi_version():
|
||||||
return render_template('ajax/check_version.html', versions=roxy.versions())
|
return jsonify(roxy.versions())
|
||||||
|
|
|
@ -7,14 +7,15 @@ from app.routes.server import bp
|
||||||
import app.modules.db.cred as cred_sql
|
import app.modules.db.cred as cred_sql
|
||||||
import app.modules.db.server as server_sql
|
import app.modules.db.server as server_sql
|
||||||
import app.modules.db.backup as backup_sql
|
import app.modules.db.backup as backup_sql
|
||||||
|
import app.modules.db.service as service_sql
|
||||||
import app.modules.common.common as common
|
import app.modules.common.common as common
|
||||||
import app.modules.roxywi.auth as roxywi_auth
|
import app.modules.roxywi.auth as roxywi_auth
|
||||||
import app.modules.roxywi.common as roxywi_common
|
import app.modules.roxywi.common as roxywi_common
|
||||||
import app.modules.server.server as server_mod
|
import app.modules.server.server as server_mod
|
||||||
import app.modules.service.backup as backup_mod
|
|
||||||
from app.middleware import get_user_params
|
from app.middleware import get_user_params
|
||||||
from app.views.server.views import ServerView, CredView, CredsView, ServerGroupView, ServerGroupsView, ServerIPView
|
from app.views.server.views import ServerView, ServerGroupView, ServerGroupsView, ServerIPView
|
||||||
from app.views.server.backup_vews import BackupView, S3BackupView
|
from app.views.server.cred_views import CredView, CredsView
|
||||||
|
from app.views.server.backup_vews import BackupView, S3BackupView, GitBackupView
|
||||||
|
|
||||||
|
|
||||||
def register_api(view, endpoint, url, pk='listener_id', pk_type='int'):
|
def register_api(view, endpoint, url, pk='listener_id', pk_type='int'):
|
||||||
|
@ -33,6 +34,7 @@ bp.add_url_rule('/<server_id>/ip', view_func=ServerIPView.as_view('server_ip_ip'
|
||||||
bp.add_url_rule('/<int:server_id>/ip', view_func=ServerIPView.as_view('server_ip'), methods=['GET'])
|
bp.add_url_rule('/<int:server_id>/ip', view_func=ServerIPView.as_view('server_ip'), methods=['GET'])
|
||||||
bp.add_url_rule('/backup', view_func=BackupView.as_view('backup', False), methods=['POST'])
|
bp.add_url_rule('/backup', view_func=BackupView.as_view('backup', False), methods=['POST'])
|
||||||
bp.add_url_rule('/backup/s3', view_func=S3BackupView.as_view('backup_s3', False), methods=['POST'])
|
bp.add_url_rule('/backup/s3', view_func=S3BackupView.as_view('backup_s3', False), methods=['POST'])
|
||||||
|
bp.add_url_rule('/backup/git', view_func=GitBackupView.as_view('backup_git', False), methods=['POST'])
|
||||||
|
|
||||||
error_mess = roxywi_common.return_error_message()
|
error_mess = roxywi_common.return_error_message()
|
||||||
|
|
||||||
|
@ -137,6 +139,7 @@ def load_backup():
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'sshs': cred_sql.select_ssh(group=user_group),
|
'sshs': cred_sql.select_ssh(group=user_group),
|
||||||
'servers': roxywi_common.get_dick_permit(virt=1, disable=0, only_group=1),
|
'servers': roxywi_common.get_dick_permit(virt=1, disable=0, only_group=1),
|
||||||
|
'services': service_sql.select_services(),
|
||||||
'backups': backup_sql.select_backups(),
|
'backups': backup_sql.select_backups(),
|
||||||
's3_backups': backup_sql.select_s3_backups(),
|
's3_backups': backup_sql.select_s3_backups(),
|
||||||
'gits': backup_sql.select_gits(),
|
'gits': backup_sql.select_gits(),
|
||||||
|
@ -145,26 +148,3 @@ def load_backup():
|
||||||
'user_subscription': roxywi_common.return_user_subscription(),
|
'user_subscription': roxywi_common.return_user_subscription(),
|
||||||
}
|
}
|
||||||
return render_template('include/admin_backup.html', **kwargs)
|
return render_template('include/admin_backup.html', **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/git', methods=['DELETE', 'POST'])
|
|
||||||
def create_git_backup():
|
|
||||||
json_data = request.get_json()
|
|
||||||
server_id = int(json_data['server'])
|
|
||||||
service_id = int(json_data['service'])
|
|
||||||
git_init = int(json_data['init'])
|
|
||||||
repo = common.checkAjaxInput(json_data['repo'])
|
|
||||||
branch = common.checkAjaxInput(json_data['branch'])
|
|
||||||
period = common.checkAjaxInput(json_data['time'])
|
|
||||||
cred = int(json_data['cred'])
|
|
||||||
del_job = int(json_data['del_job'])
|
|
||||||
description = common.checkAjaxInput(json_data['desc'])
|
|
||||||
backup_id = ''
|
|
||||||
if request.method == 'DELETE':
|
|
||||||
backup_id = json_data['backup_id']
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = backup_mod.git_backup(server_id, service_id, git_init, repo, branch, period, cred, del_job, description, backup_id)
|
|
||||||
return jsonify({'status': 'ok', 'data': data})
|
|
||||||
except Exception as e:
|
|
||||||
return roxywi_common.handle_json_exceptions(e, f'Cannot {request.method} git backup')
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
---
|
---
|
||||||
|
- name: restart rsyslog
|
||||||
|
service: name=rsyslog state=restarted
|
||||||
|
|
||||||
- name: restart docker
|
- name: restart docker
|
||||||
service: "name=docker state={{ docker_restart_handler_state }}"
|
service: "name=docker state={{ docker_restart_handler_state }}"
|
||||||
ignore_errors: "{{ ansible_check_mode }}"
|
ignore_errors: "{{ ansible_check_mode }}"
|
|
@ -11,7 +11,7 @@
|
||||||
- name: Fail if has been installed
|
- name: Fail if has been installed
|
||||||
fail:
|
fail:
|
||||||
msg="Git configuration not found. Initialize git at the beginning"
|
msg="Git configuration not found. Initialize git at the beginning"
|
||||||
when: not register_name.stat.exists and not INIT and DELJOB
|
when: not register_name.stat.exists and not INIT and not DELJOB
|
||||||
|
|
||||||
- name: Install git
|
- name: Install git
|
||||||
package:
|
package:
|
||||||
|
@ -34,15 +34,16 @@
|
||||||
- name: Copy ssh file
|
- name: Copy ssh file
|
||||||
copy:
|
copy:
|
||||||
src: '{{ KEY }}'
|
src: '{{ KEY }}'
|
||||||
dest: '/home/{{ ansible_user }}/.ssh/id_rsa'
|
dest: '/home/{{ ansible_user }}/.ssh/git_{{ SERVICE }}_key'
|
||||||
mode: 0600
|
mode: 0600
|
||||||
group: '{{ ansible_user }}'
|
group: '{{ ansible_user }}'
|
||||||
owner: '{{ ansible_user }}'
|
owner: '{{ ansible_user }}'
|
||||||
force: no
|
force: yes
|
||||||
when: INIT
|
when: INIT
|
||||||
|
|
||||||
- name: Add write permissions
|
- name: Add write permissions
|
||||||
shell: "chmod o+wr -R {{ CONFIG_DIR }}"
|
shell: "chmod o+wr -R {{ CONFIG_DIR }}"
|
||||||
|
when: not DELJOB
|
||||||
|
|
||||||
- name: Git init
|
- name: Git init
|
||||||
shell: 'cd {{ CONFIG_DIR }} && git init'
|
shell: 'cd {{ CONFIG_DIR }} && git init'
|
||||||
|
@ -58,13 +59,18 @@
|
||||||
email = roxy-wi@.com
|
email = roxy-wi@.com
|
||||||
when: INIT
|
when: INIT
|
||||||
|
|
||||||
|
- name: Add dir exception
|
||||||
|
shell: 'git config --global --add safe.directory {{ CONFIG_DIR }}'
|
||||||
|
when: INIT
|
||||||
|
become: no
|
||||||
|
|
||||||
- name: Git add remote
|
- name: Git add remote
|
||||||
shell: 'cd {{ CONFIG_DIR }} && git add --all . && git commit -m "Roxy-WI init repo" && git branch -M {{ BRANCH }} && git remote add origin {{ REPO }}'
|
shell: 'cd {{ CONFIG_DIR }} && git add --all . && git commit -m "Roxy-WI init repo" && git branch -M {{ BRANCH }} && git remote add origin {{ REPO }}'
|
||||||
when: INIT
|
when: INIT
|
||||||
become: no
|
become: no
|
||||||
|
|
||||||
- name: Git add push
|
- name: Git add push
|
||||||
shell: 'cd {{ CONFIG_DIR }} && GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no" git push -u origin {{ BRANCH }}'
|
shell: 'cd {{ CONFIG_DIR }} && GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no -i /home/{{ ansible_user }}/.ssh/git_{{ SERVICE }}_key" git push -u origin {{ BRANCH }}'
|
||||||
when: INIT
|
when: INIT
|
||||||
become: no
|
become: no
|
||||||
|
|
||||||
|
|
|
@ -219,18 +219,17 @@ function addGit(dialog_id) {
|
||||||
valid = valid && checkLength(branch_div, "Branch name", 1);
|
valid = valid && checkLength(branch_div, "Branch name", 1);
|
||||||
if (valid) {
|
if (valid) {
|
||||||
let jsonData = {
|
let jsonData = {
|
||||||
"server": server_div.val(),
|
"server_id": server_div.val(),
|
||||||
"service": service_div.val(),
|
"service_id": service_div.val(),
|
||||||
"init": git_init,
|
"init": git_init,
|
||||||
"repo": $('#git-repo').val(),
|
"repo": $('#git-repo').val(),
|
||||||
"branch": branch_div.val(),
|
"branch": branch_div.val(),
|
||||||
"time": time_div.val(),
|
"time": time_div.val(),
|
||||||
"cred": cred_div.val(),
|
"cred_id": cred_div.val(),
|
||||||
"del_job": 0,
|
|
||||||
"desc": $('#git-description').text(),
|
"desc": $('#git-description').text(),
|
||||||
}
|
}
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/server/git",
|
url: "/server/backup/git",
|
||||||
data: JSON.stringify(jsonData),
|
data: JSON.stringify(jsonData),
|
||||||
contentType: "application/json; charset=utf-8",
|
contentType: "application/json; charset=utf-8",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
@ -388,34 +387,35 @@ function removeS3Backup(id) {
|
||||||
function removeGit(id) {
|
function removeGit(id) {
|
||||||
$("#git-table-" + id).css("background-color", "#f2dede");
|
$("#git-table-" + id).css("background-color", "#f2dede");
|
||||||
let jsonData = {
|
let jsonData = {
|
||||||
"backup_id": id,
|
"cred_id": $('#git-credentials-id-' + id).text(),
|
||||||
"del_job": 1,
|
"server_id": $('#git-server-id-' + id).text(),
|
||||||
"init": 0,
|
"service_id": $('#git-service-id-' + id).text(),
|
||||||
"repo": 0,
|
|
||||||
"branch": 0,
|
|
||||||
"time": 0,
|
|
||||||
"cred": $('#git-credentials-id-' + id).text(),
|
|
||||||
"server": $('#git-server-id-' + id).text(),
|
|
||||||
"service": $('#git-service-id-' + id).text(),
|
|
||||||
"desc": '',
|
|
||||||
}
|
}
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/server/git",
|
url: api_prefix + "/server/backup/git/" + id,
|
||||||
data: JSON.stringify(jsonData),
|
data: JSON.stringify(jsonData),
|
||||||
contentType: "application/json; charset=utf-8",
|
contentType: "application/json; charset=utf-8",
|
||||||
type: "DELETE",
|
type: "DELETE",
|
||||||
success: function (data) {
|
statusCode: {
|
||||||
if (data.status === 'failed') {
|
204: function (xhr) {
|
||||||
toastr.error(data.error);
|
|
||||||
} else {
|
|
||||||
$("#git-table-" + id).remove();
|
$("#git-table-" + id).remove();
|
||||||
|
},
|
||||||
|
404: function (xhr) {
|
||||||
|
$("#git-table-" + id).remove();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
success: function (data) {
|
||||||
|
if (data) {
|
||||||
|
if (data.status === "failed") {
|
||||||
|
toastr.error(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function updateBackup(id) {
|
function updateBackup(id) {
|
||||||
toastr.clear();
|
toastr.clear();
|
||||||
if ($("#backup-type-" + id + " option:selected").val() == "-------" || $('#backup-rserver-' + id).val() == '' || $('#backup-rpath-' + id).val() == '') {
|
if ($("#backup-type-" + id + " option:selected").val() === "-------" || $('#backup-rserver-' + id).val() === '' || $('#backup-rpath-' + id).val() === '') {
|
||||||
toastr.error('All fields must be completed');
|
toastr.error('All fields must be completed');
|
||||||
} else {
|
} else {
|
||||||
let jsonData = {
|
let jsonData = {
|
||||||
|
|
|
@ -1163,9 +1163,14 @@ function show_version() {
|
||||||
NProgress.configure({showSpinner: false});
|
NProgress.configure({showSpinner: false});
|
||||||
$.ajax( {
|
$.ajax( {
|
||||||
url: "/internal/show_version",
|
url: "/internal/show_version",
|
||||||
|
contentType: "application/json; charset=utf-8",
|
||||||
success: function( data ) {
|
success: function( data ) {
|
||||||
$('#version').html(data);
|
if (data.need_update) {
|
||||||
var showUpdates = $( "#show-updates" ).dialog({
|
$('#version').html('<span id="show-updates-button" class="new-version-exists" style="cursor: pointer;">v' + data.current_ver + '</span>');
|
||||||
|
} else {
|
||||||
|
$('#version').html('v' + data.current_ver);
|
||||||
|
}
|
||||||
|
let showUpdates = $("#show-updates").dialog({
|
||||||
autoOpen: false,
|
autoOpen: false,
|
||||||
width: 600,
|
width: 600,
|
||||||
modal: true,
|
modal: true,
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
{%- if versions is defined -%}
|
|
||||||
{%- set current_ver = versions.0 -%}
|
|
||||||
{%- set new_ver = versions.1 %}
|
|
||||||
{%- set current_ver_without_dots = versions.2 %}
|
|
||||||
{%- set new_ver_without_dots = versions.3 %}
|
|
||||||
{%- endif -%}
|
|
||||||
{%- if new_ver_without_dots is defined and current_ver_without_dots is defined and new_ver is defined and new_ver_without_dots is defined -%}
|
|
||||||
<a style="color: #000; cursor: pointer;">
|
|
||||||
{%- if new_ver_without_dots > current_ver_without_dots and new_ver != "Sorry cannot get current version" %}
|
|
||||||
<span id="show-updates-button" class="new-version-exists">v{{current_ver}}</span>
|
|
||||||
<script defer src="/static/js/fontawesome.min.js"></script>
|
|
||||||
{%- else %}
|
|
||||||
<a href="/admin#updatehapwi" title="Update center" style="color: black;">v{{current_ver}}</a>
|
|
||||||
{%- endif %}
|
|
||||||
</a>
|
|
||||||
{%- else %}
|
|
||||||
<a href="/admin#updatehapwi" title="Update center" style="color: black;">v{{current_ver}}</a>
|
|
||||||
{% endif -%}
|
|
|
@ -1,8 +1,4 @@
|
||||||
{% import 'languages/'+lang|default('en')+'.html' as lang %}
|
{% import 'languages/'+lang|default('en')+'.html' as lang %}
|
||||||
{% set current_ver = versions.0 %}
|
|
||||||
{% set new_ver = versions.1 %}
|
|
||||||
{% set current_ver_without_dots = versions.2 %}
|
|
||||||
{% set new_ver_without_dots = versions.3 %}
|
|
||||||
{% set services_name = {
|
{% set services_name = {
|
||||||
'roxy-wi-checker': { 'link': 'checker', 'name': 'Checker', 'desc': lang.admin_page.desc.checker_desc },
|
'roxy-wi-checker': { 'link': 'checker', 'name': 'Checker', 'desc': lang.admin_page.desc.checker_desc },
|
||||||
'roxy-wi-keep_alive': { 'link': 'auto_start', 'name': 'Auto start', 'desc': lang.admin_page.desc.auto_start_desc },
|
'roxy-wi-keep_alive': { 'link': 'auto_start', 'name': 'Auto start', 'desc': lang.admin_page.desc.auto_start_desc },
|
||||||
|
@ -19,7 +15,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<b
|
<b
|
||||||
{% if new_ver_without_dots > current_ver_without_dots and new_ver != "Sorry cannot get current version" %}
|
{% if versions.need_update %}
|
||||||
title=lang.admin_page.desc.a_new_version+" Roxy-WI"
|
title=lang.admin_page.desc.a_new_version+" Roxy-WI"
|
||||||
style="color: var(--red-color)"
|
style="color: var(--red-color)"
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -27,14 +23,14 @@
|
||||||
style="color: var(--green-color)"
|
style="color: var(--green-color)"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
>
|
>
|
||||||
{{current_ver}}
|
{{versions.current_ver}}
|
||||||
</b>
|
</b>
|
||||||
</td>
|
</td>
|
||||||
<td class="padding10">
|
<td class="padding10">
|
||||||
<b>{{new_ver}}</b>
|
<b>{{versions.new_ver}}</b>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if new_ver_without_dots > current_ver_without_dots and new_ver != "Sorry cannot get current version" %}
|
{% if versions.need_update %}
|
||||||
<a class="ui-button ui-widget ui-corner-all" onclick="updateService('roxy-wi')" title="{{lang.words.w_update|title()}} Roxy-WI">{{lang.words.w_update|title()}}</a>
|
<a class="ui-button ui-widget ui-corner-all" onclick="updateService('roxy-wi')" title="{{lang.words.w_update|title()}} Roxy-WI">{{lang.words.w_update|title()}}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td style="width: 10%">
|
<td style="width: 10%">
|
||||||
{% for ssh in sshs %}
|
{% for ssh in sshs %}
|
||||||
{% if ssh.enable == 1 %}
|
{% if ssh.key_enabled == 1 %}
|
||||||
{% if ssh.id == b.cred_id %}
|
{% if ssh.id == b.cred_id %}
|
||||||
<span id="git-credentials-id-{{b.id}}" style="display: none">{{ ssh.id }}</span>
|
<span id="git-credentials-id-{{b.id}}" style="display: none">{{ ssh.id }}</span>
|
||||||
<span id="git-credentials-{{b.id}}">{{ ssh.name }}</span>
|
<span id="git-credentials-{{b.id}}">{{ ssh.name }}</span>
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
<td style="width: 100%">
|
<td style="width: 100%">
|
||||||
<span type="text" id="git-description-{{b.id}}">
|
<span id="git-description-{{b.id}}">
|
||||||
{% if b.description %}
|
{% if b.description %}
|
||||||
{{b.description}}
|
{{b.description}}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<tr style="width: 50%;" id="ssh-table-{{ssh.id}}" class="{{ loop.cycle('odd', 'even') }}">
|
<tr style="width: 50%;" id="ssh-table-{{ssh.id}}" class="{{ loop.cycle('odd', 'even') }}">
|
||||||
<td class="first-collumn padding10">
|
<td class="first-collumn padding10">
|
||||||
{% set id = 'ssh_name-' + ssh.id|string() %}
|
{% set id = 'ssh_name-' + ssh.id|string() %}
|
||||||
{{ input(id, value=ssh.name, size='15') }}
|
{{ input(id, value=ssh.name.replace("'", ""), size='15') }}
|
||||||
</td>
|
</td>
|
||||||
<td class="first-collumn" valign="top" style="padding-top: 15px;">
|
<td class="first-collumn" valign="top" style="padding-top: 15px;">
|
||||||
{% if ssh.key_enabled == 1 %}
|
{% if ssh.key_enabled == 1 %}
|
||||||
|
@ -48,9 +48,9 @@
|
||||||
{{ input(id, value=ssh.username, title='SSH user name') }}
|
{{ input(id, value=ssh.username, title='SSH user name') }}
|
||||||
</p>
|
</p>
|
||||||
{% if ssh.key_enabled == 1 %}
|
{% if ssh.key_enabled == 1 %}
|
||||||
<input type="password" id="ssh_pass-{{ssh.id}}" class="form-control" title="User password, if SSH key is disabled" placeholder="*****" style="display: none;" autocomplete="new-password">
|
<input type="password" id="ssh_pass-{{ssh.id}}" class="form-control" title="User password, if SSH key is disabled" value="{{ ssh.password }}" style="display: none;" autocomplete="new-password">
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="password" id="ssh_pass-{{ssh.id}}" class="form-control" title="User password, if SSH key is disabled" placeholder="*****" autocomplete="new-password">
|
<input type="password" id="ssh_pass-{{ssh.id}}" class="form-control" title="User password, if SSH key is disabled" value="{{ ssh.password }}" autocomplete="new-password">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<br>
|
<br>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -8,7 +8,7 @@ import app.modules.db.backup as backup_sql
|
||||||
import app.modules.service.backup as backup_mod
|
import app.modules.service.backup as backup_mod
|
||||||
import app.modules.roxywi.common as roxywi_common
|
import app.modules.roxywi.common as roxywi_common
|
||||||
from app.middleware import get_user_params, page_for_admin, check_group
|
from app.middleware import get_user_params, page_for_admin, check_group
|
||||||
from app.modules.roxywi.class_models import BackupRequest, S3BackupRequest, BaseResponse
|
from app.modules.roxywi.class_models import BackupRequest, S3BackupRequest, GitBackupRequest, BaseResponse
|
||||||
|
|
||||||
|
|
||||||
class BackupView(MethodView):
|
class BackupView(MethodView):
|
||||||
|
@ -209,7 +209,7 @@ class BackupView(MethodView):
|
||||||
|
|
||||||
|
|
||||||
class S3BackupView(MethodView):
|
class S3BackupView(MethodView):
|
||||||
methods = ['GET', 'POST', 'PUT', 'DELETE']
|
methods = ['GET', 'POST', 'DELETE']
|
||||||
decorators = [jwt_required(), get_user_params(), page_for_admin(), check_group()]
|
decorators = [jwt_required(), get_user_params(), page_for_admin(), check_group()]
|
||||||
|
|
||||||
def __init__(self, is_api=True):
|
def __init__(self, is_api=True):
|
||||||
|
@ -352,3 +352,151 @@ class S3BackupView(MethodView):
|
||||||
return BaseResponse().model_dump(mode='json'), 204
|
return BaseResponse().model_dump(mode='json'), 204
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot delete S3 backup')
|
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot delete S3 backup')
|
||||||
|
|
||||||
|
|
||||||
|
class GitBackupView(MethodView):
|
||||||
|
methods = ['GET', 'POST', 'DELETE']
|
||||||
|
decorators = [jwt_required(), get_user_params(), page_for_admin(), check_group()]
|
||||||
|
|
||||||
|
def __init__(self, is_api=True):
|
||||||
|
self.is_api = is_api
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(backup_id: int):
|
||||||
|
"""
|
||||||
|
Retrieves the details of a specific Git backup configuration.
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- Git Backup
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: backup_id
|
||||||
|
type: 'integer'
|
||||||
|
required: true
|
||||||
|
description: The ID of the specific Git backup
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: Successful operation
|
||||||
|
schema:
|
||||||
|
type: 'object'
|
||||||
|
properties:
|
||||||
|
branch:
|
||||||
|
type: 'string'
|
||||||
|
description: 'The branch the backup is on'
|
||||||
|
cred_id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'The ID of the credentials used for the backup'
|
||||||
|
description:
|
||||||
|
type: 'string'
|
||||||
|
description: 'Description for the Git backup configuration'
|
||||||
|
id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'The ID of the backup'
|
||||||
|
period:
|
||||||
|
type: 'string'
|
||||||
|
description: 'The timing for the Git backup task'
|
||||||
|
repo:
|
||||||
|
type: 'string'
|
||||||
|
description: 'The repository URL for the backup'
|
||||||
|
server_id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'The ID of the server that was backed up'
|
||||||
|
service_id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'The service ID of the backup'
|
||||||
|
default:
|
||||||
|
description: Unexpected error
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
backup = backup_sql.get_backup(backup_id, 'git')
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, '')
|
||||||
|
|
||||||
|
return jsonify(model_to_dict(backup, recurse=False))
|
||||||
|
|
||||||
|
@validate(body=GitBackupRequest)
|
||||||
|
def post(self, body: GitBackupRequest):
|
||||||
|
"""
|
||||||
|
Create a new Git backup.
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- Git Backup
|
||||||
|
parameters:
|
||||||
|
- name: config
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
description: The configuration for Git backup service
|
||||||
|
schema:
|
||||||
|
type: 'object'
|
||||||
|
properties:
|
||||||
|
server_id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'The ID of the server to backed up'
|
||||||
|
service_id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'Service ID'
|
||||||
|
init:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'Indicates whether to initialize the repository'
|
||||||
|
repo:
|
||||||
|
type: 'string'
|
||||||
|
description: 'The repository from where to fetch the data for backup'
|
||||||
|
branch:
|
||||||
|
type: 'string'
|
||||||
|
description: 'The branch to pull for backup'
|
||||||
|
time:
|
||||||
|
type: 'string'
|
||||||
|
description: 'The timing for the Git backup task'
|
||||||
|
cred_id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'The ID of the credentials to be used for backup'
|
||||||
|
description:
|
||||||
|
type: 'string'
|
||||||
|
description: 'Description for the Git backup configuration'
|
||||||
|
responses:
|
||||||
|
201:
|
||||||
|
description: Successful operation
|
||||||
|
default:
|
||||||
|
description: Unexpected error
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return backup_mod.create_git_backup(body, self.is_api)
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot create GIT backup')
|
||||||
|
|
||||||
|
@validate(body=GitBackupRequest)
|
||||||
|
def delete(self, backup_id: int, body: GitBackupRequest):
|
||||||
|
"""
|
||||||
|
Deletes a specific Git based backup configuration.
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- Git Backup
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: backup_id
|
||||||
|
type: 'integer'
|
||||||
|
required: true
|
||||||
|
description: The ID of the specific Git backup
|
||||||
|
- name: config
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
description: The configuration for Git backup service delete operation
|
||||||
|
schema:
|
||||||
|
type: 'object'
|
||||||
|
properties:
|
||||||
|
server_id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'ID of the server from where the backup is to be deleted'
|
||||||
|
service_id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'Service ID of the backup to be deleted'
|
||||||
|
responses:
|
||||||
|
204:
|
||||||
|
description: Successful operation
|
||||||
|
default:
|
||||||
|
description: Unexpected error
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return backup_mod.delete_git_backup(body, backup_id)
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot delete GIT backup')
|
||||||
|
|
|
@ -0,0 +1,319 @@
|
||||||
|
import base64
|
||||||
|
|
||||||
|
from flask.views import MethodView
|
||||||
|
from flask_pydantic import validate
|
||||||
|
from flask import jsonify, g
|
||||||
|
from flask_jwt_extended import jwt_required
|
||||||
|
|
||||||
|
import app.modules.db.cred as cred_sql
|
||||||
|
import app.modules.roxywi.common as roxywi_common
|
||||||
|
import app.modules.server.ssh as ssh_mod
|
||||||
|
from app.middleware import get_user_params, page_for_admin, check_group
|
||||||
|
from app.modules.roxywi.exception import RoxywiGroupMismatch, RoxywiResourceNotFound
|
||||||
|
from app.modules.roxywi.class_models import BaseResponse, GroupQuery, CredRequest, CredUploadRequest
|
||||||
|
from app.modules.common.common_classes import SupportClass
|
||||||
|
|
||||||
|
class CredView(MethodView):
|
||||||
|
methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']
|
||||||
|
decorators = [jwt_required(), get_user_params(), page_for_admin(level=2), check_group()]
|
||||||
|
|
||||||
|
def __init__(self, is_api=False):
|
||||||
|
self.is_api = is_api
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@validate(query=GroupQuery)
|
||||||
|
def get(cred_id: int, query: GroupQuery):
|
||||||
|
"""
|
||||||
|
Retrieve credential information for a specific ID
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- 'SSH credentials'
|
||||||
|
parameters:
|
||||||
|
- in: 'path'
|
||||||
|
name: 'cred_id'
|
||||||
|
description: 'ID of the credential to retrieve'
|
||||||
|
required: true
|
||||||
|
type: 'integer'
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: 'Individual Credential Information'
|
||||||
|
schema:
|
||||||
|
type: 'object'
|
||||||
|
properties:
|
||||||
|
group_id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'Group ID the credential belongs to'
|
||||||
|
id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'Credential ID'
|
||||||
|
key_enabled:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'Key status of the credential'
|
||||||
|
name:
|
||||||
|
type: 'string'
|
||||||
|
description: 'Name of the credential'
|
||||||
|
username:
|
||||||
|
type: 'string'
|
||||||
|
description: 'Username associated with the credential'
|
||||||
|
password:
|
||||||
|
type: 'string'
|
||||||
|
description: 'Password associated with the credential'
|
||||||
|
passphrase:
|
||||||
|
type: 'string'
|
||||||
|
description: 'Password for the SSH private key'
|
||||||
|
private_key:
|
||||||
|
type: 'string'
|
||||||
|
description: 'SSH private key in base64 encoded format'
|
||||||
|
404:
|
||||||
|
description: 'Credential not found'
|
||||||
|
"""
|
||||||
|
group_id = SupportClass.return_group_id(query)
|
||||||
|
try:
|
||||||
|
creds = ssh_mod.get_creds(group_id=group_id, cred_id=cred_id)
|
||||||
|
return jsonify(creds), 200
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get credentials')
|
||||||
|
|
||||||
|
@validate(body=CredRequest)
|
||||||
|
def post(self, body: CredRequest):
|
||||||
|
"""
|
||||||
|
Create a new credential entry
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- SSH credentials
|
||||||
|
parameters:
|
||||||
|
- in: 'path'
|
||||||
|
name: 'creds_id'
|
||||||
|
description: 'ID of the credential to retrieve'
|
||||||
|
required: true
|
||||||
|
type: 'integer'
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
schema:
|
||||||
|
id: AddCredentials
|
||||||
|
required:
|
||||||
|
- group_шв
|
||||||
|
- name
|
||||||
|
- username
|
||||||
|
- key_enabled
|
||||||
|
- password
|
||||||
|
properties:
|
||||||
|
group_id:
|
||||||
|
type: integer
|
||||||
|
description: The ID of the group to create the credential for. Only for superAdmin role
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The credential name
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: The username
|
||||||
|
key_enabled:
|
||||||
|
type: integer
|
||||||
|
description: If key is enabled or not
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
description: The password
|
||||||
|
responses:
|
||||||
|
201:
|
||||||
|
description: Credential addition successful
|
||||||
|
"""
|
||||||
|
group_id = SupportClass.return_group_id(body)
|
||||||
|
try:
|
||||||
|
return ssh_mod.create_ssh_cred(body.name, body.password, group_id, body.username, body.key_enabled, self.is_api)
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot create new cred')
|
||||||
|
|
||||||
|
@validate(body=CredRequest)
|
||||||
|
def put(self, creds_id: int, body: CredRequest):
|
||||||
|
"""
|
||||||
|
Update a credential entry
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- SSH credentials
|
||||||
|
parameters:
|
||||||
|
- in: 'path'
|
||||||
|
name: 'creds_id'
|
||||||
|
description: 'ID of the credential to retrieve'
|
||||||
|
required: true
|
||||||
|
type: 'integer'
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
schema:
|
||||||
|
id: UpdateCredentials
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- username
|
||||||
|
- key_enabled
|
||||||
|
- password
|
||||||
|
properties:
|
||||||
|
group_id:
|
||||||
|
type: integer
|
||||||
|
description: The ID of the group to create the credential for. Only for superAdmin role
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The credential name
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: The username
|
||||||
|
key_enabled:
|
||||||
|
type: integer
|
||||||
|
description: If key is enabled or not
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
description: The password
|
||||||
|
responses:
|
||||||
|
201:
|
||||||
|
description: Credential update successful
|
||||||
|
"""
|
||||||
|
group_id = SupportClass.return_group_id(body)
|
||||||
|
try:
|
||||||
|
self._check_is_correct_group(creds_id)
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, ''), 404
|
||||||
|
|
||||||
|
try:
|
||||||
|
ssh_mod.update_ssh_key(creds_id, body.name, body.password, body.key_enabled, body.username, group_id)
|
||||||
|
return BaseResponse().model_dump(mode='json'), 201
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot update SSH key')
|
||||||
|
|
||||||
|
def delete(self, creds_id: int):
|
||||||
|
"""
|
||||||
|
Delete a credential entry
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- SSH credentials
|
||||||
|
parameters:
|
||||||
|
- in: 'path'
|
||||||
|
name: 'creds_id'
|
||||||
|
description: 'ID of the credential to retrieve'
|
||||||
|
required: true
|
||||||
|
type: 'integer'
|
||||||
|
responses:
|
||||||
|
204:
|
||||||
|
description: Credential deletion successful
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self._check_is_correct_group(creds_id)
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, ''), 404
|
||||||
|
|
||||||
|
try:
|
||||||
|
ssh_mod.delete_ssh_key(creds_id)
|
||||||
|
return BaseResponse().model_dump(mode='json'), 204
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot delete SSH key')
|
||||||
|
|
||||||
|
@validate(body=CredUploadRequest)
|
||||||
|
def patch(self, creds_id: int, body: CredUploadRequest):
|
||||||
|
"""
|
||||||
|
Upload an SSH private key
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- SSH credentials
|
||||||
|
parameters:
|
||||||
|
- in: 'path'
|
||||||
|
name: 'creds_id'
|
||||||
|
description: 'ID of the credential to retrieve'
|
||||||
|
required: true
|
||||||
|
type: 'integer'
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
schema:
|
||||||
|
id: UploadSSHKey
|
||||||
|
required:
|
||||||
|
- private_key
|
||||||
|
- passphrase
|
||||||
|
properties:
|
||||||
|
private_key:
|
||||||
|
type: string
|
||||||
|
description: The private key string or base64 encoded string
|
||||||
|
passphrase:
|
||||||
|
type: string
|
||||||
|
description: The passphrase
|
||||||
|
responses:
|
||||||
|
201:
|
||||||
|
description: SSH key upload successful
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self._check_is_correct_group(creds_id)
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, ''), 404
|
||||||
|
try:
|
||||||
|
body.private_key = base64.b64decode(body.private_key).decode("ascii")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
ssh_mod.upload_ssh_key(creds_id, body.private_key, body.passphrase)
|
||||||
|
return BaseResponse().model_dump(mode='json'), 201
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot upload SSH key')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _check_is_correct_group(creds_id: int):
|
||||||
|
if g.user_params['role'] == 1:
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
ssh = cred_sql.get_ssh(creds_id)
|
||||||
|
except RoxywiResourceNotFound:
|
||||||
|
raise RoxywiResourceNotFound
|
||||||
|
if ssh.group_id != g.user_params['group_id']:
|
||||||
|
raise RoxywiGroupMismatch
|
||||||
|
|
||||||
|
|
||||||
|
class CredsView(MethodView):
|
||||||
|
methods = ['GET']
|
||||||
|
decorators = [jwt_required(), get_user_params(), page_for_admin(level=2), check_group()]
|
||||||
|
|
||||||
|
@validate(query=GroupQuery)
|
||||||
|
def get(self, query: GroupQuery):
|
||||||
|
"""
|
||||||
|
Retrieve credential information based on group_id
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- 'SSH credentials'
|
||||||
|
parameters:
|
||||||
|
- in: 'query'
|
||||||
|
name: 'group_id'
|
||||||
|
description: 'GroupQuery to filter servers. Only for superAdmin role'
|
||||||
|
required: false
|
||||||
|
type: 'integer'
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: 'Credentials Information'
|
||||||
|
schema:
|
||||||
|
type: 'array'
|
||||||
|
items:
|
||||||
|
type: 'object'
|
||||||
|
properties:
|
||||||
|
group_id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'Group ID the credential belongs to'
|
||||||
|
id:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'Credential ID'
|
||||||
|
key_enabled:
|
||||||
|
type: 'integer'
|
||||||
|
description: 'Key status of the credential'
|
||||||
|
name:
|
||||||
|
type: 'string'
|
||||||
|
description: 'Name of the credential'
|
||||||
|
username:
|
||||||
|
type: 'string'
|
||||||
|
description: 'Username of the credential'
|
||||||
|
password:
|
||||||
|
type: 'string'
|
||||||
|
description: 'Password associated with the credential'
|
||||||
|
passphrase:
|
||||||
|
type: 'string'
|
||||||
|
description: 'Password for the SSH private key'
|
||||||
|
private_key:
|
||||||
|
type: 'string'
|
||||||
|
description: 'SSH private key in base64 encoded format'
|
||||||
|
"""
|
||||||
|
group_id = SupportClass.return_group_id(query)
|
||||||
|
try:
|
||||||
|
creds = ssh_mod.get_creds(group_id=group_id)
|
||||||
|
return jsonify(creds), 200
|
||||||
|
except Exception as e:
|
||||||
|
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get credentials')
|
|
@ -1,19 +1,17 @@
|
||||||
from flask.views import MethodView
|
from flask.views import MethodView
|
||||||
from flask_pydantic import validate
|
from flask_pydantic import validate
|
||||||
from flask import render_template, jsonify, request, g
|
from flask import render_template, jsonify, request
|
||||||
from playhouse.shortcuts import model_to_dict
|
from playhouse.shortcuts import model_to_dict
|
||||||
from flask_jwt_extended import jwt_required
|
from flask_jwt_extended import jwt_required
|
||||||
|
|
||||||
from app.modules.db.db_model import Cred
|
|
||||||
import app.modules.db.cred as cred_sql
|
import app.modules.db.cred as cred_sql
|
||||||
import app.modules.db.group as group_sql
|
import app.modules.db.group as group_sql
|
||||||
import app.modules.db.server as server_sql
|
import app.modules.db.server as server_sql
|
||||||
import app.modules.roxywi.group as group_mod
|
import app.modules.roxywi.group as group_mod
|
||||||
import app.modules.roxywi.common as roxywi_common
|
import app.modules.roxywi.common as roxywi_common
|
||||||
import app.modules.server.ssh as ssh_mod
|
|
||||||
import app.modules.server.server as server_mod
|
import app.modules.server.server as server_mod
|
||||||
from app.middleware import get_user_params, page_for_admin, check_group
|
from app.middleware import get_user_params, page_for_admin, check_group
|
||||||
from app.modules.roxywi.exception import RoxywiGroupMismatch, RoxywiResourceNotFound
|
from app.modules.roxywi.exception import RoxywiResourceNotFound
|
||||||
from app.modules.roxywi.class_models import (
|
from app.modules.roxywi.class_models import (
|
||||||
BaseResponse, IdResponse, IdDataResponse, ServerRequest, GroupQuery, GroupRequest, CredRequest, CredUploadRequest
|
BaseResponse, IdResponse, IdDataResponse, ServerRequest, GroupQuery, GroupRequest, CredRequest, CredUploadRequest
|
||||||
)
|
)
|
||||||
|
@ -132,21 +130,20 @@ class ServerView(MethodView):
|
||||||
required:
|
required:
|
||||||
- hostname
|
- hostname
|
||||||
- ip
|
- ip
|
||||||
- enabled
|
- cred_id
|
||||||
- creds_id
|
|
||||||
- port
|
- port
|
||||||
- description
|
- group_id
|
||||||
properties:
|
properties:
|
||||||
hostname:
|
hostname:
|
||||||
type: string
|
type: string
|
||||||
description: The server name
|
description: The server name
|
||||||
ip:
|
ip:
|
||||||
type: string
|
type: string
|
||||||
description: The server IP address
|
description: The server IP address or domain name
|
||||||
enabled:
|
enabled:
|
||||||
type: integer
|
type: integer
|
||||||
description: If server is enabled or not
|
description: If server is enabled or not
|
||||||
creds_id:
|
cred_id:
|
||||||
type: integer
|
type: integer
|
||||||
description: The ID of the credentials
|
description: The ID of the credentials
|
||||||
port:
|
port:
|
||||||
|
@ -158,6 +155,18 @@ class ServerView(MethodView):
|
||||||
group_id:
|
group_id:
|
||||||
type: integer
|
type: integer
|
||||||
description: The ID of the group to create the server for. Only for superAdmin role
|
description: The ID of the group to create the server for. Only for superAdmin role
|
||||||
|
type_ip:
|
||||||
|
type: integer
|
||||||
|
description: Is server virtual (VIP address) or not
|
||||||
|
master:
|
||||||
|
type: integer
|
||||||
|
description: Server id of the master server
|
||||||
|
firewall_enable:
|
||||||
|
type: integer
|
||||||
|
description: Is firewalld enabled or not
|
||||||
|
protected:
|
||||||
|
type: integer
|
||||||
|
description: Is the server protected from changes by a non-admin role
|
||||||
responses:
|
responses:
|
||||||
201:
|
201:
|
||||||
description: Server creation successful
|
description: Server creation successful
|
||||||
|
@ -216,19 +225,22 @@ class ServerView(MethodView):
|
||||||
schema:
|
schema:
|
||||||
id: UpdateServer
|
id: UpdateServer
|
||||||
required:
|
required:
|
||||||
- name
|
- hostname
|
||||||
- enabled
|
- ip
|
||||||
- creds_id
|
- cred_id
|
||||||
- port
|
- port
|
||||||
- description
|
- group_id
|
||||||
properties:
|
properties:
|
||||||
name:
|
hostname:
|
||||||
type: string
|
type: string
|
||||||
description: The server name
|
description: The server name
|
||||||
|
ip:
|
||||||
|
type: string
|
||||||
|
description: The server IP or domain name
|
||||||
enabled:
|
enabled:
|
||||||
type: integer
|
type: integer
|
||||||
description: If server is enabled or not
|
description: If server is enabled or not
|
||||||
creds_id:
|
cred_id:
|
||||||
type: integer
|
type: integer
|
||||||
description: The ID of the credentials
|
description: The ID of the credentials
|
||||||
port:
|
port:
|
||||||
|
@ -240,6 +252,18 @@ class ServerView(MethodView):
|
||||||
group_id:
|
group_id:
|
||||||
type: integer
|
type: integer
|
||||||
description: The ID of the group to update the server for. Only for superAdmin role
|
description: The ID of the group to update the server for. Only for superAdmin role
|
||||||
|
type_ip:
|
||||||
|
type: integer
|
||||||
|
description: Is server virtual (VIP address) or not
|
||||||
|
master:
|
||||||
|
type: integer
|
||||||
|
description: Server id of the master server
|
||||||
|
firewall_enable:
|
||||||
|
type: integer
|
||||||
|
description: Is firewalld enabled or not
|
||||||
|
protected:
|
||||||
|
type: integer
|
||||||
|
description: Is the server protected from changes by a non-admin role
|
||||||
responses:
|
responses:
|
||||||
201:
|
201:
|
||||||
description: Server update successful
|
description: Server update successful
|
||||||
|
@ -248,7 +272,7 @@ class ServerView(MethodView):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
server_sql.update_server(
|
server_sql.update_server(
|
||||||
body.hostname, group_id, body.type_ip, body.enabled, body.master, server_id, body.cred_id, body.port, body.description,
|
body.hostname, body.ip, group_id, body.type_ip, body.enabled, body.master, server_id, body.cred_id, body.port, body.description,
|
||||||
body.firewall_enable, body.protected
|
body.firewall_enable, body.protected
|
||||||
)
|
)
|
||||||
server_ip = server_sql.select_server_ip_by_id(server_id)
|
server_ip = server_sql.select_server_ip_by_id(server_id)
|
||||||
|
@ -570,294 +594,6 @@ class ServerGroupsView(MethodView):
|
||||||
return jsonify(groups_list)
|
return jsonify(groups_list)
|
||||||
|
|
||||||
|
|
||||||
class CredView(MethodView):
|
|
||||||
methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']
|
|
||||||
decorators = [jwt_required(), get_user_params(), page_for_admin(level=2), check_group()]
|
|
||||||
|
|
||||||
def __init__(self, is_api=False):
|
|
||||||
self.is_api = is_api
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get(creds_id: int):
|
|
||||||
"""
|
|
||||||
Retrieve credential information for a specific ID
|
|
||||||
---
|
|
||||||
tags:
|
|
||||||
- 'SSH credentials'
|
|
||||||
parameters:
|
|
||||||
- in: 'path'
|
|
||||||
name: 'creds_id'
|
|
||||||
description: 'ID of the credential to retrieve'
|
|
||||||
required: true
|
|
||||||
type: 'integer'
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: 'Individual Credential Information'
|
|
||||||
schema:
|
|
||||||
type: 'object'
|
|
||||||
properties:
|
|
||||||
group_id:
|
|
||||||
type: 'integer'
|
|
||||||
description: 'Group ID the credential belongs to'
|
|
||||||
id:
|
|
||||||
type: 'integer'
|
|
||||||
description: 'Credential ID'
|
|
||||||
key_enabled:
|
|
||||||
type: 'integer'
|
|
||||||
description: 'Key status of the credential'
|
|
||||||
name:
|
|
||||||
type: 'string'
|
|
||||||
description: 'Name of the credential'
|
|
||||||
username:
|
|
||||||
type: 'string'
|
|
||||||
description: 'Username associated with the credential'
|
|
||||||
404:
|
|
||||||
description: 'Credential not found'
|
|
||||||
"""
|
|
||||||
group_id = int(g.user_params['group_id'])
|
|
||||||
try:
|
|
||||||
creds = cred_sql.get_ssh_by_id_and_group(creds_id, group_id)
|
|
||||||
for cred in creds:
|
|
||||||
return jsonify(model_to_dict(cred, exclude=[Cred.password, Cred.passphrase])), 200
|
|
||||||
except Exception as e:
|
|
||||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get credentials')
|
|
||||||
|
|
||||||
@validate(body=CredRequest)
|
|
||||||
def post(self, body: CredRequest):
|
|
||||||
"""
|
|
||||||
Create a new credential entry
|
|
||||||
---
|
|
||||||
tags:
|
|
||||||
- SSH credentials
|
|
||||||
parameters:
|
|
||||||
- in: 'path'
|
|
||||||
name: 'creds_id'
|
|
||||||
description: 'ID of the credential to retrieve'
|
|
||||||
required: true
|
|
||||||
type: 'integer'
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
schema:
|
|
||||||
id: AddCredentials
|
|
||||||
required:
|
|
||||||
- group_шв
|
|
||||||
- name
|
|
||||||
- username
|
|
||||||
- key_enabled
|
|
||||||
- password
|
|
||||||
properties:
|
|
||||||
group_id:
|
|
||||||
type: integer
|
|
||||||
description: The ID of the group to create the credential for. Only for superAdmin role
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
description: The credential name
|
|
||||||
username:
|
|
||||||
type: string
|
|
||||||
description: The username
|
|
||||||
key_enabled:
|
|
||||||
type: integer
|
|
||||||
description: If key is enabled or not
|
|
||||||
password:
|
|
||||||
type: string
|
|
||||||
description: The password
|
|
||||||
responses:
|
|
||||||
201:
|
|
||||||
description: Credential addition successful
|
|
||||||
"""
|
|
||||||
group_id = SupportClass.return_group_id(body)
|
|
||||||
try:
|
|
||||||
return ssh_mod.create_ssh_cred(body.name, body.password, group_id, body.username, body.key_enabled, self.is_api)
|
|
||||||
except Exception as e:
|
|
||||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot create new cred')
|
|
||||||
|
|
||||||
@validate(body=CredRequest)
|
|
||||||
def put(self, creds_id: int, body: CredRequest):
|
|
||||||
"""
|
|
||||||
Update a credential entry
|
|
||||||
---
|
|
||||||
tags:
|
|
||||||
- SSH credentials
|
|
||||||
parameters:
|
|
||||||
- in: 'path'
|
|
||||||
name: 'creds_id'
|
|
||||||
description: 'ID of the credential to retrieve'
|
|
||||||
required: true
|
|
||||||
type: 'integer'
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
schema:
|
|
||||||
id: UpdateCredentials
|
|
||||||
required:
|
|
||||||
- name
|
|
||||||
- username
|
|
||||||
- key_enabled
|
|
||||||
- password
|
|
||||||
properties:
|
|
||||||
group_id:
|
|
||||||
type: integer
|
|
||||||
description: The ID of the group to create the credential for. Only for superAdmin role
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
description: The credential name
|
|
||||||
username:
|
|
||||||
type: string
|
|
||||||
description: The username
|
|
||||||
key_enabled:
|
|
||||||
type: integer
|
|
||||||
description: If key is enabled or not
|
|
||||||
password:
|
|
||||||
type: string
|
|
||||||
description: The password
|
|
||||||
responses:
|
|
||||||
201:
|
|
||||||
description: Credential update successful
|
|
||||||
"""
|
|
||||||
group_id = SupportClass.return_group_id(body)
|
|
||||||
try:
|
|
||||||
self._check_is_correct_group(creds_id)
|
|
||||||
except Exception as e:
|
|
||||||
return roxywi_common.handler_exceptions_for_json_data(e, ''), 404
|
|
||||||
|
|
||||||
try:
|
|
||||||
ssh_mod.update_ssh_key(creds_id, body.name, body.password, body.key_enabled, body.username, group_id)
|
|
||||||
return BaseResponse().model_dump(mode='json'), 201
|
|
||||||
except Exception as e:
|
|
||||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot update SSH key')
|
|
||||||
|
|
||||||
def delete(self, creds_id: int):
|
|
||||||
"""
|
|
||||||
Delete a credential entry
|
|
||||||
---
|
|
||||||
tags:
|
|
||||||
- SSH credentials
|
|
||||||
parameters:
|
|
||||||
- in: 'path'
|
|
||||||
name: 'creds_id'
|
|
||||||
description: 'ID of the credential to retrieve'
|
|
||||||
required: true
|
|
||||||
type: 'integer'
|
|
||||||
responses:
|
|
||||||
204:
|
|
||||||
description: Credential deletion successful
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
self._check_is_correct_group(creds_id)
|
|
||||||
except Exception as e:
|
|
||||||
return roxywi_common.handler_exceptions_for_json_data(e, ''), 404
|
|
||||||
|
|
||||||
try:
|
|
||||||
ssh_mod.delete_ssh_key(creds_id)
|
|
||||||
return BaseResponse().model_dump(mode='json'), 204
|
|
||||||
except Exception as e:
|
|
||||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot delete SSH key')
|
|
||||||
|
|
||||||
@validate(body=CredUploadRequest)
|
|
||||||
def patch(self, creds_id: int, body: CredUploadRequest):
|
|
||||||
"""
|
|
||||||
Upload an SSH private key
|
|
||||||
---
|
|
||||||
tags:
|
|
||||||
- SSH credentials
|
|
||||||
parameters:
|
|
||||||
- in: 'path'
|
|
||||||
name: 'creds_id'
|
|
||||||
description: 'ID of the credential to retrieve'
|
|
||||||
required: true
|
|
||||||
type: 'integer'
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
schema:
|
|
||||||
id: UploadSSHKey
|
|
||||||
required:
|
|
||||||
- private_key
|
|
||||||
- passphrase
|
|
||||||
properties:
|
|
||||||
private_key:
|
|
||||||
type: string
|
|
||||||
description: The private key string
|
|
||||||
passphrase:
|
|
||||||
type: string
|
|
||||||
description: The passphrase
|
|
||||||
responses:
|
|
||||||
201:
|
|
||||||
description: SSH key upload successful
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
self._check_is_correct_group(creds_id)
|
|
||||||
except Exception as e:
|
|
||||||
return roxywi_common.handler_exceptions_for_json_data(e, ''), 404
|
|
||||||
|
|
||||||
try:
|
|
||||||
ssh_mod.upload_ssh_key(creds_id, body.private_key, body.passphrase)
|
|
||||||
return BaseResponse().model_dump(mode='json'), 201
|
|
||||||
except Exception as e:
|
|
||||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot upload SSH key')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _check_is_correct_group(creds_id: int):
|
|
||||||
if g.user_params['role'] == 1:
|
|
||||||
return True
|
|
||||||
try:
|
|
||||||
ssh = cred_sql.get_ssh(creds_id)
|
|
||||||
except RoxywiResourceNotFound:
|
|
||||||
raise RoxywiResourceNotFound
|
|
||||||
if ssh.group_id != g.user_params['group_id']:
|
|
||||||
raise RoxywiGroupMismatch
|
|
||||||
|
|
||||||
|
|
||||||
class CredsView(MethodView):
|
|
||||||
methods = ['GET']
|
|
||||||
decorators = [jwt_required(), get_user_params(), page_for_admin(level=2), check_group()]
|
|
||||||
|
|
||||||
@validate(query=GroupQuery)
|
|
||||||
def get(self, query: GroupQuery):
|
|
||||||
"""
|
|
||||||
Retrieve credential information based on group_id
|
|
||||||
---
|
|
||||||
tags:
|
|
||||||
- 'SSH credentials'
|
|
||||||
parameters:
|
|
||||||
- in: 'query'
|
|
||||||
name: 'group_id'
|
|
||||||
description: 'GroupQuery to filter servers. Only for superAdmin role'
|
|
||||||
required: false
|
|
||||||
type: 'integer'
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: 'Credentials Information'
|
|
||||||
schema:
|
|
||||||
type: 'array'
|
|
||||||
items:
|
|
||||||
type: 'object'
|
|
||||||
properties:
|
|
||||||
group_id:
|
|
||||||
type: 'integer'
|
|
||||||
description: 'Group ID the credential belongs to'
|
|
||||||
id:
|
|
||||||
type: 'integer'
|
|
||||||
description: 'Credential ID'
|
|
||||||
key_enabled:
|
|
||||||
type: 'integer'
|
|
||||||
description: 'Key status of the credential'
|
|
||||||
name:
|
|
||||||
type: 'string'
|
|
||||||
description: 'Name of the credential'
|
|
||||||
username:
|
|
||||||
type: 'string'
|
|
||||||
description: 'Username of the credential'
|
|
||||||
"""
|
|
||||||
group_id = SupportClass.return_group_id(query)
|
|
||||||
try:
|
|
||||||
creds = cred_sql.select_ssh(group=group_id)
|
|
||||||
json_data = []
|
|
||||||
for cred in creds:
|
|
||||||
json_data.append(model_to_dict(cred, exclude=[Cred.password, Cred.passphrase]))
|
|
||||||
return jsonify(json_data), 200
|
|
||||||
except Exception as e:
|
|
||||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get credentials')
|
|
||||||
|
|
||||||
|
|
||||||
class ServerIPView(MethodView):
|
class ServerIPView(MethodView):
|
||||||
class ServersView(MethodView):
|
class ServersView(MethodView):
|
||||||
methods = ["GET"]
|
methods = ["GET"]
|
||||||
|
|
|
@ -12,7 +12,6 @@ slack-sdk>=3.4.0
|
||||||
peewee>=3.14.10
|
peewee>=3.14.10
|
||||||
PyMySQL>=1.0.2
|
PyMySQL>=1.0.2
|
||||||
distro>=1.2.0
|
distro>=1.2.0
|
||||||
bottle>=0.12.20
|
|
||||||
psutil>=5.9.1
|
psutil>=5.9.1
|
||||||
pdpyras>=4.5.2
|
pdpyras>=4.5.2
|
||||||
pika>=1.3.1
|
pika>=1.3.1
|
||||||
|
|
Loading…
Reference in New Issue