diff --git a/app/db_model.py b/app/db_model.py index 505eb551..cc78e9a8 100644 --- a/app/db_model.py +++ b/app/db_model.py @@ -13,7 +13,7 @@ if mysql_enable == '1': conn = MySQLDatabase(mysql_db, user=mysql_user, password=mysql_password, host=mysql_host, port=int(mysql_port)) else: db = "/var/www/haproxy-wi/app/roxy-wi.db" - conn = SqliteDatabase(db, pragmas={'timeout': 1000}) + conn = SqliteDatabase(db, pragmas={'timeout': 1000, 'foreign_keys': 1}) class BaseModel(Model): @@ -495,10 +495,25 @@ class UserName(BaseModel): primary_key = False +class GitSetting(BaseModel): + id = AutoField() + server_id = ForeignKeyField(Server, on_delete='Cascade') + service_id = IntegerField() + period = CharField() + repo = CharField(null=True) + branch = CharField(null=True) + cred_id = IntegerField() + description = CharField(null=True) + + class Meta: + table_name = 'git_setting' + constraints = [SQL('UNIQUE (server_id, service_id)')] + + def create_tables(): with conn: conn.create_tables([User, Server, Role, Telegram, Slack, UUID, Token, ApiToken, Groups, UserGroups, ConfigVersion, Setting, Cred, Backup, Metrics, WafMetrics, Version, Option, SavedServer, Waf, ActionHistory, PortScannerSettings, PortScannerPorts, PortScannerHistory, ProvidersCreds, ServiceSetting, ProvisionedServers, MetricsHttpStatus, SMON, WafRules, Alerts, GeoipCodes, NginxMetrics, - SystemInfo, Services, UserName]) + SystemInfo, Services, UserName, GitSetting]) diff --git a/app/funct.py b/app/funct.py index c4430d49..ddc70c50 100644 --- a/app/funct.py +++ b/app/funct.py @@ -948,13 +948,7 @@ def upload_and_restart(server_ip, cfg, **kwargs): if haproxy_enterprise == '1': service_name = "hapee-2.0-lb" if service == 'apache': - server_id = sql.select_server_id_by_ip(server_ip) - os_info = sql.select_os_info(server_id) - - if "CentOS" in os_info or "Redhat" in os_info: - service_name = 'httpd' - else: - service_name = 'apache2' + get_correct_apache_service_name(server_ip) reload_command = " && sudo systemctl reload " + service_name restart_command = " && sudo systemctl restart " + service_name @@ -1998,9 +1992,12 @@ def return_user_status(): return user_status, user_plan -def get_correct_apache_service_name(server_ip): +def get_correct_apache_service_name(server_ip=0, server_id=0): import sql - server_id = sql.select_server_id_by_ip(server_ip) + + if server_id == 0: + server_id = sql.select_server_id_by_ip(server_ip) + os_info = sql.select_os_info(server_id) if "CentOS" in os_info or "Redhat" in os_info: diff --git a/app/options.py b/app/options.py index d78206e0..ed7e30e3 100644 --- a/app/options.py +++ b/app/options.py @@ -478,13 +478,8 @@ if form.getvalue('action_apache') is not None and serv is not None: container_name = sql.get_setting('apache_container_name') commands = ["sudo docker %s %s" % (action, container_name)] else: - os_info = sql.select_os_info(server_id) + service_apache_name = funct.get_correct_apache_service_name(0, server_id) - if "CentOS" in os_info or "Redhat" in os_info: - service_apache_name = 'httpd' - else: - service_apache_name = 'apache2' - commands = ["sudo systemctl %s %s" % (action, service_apache_name)] funct.ssh_command(serv, commands) funct.logging(serv, 'Service has been ' + action + 'ed', haproxywi=1, login=1, keep_history=1, service='apache') @@ -1668,6 +1663,79 @@ if form.getvalue('backup') or form.getvalue('deljob') or form.getvalue('backupup print('Ok') funct.logging('backup ', ' a backup job for server ' + serv + ' has been updated', haproxywi=1, login=1) +if form.getvalue('git_backup'): + server_id = form.getvalue('server') + service_id = form.getvalue('git_service') + git_init = form.getvalue('git_init') + repo = form.getvalue('git_repo') + branch = form.getvalue('git_branch') + period = form.getvalue('time') + cred = form.getvalue('cred') + deljob = form.getvalue('git_deljob') + description = form.getvalue('description') + servers = sql.get_dick_permit() + proxy = sql.get_setting('proxy') + services = sql.select_services() + server_ip = sql.select_server_ip_by_id(server_id) + service_name = sql.select_service_name_by_id(service_id).lower() + service_config_dir = sql.get_setting(service_name + '_dir') + script = 'git_backup.sh' + ssh_port = 22 + ssh_enable, ssh_user_name, ssh_user_password, ssh_key_name = funct.return_ssh_keys_path('localhost', + id=int(cred)) + + os.system("cp scripts/%s ." % script) + + if proxy is not None and proxy != '' and proxy != 'None': + proxy_serv = proxy + else: + proxy_serv = '' + + servers = sql.select_servers(server=server_ip) + for server in servers: + ssh_port = str(server[10]) + + if repo is None or git_init == '0': + repo = '' + if branch is None: + branch = 'main' + + commands = ["chmod +x " + script + " && ./" + script + " HOST=" + server_ip + " DELJOB=" + deljob + + " SERVICE=" + service_name + " INIT=" + git_init + " SSH_PORT=" + ssh_port + " PERIOD=" + period + + " REPO=" + repo + " BRANCH=" + branch + " CONFIG_DIR=" + service_config_dir + + " PROXY=" + proxy_serv + " USER=" + str(ssh_user_name) + " KEY=" + str(ssh_key_name)] + + output, error = funct.subprocess_execute(commands[0]) + + for l in output: + if "Traceback" in l or "FAILED" in l: + try: + print('error: ' + l) + break + except Exception: + print('error: ' + output) + break + else: + if deljob == '0': + if sql.insert_new_git(server_id=server_id, service_id=service_id, repo=repo, branch=branch, + period=period, cred=cred, description=description): + from jinja2 import Environment, FileSystemLoader + + gits = sql.select_gits(server_id=server_id, service_id=service_id) + sshs = sql.select_ssh() + + env = Environment(loader=FileSystemLoader('templates/ajax'), autoescape=True) + template = env.get_template('new_git.html') + template = template.render(gits=gits, sshs=sshs, servers=servers, services=services, new_add=1) + print(template) + print('success: Git job has been created') + funct.logging(server_ip, ' A new git job has been created', haproxywi=1, login=1, + keep_history=1, service=service_name) + else: + if sql.delete_git(form.getvalue('git_backup')): + print('Ok') + os.system("rm -f %s" % script) + if form.getvalue('install_nginx'): funct.install_nginx(form.getvalue('install_nginx'), docker=form.getvalue('docker')) diff --git a/app/scripts/ansible/roles/git_backup.yml b/app/scripts/ansible/roles/git_backup.yml new file mode 100644 index 00000000..16272ccc --- /dev/null +++ b/app/scripts/ansible/roles/git_backup.yml @@ -0,0 +1,75 @@ +- hosts: "{{ variable_host }}" + become: yes + become_method: sudo + gather_facts: no + tasks: + + - name: Install git + package: + name: git + state: present + environment: + http_proxy: "{{PROXY}}" + https_proxy: "{{PROXY}}" + when: INIT == '1' + + - name: Create home dir + file: + path: '/home/{{ ansible_user }}/.ssh' + state: directory + mode: 0700 + group: '{{ ansible_user }}' + owner: '{{ ansible_user }}' + when: INIT == '1' + + - name: Copy ssh file + copy: + src: '{{ KEY }}' + dest: '/home/{{ ansible_user }}/.ssh/id_rsa' + mode: 0600 + group: '{{ ansible_user }}' + owner: '{{ ansible_user }}' + force: no + when: INIT == '1' + + - name: Add write permisions + shell: "chmod o+wr -R {{ CONFIG_DIR }}" + + - name: Git init + shell: 'cd {{ CONFIG_DIR }} && git init' + when: INIT == '1' + become: no + + - name: Git configure + blockinfile: + path: "{{ CONFIG_DIR }}/.git/config" + block: | + [user] + name = Roxy-WI + email = roxy-wi@.com + when: INIT == '1' + + - 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 }}' + when: INIT == '1' + become: no + + - name: Git add push + shell: 'cd {{ CONFIG_DIR }} && GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no" git push -u origin {{ BRANCH }}' + when: INIT == '1' + become: no + + - name: Creates git job + cron: + name: "Git backup {{ SERVICE }} configs" + special_time: "{{ PERIOD }}" + job: 'cd {{ CONFIG_DIR }} && git add --all . && git commit -m "Roxy-WI backup job at $(date)" && git push --set-upstream origin {{ BRANCH }}' + when: DELJOB == '0' + become: no + + - name: Removes git backup job + cron: + name: "Git backup {{ SERVICE }} configs" + state: absent + when: DELJOB == '1' + become: no diff --git a/app/scripts/git_backup.sh b/app/scripts/git_backup.sh new file mode 100644 index 00000000..fc744409 --- /dev/null +++ b/app/scripts/git_backup.sh @@ -0,0 +1,41 @@ +#!/bin/bash +for ARGUMENT in "$@" +do + KEY=$(echo $ARGUMENT | cut -f1 -d=) + VALUE=$(echo $ARGUMENT | cut -f2 -d=) + + case "$KEY" in + HOST) HOST=${VALUE} ;; + DELJOB) DELJOB=${VALUE} ;; + SERVICE) SERVICE=${VALUE} ;; + INIT) INIT=${VALUE} ;; + REPO) REPO=${VALUE} ;; + BRANCH) BRANCH=${VALUE} ;; + PERIOD) PERIOD=${VALUE} ;; + CONFIG_DIR) CONFIG_DIR=${VALUE} ;; + USER) USER=${VALUE} ;; + KEY) KEY=${VALUE} ;; + SSH_PORT) SSH_PORT=${VALUE} ;; + PROXY) PROXY=${VALUE} ;; + *) + esac +done + +export ANSIBLE_HOST_KEY_CHECKING=False +export ANSIBLE_DISPLAY_SKIPPED_HOSTS=False +export ACTION_WARNINGS=False +export LOCALHOST_WARNING=False +export COMMAND_WARNINGS=False + +PWD=`pwd` +PWD=$PWD/scripts/ansible/ +echo "$HOST ansible_port=$SSH_PORT" >> $PWD/$HOST + + +ansible-playbook $PWD/roles/git_backup.yml --key-file $KEY -e "ansible_user=$USER variable_host=$HOST DELJOB=$DELJOB SERVICE=$SERVICE INIT=$INIT REPO=$REPO BRANCH=$BRANCH PERIOD=$PERIOD CONFIG_DIR=$CONFIG_DIR PROXY=$PROXY KEY=$KEY" -i $PWD/$HOST + +if [ $? -gt 0 ] +then + echo "error: Cannot create a git job" +fi +rm -f $PWD/$HOST \ No newline at end of file diff --git a/app/servers.py b/app/servers.py index 0034fe89..a4e41f54 100644 --- a/app/servers.py +++ b/app/servers.py @@ -16,6 +16,7 @@ try: settings = sql.get_setting('', all=1) geoip_country_codes = sql.select_geoip_country_codes() services = sql.select_services() + gits = sql.select_gits() except Exception as e: pass @@ -44,5 +45,6 @@ output_from_parsed_template = template.render(title="Servers: ", ldap_enable=ldap_enable, user_status=user_status, user_plan=user_plan, + gits=gits, services=services) print(output_from_parsed_template) diff --git a/app/sql.py b/app/sql.py index e0175297..0d80bb38 100755 --- a/app/sql.py +++ b/app/sql.py @@ -3146,6 +3146,15 @@ def select_services(): return query_res +def select_service_name_by_id(service_id): + try: + service = Services.get(Services.service_id == service_id).service + except Exception as e: + return out_error(e) + else: + return service + + def insert_user_name(user_name): try: UserName.insert(UserName=user_name).execute() @@ -3211,3 +3220,38 @@ def select_user_all(): return False else: return query_res + + +def insert_new_git(server_id, service_id, repo, branch, period, cred, description): + try: + GitSetting.insert(server_id=server_id, service_id=service_id, repo=repo, branch=branch, period=period, cred_id=cred, + description=description).execute() + except Exception as e: + out_error(e) + return False + else: + return True + +def select_gits(**kwargs): + if kwargs.get("server_id") is not None and kwargs.get("service_id") is not None: + query = GitSetting.select().where((GitSetting.server_id == kwargs.get("server_id")) & (GitSetting.service_id == kwargs.get("service_id"))) + else: + query = GitSetting.select().order_by(GitSetting.id) + + try: + query_res = query.execute() + except Exception as e: + out_error(e) + else: + return query_res + + +def delete_git(git_id): + query = GitSetting.delete().where(GitSetting.id == git_id) + try: + query.execute() + except Exception as e: + out_error(e) + return False + else: + return True diff --git a/app/templates/ajax/new_git.html b/app/templates/ajax/new_git.html new file mode 100644 index 00000000..a07e0f52 --- /dev/null +++ b/app/templates/ajax/new_git.html @@ -0,0 +1,62 @@ +{% for b in gits %} + {% for server in servers %} + {% if server.0|string() == b.server_id|string() %} + + + + {{ server.1 }} + + + {% for s in services %} + {% if s.service_id == b.service_id %} + + {{ s.service }} + {% endif %} + {% endfor %} + + + {% set values = {'hourly':'hourly','daily':'daily','weekly':'weekly', 'monthly':'monthly'} %} + {% for v, des in values|dictsort(false, 'value') %} + {% if v == b.period %} + {{ des }} + {% endif %} + {% endfor %} + + + + {% if b.repo %} + {{ b.repo }} + {% endif %} + + + + + {% if b.branch %} + {{ b.branch }} + {% endif %} + + + + {% for ssh in sshs %} + {% if ssh.enable == 1 %} + {% if ssh.id == b.cred_id %} + + {{ ssh.name }} + {% endif %} + {% endif %} + {% endfor %} + + + + {% if b.description %} + {{b.description}} + {% endif %} + + + + + + + {% endif %} + {% endfor %} +{% endfor %} diff --git a/app/templates/include/admin_backup.html b/app/templates/include/admin_backup.html index a26cf546..12d3cdc1 100644 --- a/app/templates/include/admin_backup.html +++ b/app/templates/include/admin_backup.html @@ -1,6 +1,41 @@ - {% if user_status == 0 or user_plan == 'user' %} - {% include 'include/no_sub.html' %} - {% else %} +
+ + +
+ {% if user_status == 0 or user_plan == 'user' %} + {% include 'include/no_sub.html' %} + {% else %} + + + + + + + + + + + + + + + {% include 'ajax/new_git.html' %} + +
ServersServicePeriodRepoBranchCredentialsDescription
+
+ Add git job +

+
+ You can read the description of all parameters here +
+ {% endif %} +
+
+ {% if user_status == 0 or user_plan == 'user' %} + {% include 'include/no_sub.html' %} + {% else %} @@ -73,4 +108,6 @@
You can read the description of all parameters here
- {% endif %} + {% endif %} + + diff --git a/app/templates/include/admins_dialogs.html b/app/templates/include/admins_dialogs.html index 44fb0985..bc509f62 100644 --- a/app/templates/include/admins_dialogs.html +++ b/app/templates/include/admins_dialogs.html @@ -236,10 +236,10 @@
Servers @@ -255,6 +255,99 @@
+ diff --git a/app/users.py b/app/users.py index 4f60c165..c0c6fcaa 100644 --- a/app/users.py +++ b/app/users.py @@ -20,6 +20,7 @@ try: ldap_enable = sql.get_setting('ldap_enable') grafana, stderr = funct.subprocess_execute("systemctl is-active grafana-server") services = sql.select_services() + gits = sql.select_gits() except Exception: pass @@ -48,5 +49,6 @@ template = template.render(title="Admin area: Manage users", ldap_enable=ldap_enable, user_status=user_status, user_plan=user_plan, + gits=gits, services=services) print(template) diff --git a/inc/users.js b/inc/users.js index 80ba6646..8e5cb330 100644 --- a/inc/users.js +++ b/inc/users.js @@ -1,6 +1,7 @@ var awesome = "/inc/fontawesome.min.js" $( function() { + $( "#backup_tabs" ).tabs(); $( "#interface" ).autocomplete({ source: function( request, response ) { $.ajax( { @@ -585,6 +586,41 @@ $( function() { } } }); + $('#add-git-button').click(function() { + addGitDialog.dialog('open'); + }); + var addGitDialog = $( "#git-add-table" ).dialog({ + autoOpen: false, + resizable: false, + height: "auto", + width: 600, + modal: true, + title: "Create a new git job", + show: { + effect: "fade", + duration: 200 + }, + hide: { + effect: "fade", + duration: 200 + }, + buttons: { + "Add": function () { + addGit(this); + }, + Cancel: function () { + $(this).dialog("close"); + clearTips(); + } + } + }); + $('#git-init').click(function() { + if ($('#git-init').is(':checked')) { + $('.git-init-params').show(); + } else { + $('.git-init-params').hide(); + } + }); $( "#ajax-users input" ).change(function() { var id = $(this).attr('id').split('-'); updateUser(id[1]) @@ -994,6 +1030,14 @@ function addServer(dialog_id) { $( "input[type=checkbox]" ).checkboxradio(); $( ".controlgroup" ).controlgroup(); $( "select" ).selectmenu(); + var getId = new RegExp('server-[0-9]+'); + var id = data.match(getId) + ''; + id = id.split('-').pop(); + $('select:regex(id, git-server)').append('').selectmenu("refresh"); + $('select:regex(id, backup-server)').append('').selectmenu("refresh"); + $('select:regex(id, haproxy_exp_addserv)').append('').selectmenu("refresh"); + $('select:regex(id, nginx_exp_addserv)').append('').selectmenu("refresh"); + $('select:regex(id, node_exp_addserv)').append('').selectmenu("refresh"); } } } ); @@ -1169,6 +1213,54 @@ function addBackup(dialog_id) { } ); } } +function addGit(dialog_id) { + var valid = true; + toastr.clear(); + allFields = $( [] ).add( $('#git-server') ).add( $('#git-service') ).add( $('#git-time')).add( $('#git-credentials') ).add( $('#git-branch') ) + allFields.removeClass( "ui-state-error" ); + valid = valid && checkLength( $('#git-server'), "Server ", 1 ); + valid = valid && checkLength( $('#git-service'), "Service", 1 ); + valid = valid && checkLength( $('#git-credentials'), "Credentials", 1 ); + valid = valid && checkLength( $('#git-branch'), "Branch name", 1 ); + var git_init = 0; + if ($('#git-init').is(':checked')) { + git_init = '1'; + } + if (valid) { + $.ajax( { + url: "options.py", + data: { + git_backup: '1', + server: $('#git-server').val(), + git_service: $('#git-service').val(), + git_init: git_init, + git_repo: $('#git-repo').val(), + git_branch: $('#git-branch').val(), + time: $('#git-time').val(), + cred: $('#git-credentials').val(), + description: $('#git-description').val(), + git_deljob: 0, + token: $('#token').val() + }, + type: "POST", + success: function( data ) { + data = data.replace(/\s+/g,' '); + if (data.indexOf('error:') != '-1') { + toastr.error(data); + } else if (data.indexOf('success: ') != '-1') { + common_ajax_action_after_success(dialog_id, 'newgit', 'ajax-git-table', data); + $( "select" ).selectmenu(); + } else if (data.indexOf('info: ') != '-1') { + toastr.clear(); + toastr.info(data); + } else if (data.indexOf('warning: ') != '-1') { + toastr.clear(); + toastr.warning(data); + } + } + } ); + } +} function updateSettings(param, val) { toastr.clear(); $.ajax( { @@ -1322,7 +1414,7 @@ function confirmDeleteBackup(id) { height: "auto", width: 400, modal: true, - title: "Are you sure you want to delete job for" +$('#backup-server-'+id).val() + "?", + title: "Are you sure you want to delete job for " +$('#backup-server-'+id).val() + "?", buttons: { "Delete": function() { $( this ).dialog( "close" ); @@ -1334,6 +1426,24 @@ function confirmDeleteBackup(id) { } }); } +function confirmDeleteGit(id) { + $( "#dialog-confirm" ).dialog({ + resizable: false, + height: "auto", + width: 400, + modal: true, + title: "Are you sure you want to delete job for " +$('#git-server-'+id).text() + "?", + buttons: { + "Delete": function() { + $( this ).dialog( "close" ); + removeGit(id); + }, + Cancel: function() { + $( this ).dialog( "close" ); + } + } + }); +} function cloneServer(id) { $( "#add-server-button" ).trigger( "click" ); if ($('#enable-'+id).is(':checked')) { @@ -1554,6 +1664,33 @@ function removeBackup(id) { } } ); } +function removeGit(id) { + $("#git-table-"+id).css("background-color", "#f2dede"); + $.ajax( { + url: "options.py", + data: { + git_backup: id, + git_deljob: 1, + git_init: 0, + repo: 0, + branch: 0, + time: 0, + cred: $('#git-credentials-id-'+id).text(), + server: $('#git-server-id-'+id).text(), + git_service: $('#git-service-id-'+id).text(), + token: $('#token').val() + }, + type: "POST", + success: function( data ) { + data = data.replace(/\s+/g,' '); + if(data.indexOf('Ok') != '-1') { + $("#git-table-"+id).remove(); + } else if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { + toastr.error(data); + } + } + } ); +} function updateUser(id) { toastr.remove(); cur_url[0] = cur_url[0].split('#')[0]