First files to the project

This commit is contained in:
Antonio de la Rosa 2022-02-07 00:35:21 +01:00
commit cda8eb1232
26 changed files with 2657 additions and 0 deletions

108
.gitignore vendored Normal file
View file

@ -0,0 +1,108 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
.static_storage/
.media/
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
/backups
/settings/config.py
/media/js/jsutils

3
__init__.py Normal file
View file

@ -0,0 +1,3 @@
from flask import Blueprint, g
pastafari_app=Blueprint('pastafari_app', __name__)

541
admin/dashboard.py Normal file
View file

@ -0,0 +1,541 @@
from settings import config
from flask import g, url_for, request, session, make_response
from paramecio2.libraries.generate_admin_class import GenerateAdminClass
from paramecio2.libraries.i18n import I18n
from paramecio2.modules.admin import admin_app, t as admin_t
from paramecio2.libraries.db.coreforms import SelectForm, SelectModelForm
from paramecio2.libraries.mtemplates import PTemplate, env_theme
from paramecio2.libraries import datetime
from paramecio2.libraries.urls import make_media_url
from modules.monit.models.monit import Server, ServerData, Alerts
from paramecio2.libraries.db.webmodel import WebModel
from paramecio2.libraries.lists import AjaxList
from paramecio2.libraries.db.extraforms.fileform import FileForm
from paramecio2.libraries.formsutils import show_form
from modules.pastafari2.libraries.task import Task as SSHTask
from modules.pastafari2.models.tasks import Task, LogTask
from modules.pastafari2.libraries.configtask import config_task
from modules.pastafari2.models.pastafari2 import ServerGroup
from pathlib import Path
import paramiko
import socket
import os
try:
import ujson as json
except:
import json
env=env_theme(__file__)
t=PTemplate(env)
t.env.directories=admin_t.env.directories
t.env.directories.insert(1, os.path.dirname(__file__).replace('/admin', '')+'/templates/admin')
system_path='./ssh/'
@admin_app.route('/pastafari2/dashboard/')
def pastafari2_dashboard():
return t.load_template('dash_pastafari.phtml', title=I18n.lang('pastafari2', 'servers_dashboard', 'Servers Dashboard'), path_module='admin_app.pastafari2_dashboard')
@admin_app.route('/pastafari2/settings/')
def pastafari2_settings():
"""
forms={}
forms['ssh_key_priv']=FileForm('ssh_key_priv', '', '')
forms['ssh_key_pub']=FileForm('ssh_key_pub', '', '')
forms['ssh_key_priv'].help=I18n.lang('pastafari2', 'ssh_key_priv_file_help', 'Global private SSH key used for enter in servers')
forms['ssh_key_pub'].help=I18n.lang('pastafari2', 'ssh_key_pub_file_help', 'Global public SSH key used for enter in servers')
forms['ssh_key_priv'].label=I18n.lang('pastafari2', 'ssh_key_priv_file', 'Global private SSH')
forms['ssh_key_pub'].label=I18n.lang('pastafari2', 'ssh_key_pub_file', 'Global public SSH')
forms['ssh_key_priv'].required=True
forms['ssh_key_pub'].required=True
html_forms=show_form({}, forms, t, yes_error=False, pass_values=True, modelform_tpl='forms/modelform.phtml')
"""
txt_error=''
txt_generate_key='<p>You have created your ssh keys</p>'
txt_generate_key_button='Regenerate SSH keys'
regenerate=True
if not os.path.isdir(system_path):
try:
Path(system_path).mkdir(mode=511)
except:
txt_error='<p><strong>You need create ssh directory for save ssh keys</strong></p>'
#Get ssh key
if not os.path.isfile(system_path+'id_rsa'):
txt_generate_key='<p>You need generate a global private ssh key, because doesn\'t exists</p>'
txt_generate_key_button='Generate SSH keys'
regenerate=False
pass
return t.load_template('settings.phtml', title=I18n.lang('pastafari2', 'settings', 'Settings'), path_module='admin_app.pastafari2_settings', txt_error=txt_error, txt_generate_key=txt_generate_key, txt_generate_key_button=txt_generate_key_button, regenerate=regenerate)
@admin_app.route('/pastafari2/edit_global_ssh_keys/', methods=['POST'])
def pastafari2_edit_global_ssh_keys():
form={}
error=0
if not os.path.isfile(system_path+'id_rsa'):
try:
key=paramiko.RSAKey.generate(2048)
key.write_private_key_file(system_path+'id_rsa')
with open(system_path+'id_rsa.pub',"w") as pub_key:
pub_key.write("%s %s" % (key.get_name(), key.get_base64()))
except:
error=1
"""
if not 'ssh_key_priv_file' in request.files:
error=1
form['ssh_key_priv']='ssh private key file required'
if not 'ssh_key_pub_file' in request.files:
error=1
form['ssh_key_pub']='ssh public key file required'
if not error:
ssh_key_priv=request.files['ssh_key_priv_file']
ssh_key_pub=request.files['ssh_key_pub_file']
if ssh_key_priv.filename=='':
error=1
form['ssh_key_priv']='ssh private key file required'
if ssh_key_pub.filename=='':
error=1
form['ssh_key_pub']='ssh private key file required'
if not os.path.isdir(system_path):
try:
Path(system_path).mkdir(mode=511)
except:
error=1
form['ssh_key_priv']='You need create ssh directory for save ssh keys'
if not error:
#Load keys
#Check keys
pass
"""
#return {'form': form, 'error': error}
return {'error': error}
@admin_app.route('/pastafari2/add_server/')
def pastafari2_add_server():
db=g.connection
group_form=SelectModelForm('group_id', '', ServerGroup(db), 'group', 'id', field_parent=None)
return t.load_template('add_server.phtml', title=I18n.lang('pastafari2', 'add_server', 'Add server'), path_module='admin_app.pastafari2_dashboard', group_form=group_form)
@admin_app.route('/pastafari2/add_server_task/', methods=['POST'])
def pastafari2_add_server_task():
db=g.connection
#task=Task(db)
#task.safe_query()
#logtask=LogTask(db)
#server=ServerTask(db)
#(self, server, conn, remote_user='root', remote_password='', private_key='./ssh/id_rsa', password_key='', remote_path='leviathan', task_id=0, data={}):
error_form={}
server_host=request.form.get('server_host', '')
server_username=request.form.get('server_username', '')
server_password=request.form.get('server_password', '')
repeat_server_password=request.form.get('repeat_server_password', '')
group_id=request.form.get('group_id', '')
private_key='./ssh/id_rsa'
public_key='./ssh/id_rsa.pub'
remote_path='pastafari2'
task_id=0
ip=''
error=0
data={}
ssh_user=config_task.remote_user
#make ping to server
if server_host=='':
error=1
error_form['#server_host_error']=I18n.lang('pastafari2', 'error_hostname', 'Error: you need enter a valid hostname')
txt_error=''
try:
#print("IP address of %s: %s" %(remote_host, socket.gethostbyname(remote_host)))
ip=socket.gethostbyname(server_host)
pass
except socket.error as err_msg:
error=1
error_form['#server_host_error']=I18n.lang('pastafari2', 'error_getting_ip_host', 'Error: '+err_msg)
if not error:
group_name=''
if group_id!='':
server_group=ServerGroup(db)
arr_group=server_group.set_conditions('WHERE id=%s', [group_id]).select_a_row_where()
group_name=arr_group['group']
data={'ssh_user': ssh_user, 'pub_key': public_key, 'url_stats': config.domain_url+url_for('monit_app.monit_get_data', api_key=config.monit_api_key), 'hostname': server_host, 'ip': ip, 'group_id': group_id, 'group_name': group_name}
with SSHTask(server_host, db, remote_user=server_username, remote_password=server_password, private_key=private_key, remote_path=remote_path, task_id=task_id, data=data) as ssh_task:
if not ssh_task.prepare_connection():
error=1
txt_error=I18n.lang('pastafari2', 'error_connection', 'Error: cannot connect to server')
error_form['#server_host_error']=I18n.lang('pastafari2', 'error_connection', 'Error: cannot connect to server')
else:
# Prepare task for install monit
pass
task=Task(db)
task_id=0
path_task='modules.pastafari2.tasks.system.task'
if not task.run_task(server_host, path_task, 'Add new server', 'add_new_server', 'Task for add a new server', user=server_username, password=server_password, where_sql_server='', url='', data=data, send_task=True):
error=1
error_form['#server_host_error']=I18n.lang('pastafari2', 'error_exec_task', 'Error: cannot execute the task')
task_id=task.task_id
return {'error': error, 'txt_error': txt_error, 'error_form': error_form, 'task_id': task_id}
# Maybe translate to api
@admin_app.route('/pastafari2/progress/')
def pastafari2_progress():
db=g.connection
task_id=request.args.get('task_id', '0')
position=request.args.get('position', '0')
task=Task(db)
arr_task=task.set_conditions('WHERE id=%s', [task_id]).select_a_row_where()
#print(arr_task)
return t.load_template('progress.phtml', title=I18n.lang('pastafari2', 'task_progress', 'Task progress'), path_module='admin_app.pastafari2_dashboard', name_task=arr_task['name_task'], description_task=arr_task['description_task'], position=position, task_id=task_id, server=arr_task['server'])
@admin_app.route('/pastafari2/getprogress/', methods=['POST'])
def pastafari2_getprogress():
s=session
db=g.connection
if request.args.get('task_id', '0')=='0':
s['get_progress']=s.get('get_progress', 0)
try:
task_id=int(request.args.get('task_id', '0'))
except:
task_id=0
try:
position=int(request.args.get('position', '0'))
except:
position=0
task=Task(db)
logtask=LogTask(db)
arr_task=task.select_a_row(task_id)
arr_rows={'wait': 1}
if arr_task:
logtask.set_limit([position, 5])
logtask.set_order({'id': 0})
logtask.conditions=['WHERE task_id=%s', [task_id]]
server=request.args.get('server', '')
if server!='':
logtask.conditions=['WHERE task_id=%s and logtask.server=%s', [task_id, server]]
logtask.yes_reset_conditions=False
c=0
arr_rows=[]
with logtask.select([], True) as cursor:
for arr_row in cursor:
arr_rows.append(arr_row)
c+=1
if c==0:
arr_rows=[]
c_error=logtask.set_conditions('WHERE task_id=%s and logtask.error=%s and logtask.status=%s', [task_id, 1, 1]).select_count()
if c_error==0:
arr_rows={'wait': 1}
else:
logtask.limit=''
with logtask.set_conditions('WHERE task_id=%s and logtask.error=%s and logtask.status=%s', [task_id, 1, 1]).select([], True) as cursor:
for arr_row in cursor:
arr_rows.append(arr_row)
else:
arr_rows=[{'task_id': task_id, 'progress': 100, 'message': 'Error: no exists task', 'error': 1, 'status': 1}]
db.close()
#header=response.headers
resp=make_response(json.dumps(arr_rows))
resp.headers['Content-Type']='application/json'
return resp
@admin_app.route('/pastafari2/get_servers/', methods=['POST'])
def get_servers_task():
db=g.connection
group_sql=''
count_data=[]
sql_data=[]
group_id=request.form.get('group_id', '')
group_sql_count=''
group_sql=''
if group_id!='':
group_sql_count=' WHERE `group_id`=%s'
count_data=[group_id]
sql_data=[group_id]
group_sql=' WHERE `group_id`=%s'
fields=[[I18n.lang('pastafari2', 'hostname', 'Hostname'), True], ['IP', True], [I18n.lang('pastafari2', 'selected', 'Selected'), False], [I18n.lang('pastafari2', 'options', 'Options'), False]]
arr_order_fields=['hostname', 'ip']
count_query=['select count(serverdbtask.id) as num_elements from serverdbtask'+group_sql_count, count_data]
# server.id as select_id,
# select hostname, ip, date, num_updates, id from serverofuser where user_id=%s;
str_query=['select serverdbtask.hostname, serverdbtask.ip, serverdbtask.id as select_id, serverdbtask.id from serverdbtask'+group_sql, sql_data]
ajax=AjaxList(db, fields, arr_order_fields, count_query, str_query)
#ajax.func_fields['id']=options_server
#ajax.func_fields['ip']=options_ip
ajax.func_fields['select_id']=options_selected
ajax.func_fields['id']=options_options
ajax.limit=0
#{'fields': [['Hostname', True], ['IP', True], ['Status', True], ['Options', False]], 'rows': [{'hostname': 'debian-pc.localdomain', 'ip': '<span id="ip_192.168.122.125">192.168.122.125</span>', 'date': '<img src="/mediafrom/pastafari2/images/status_green.png" />', 'id': '<a href="#">View stats</a>'}, {'hostname': 'DESKTOP-HLHPSSO', 'ip': '<span id="ip_192.168.122.81">192.168.122.81</span>', 'date': '<img src="/mediafrom/pastafari2/images/status_green.png" />', 'id': '<a href="#">View stats</a>'}], 'html_pages': ''}
return ajax.show()
"""
def options_server(row_id, row):
#'<a href="{}">{}</a>'.format(url_for('.services', server_id=row_id), I18n.lang('monit', 'services', 'Services'))
arr_options=['<a href="{}">{}</a>'.format("", I18n.lang('pastafari2', 'edit', 'Edit'))]
arr_options.append('<a href="{}">{}</a>'.format("", I18n.lang('pastafari2', 'make_task', 'Make task')))
arr_options.append('<a href="{}">{}</a>'.format("", I18n.lang('pastafari2', 'delete', 'Delete')))
"""
def options_selected(row_id, row):
return '<input type="checkbox" name="server_id_{}" class="server_id" value="{}"/>'.format(row_id, row_id)
def options_options(row_id, row):
arr_options=['<a href="{}">{}</a>'.format("", I18n.lang('pastafari2', 'edit', 'Edit'))]
#arr_options.append('<a href="{}">{}</a>'.format("", I18n.lang('pastafari2', 'make_task', 'Make task')))
arr_options.append('<a href="{}">{}</a>'.format("", I18n.lang('pastafari2', 'delete', 'Delete')))
return '<br />'.join(arr_options)
@admin_app.route('/pastafari2/get_groups/', methods=['GET'])
def get_groups_task():
db=g.connection
arr_groups=[]
with db.query('select * from servergroup', []) as cursor:
for data in cursor:
arr_groups.append(data)
return json.dumps(arr_groups)
@admin_app.route('/pastafari2/update_task/', methods=['POST'])
def pastafari2_update_task():
db=g.connection
ids=json.loads(request.form.get('ids', '[]'))
arr_ids=[]
error=0
txt_error=''
error_form={}
#print(ids)
for v in ids:
arr_ids.append(str(int(v)))
where_sql='WHERE id IN ('+",".join(arr_ids)+') order by hostname ASC'
#print(where_sql)
task=Task(db)
task_id=0
path_task='modules.pastafari2.tasks.system.ping'
data={}
server_host=''
user=config_task.remote_user
ssh_key_priv='./ssh/id_rsa'
if not task.run_task(server_host, path_task, 'Update server', 'update_server', 'Task for update servers', user=user, password='', where_sql_server=where_sql, ssh_key_priv=ssh_key_priv, url='', data=data, send_task=True):
error=1
error_form['#server_host_error']=I18n.lang('pastafari2', 'error_exec_task', 'Error: cannot execute the task')
task_id=task.task_id
return {'error': error, 'txt_error': txt_error, 'error_form': error_form, 'task_id': task_id}
return {}
@admin_app.route('/pastafari2/multiprogress/')
def pastafari2_multiprogress():
db=g.connection
task_id=request.args.get('task_id', '')
task=Task(db)
arr_task=task.select_a_row(task_id)
num_servers=task.set_conditions('WHERE parent_id=%s', [task_id]).select_count()
if arr_task:
return t.load_template('multiprogress.phtml', title=I18n.lang('pastafari2', 'task_progress', 'Task progress'), path_module='admin_app.pastafari2_dashboard', name_task=arr_task['name_task'], description_task=arr_task['description_task'], task_id=task_id, server=arr_task['server'], num_servers=num_servers)
else:
return ""
@admin_app.route('/pastafari2/get_servers_task/')
def pastafari2_get_servers_task():
db=g.connection
task_id=request.args.get('task_id', '')
task=Task(db)
arr_ids=task.set_conditions('WHERE parent_id=%s', [task_id]).select_to_array(['id', 'hostname', 'server'])
resp=make_response(json.dumps(arr_ids))
resp.headers['Content-Type']='application/json'
return resp
@admin_app.route('/pastafari2/get_multiprogress/')
def pastafari2_get_multiprogress():
s=session
db=g.connection
ids=request.args.get('ids', '[]')
final_ids=[str(i) for i in json.loads(ids)]
final_str=",".join(['%s']*len(final_ids))
#print(final_str)
#for i in final_ids:
task=Task(db)
logtask=LogTask(db)
arr_log=logtask.set_limit([20]).set_conditions('WHERE task_id IN ({})'.format(final_str), final_ids).select_to_array([], True)
resp=make_response(json.dumps(arr_log))
resp.headers['Content-Type']='application/json'
return resp

43
admin/groups.py Normal file
View file

@ -0,0 +1,43 @@
from settings import config
from flask import g, url_for, request, session, make_response
from paramecio2.libraries.generate_admin_class import GenerateAdminClass
from paramecio2.libraries.i18n import I18n
from paramecio2.modules.admin import admin_app, t as admin_t
from paramecio2.libraries.db.coreforms import SelectForm
from paramecio2.libraries.mtemplates import PTemplate, env_theme
from paramecio2.libraries import datetime
from paramecio2.libraries.urls import make_media_url
from paramecio2.libraries.db.webmodel import WebModel
from paramecio2.libraries.lists import AjaxList
from paramecio2.libraries.db.extraforms.fileform import FileForm
from paramecio2.libraries.formsutils import show_form
from modules.pastafari2.libraries.task import Task as SSHTask
from modules.pastafari2.libraries.configtask import config_task
from modules.pastafari2.models.tasks import Task, LogTask
from modules.pastafari2.models.pastafari2 import ServerGroup
@admin_app.route('/pastafari2/groups/', methods=['GET', 'POST'])
def pastafari2_groups():
t=admin_t
db=g.connection
groups=ServerGroup(db)
url=url_for('admin_app.pastafari2_groups')
admin=GenerateAdminClass(groups, url, t)
admin.list.raw_query=False
form_admin=admin.show()
if type(form_admin).__name__=='str':
return t.load_template('content.phtml', title=I18n.lang('admin', 'groups_edit', 'Groups edit'), contents=form_admin, path_module='admin_app.pastafari2_groups')
else:
return form_admin
return ""

0
app.py Normal file
View file

83
libraries/configtask.py Normal file
View file

@ -0,0 +1,83 @@
#!/usr/bin/env python3
import os
class ConfigTask:
def __init__(self):
#Local paths
# Scheme: code task: {description task, module task}
self.libraries={}
self.base_path=os.path.dirname(os.path.dirname(__file__))
self.tasks_path=['tasks', 'modules/pastafari2/tasks']
self.scripts_path=['scripts', 'modules/pastafari2/scripts']
self.logs_path='logs'
#Remote paths
self.remote_path='/home/spanel'
#Relative to remote_path
self.tmp_sftp_path='tmp'
self.remote_user='spanel'
self.remote_password=None
#Local home
self.home=''
#SSH configuration
self.user_key=''
self.public_key=''
self.private_key=''
self.password_key=None
self.port=22
self.deny_missing_host_key=True
#Internal tasks
self.num_of_forks=10
self.stop_if_error=False
self.num_errors=0
self.num_success=0
self.num_total=0
self.num_servers=0
self.file_resume=None
#Used if in next versions, pastafari try use others tasks servers.
self.server_task='http://127.0.0.1:1337'
self.url_host=''
self.url_monit=''
self.api_key=''
self.ssh_directory=os.path.expanduser('~')+'/.ssh'
# Class for global configuration
config_task=ConfigTask()

630
libraries/task.py Normal file
View file

@ -0,0 +1,630 @@
#!/usr/bin/env python3
import paramiko, json
import os, sys,traceback
from stat import S_ISDIR
from modules.pastafari2.models import tasks
#from modules.pastafari2.models.servers import ServerGroupTask
from modules.pastafari2.libraries.configtask import config_task
from paramecio2.libraries.i18n import I18n
from paramecio2.libraries.db.webmodel import WebModel
class Task:
#($server='', $ssh_user='root', $ssh_key_priv='./ssh/id_rsa', $ssh_key_password='', $ssh_path='leviathan', $mysql_conn=false)
def __init__(self, server, conn, remote_user='root', remote_password='', private_key='./ssh/id_rsa', password_key='', remote_path='leviathan', task_id=0, data={}):
self.config=config_task
self.server=server
self.name_task=''
self.codename_task=''
self.description_task=''
self.txt_error=''
self.os_server=''
self.files=[]
# Format first array element is command with the interpreter, the task is agnostic, the files in os directory. The commands are setted with 750 permission.
# First element is the file, next elements are the arguments
self.commands_to_execute=[];
#THe files to delete
self.delete_files=[];
self.delete_directories=[];
#The id of the task in db
self.id=task_id
self.user=''
self.password=''
self.connection=conn
self.logtask=tasks.LogTask(self.connection)
self.task=tasks.Task(self.connection)
self.taskdone=tasks.TaskDone(self.connection)
self.ssh=paramiko.SSHClient()
self.logtask.reset_require()
self.task.reset_require()
self.one_time=False
self.version='1.0'
self.simultaneous=False
self.error_post_task=''
self.data=data
self.remote_user=remote_user
self.remote_password=remote_password
self.private_key=private_key
self.password_key=password_key
self.remote_path=remote_path
"""
self.pre_task=None
self.error_task=None
self.post_task=None
"""
def prepare_connection(self):
#self.ssh.load_system_host_keys()
#Check if the unknown host keys are rejected or not
#if self.config.deny_missing_host_key == False:
#self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Check if in known_hosts
check_ssh_host= paramiko.hostkeys.HostKeys()
if not os.path.isfile(self.config.ssh_directory+'/known_hosts'):
f=open(self.config.ssh_directory+'/known_hosts', 'w')
f.write('')
f.close()
self.ssh.load_system_host_keys(self.config.ssh_directory+'/known_hosts')
check_ssh_host.load(self.config.ssh_directory+'/known_hosts')
host_key=self.ssh.get_host_keys()
add_host=False
rsa=None
if self.private_key!='':
rsa=paramiko.RSAKey.from_private_key_file(self.private_key, self.password_key)
if check_ssh_host.lookup(self.server)==None:
# Be tolerant for the first connect with hostkey policy
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
add_host=True
try:
self.ssh.connect(self.server, port=self.config.port, username=self.remote_user, password=self.remote_password, pkey=rsa, key_filename=None, timeout=None, allow_agent=True, look_for_keys=True, compress=False, sock=None, gss_auth=False, gss_kex=False, gss_deleg_creds=True, gss_host=None, banner_timeout=None)
if add_host:
host_key.save(self.config.ssh_directory+'/known_hosts')
except paramiko.SSHException as e:
self.txt_error="Error: cannot connect to the server SSHException\n"+str(e)
return False
except paramiko.AuthenticationException as e:
self.txt_error="Error: cannot connect to the server AuthenticationException \n"+str(e)
return False
except paramiko.BadHostKeyException as e:
self.txt_error="Error: cannot connect to the server BadHostKeyException\n"+str(e)
return False
except OSError as e:
self.txt_error="Error: cannot connect to the server OsError \n"+str(e)
return False
except:
self.txt_error="Error: cannot connect to the server Generic\n"+traceback.format_exc()
return False
#finally:
# self.ssh.close()
return True
def upload_files(self):
try:
sftp=self.ssh.open_sftp()
except:
self.txt_error='Sorry, error connecting to sftp: '+traceback.format_exc()
return False
c=len(self.files)
if c>0:
percent=100/c
progress=0
for f in self.files:
source_file=f[0]
source_file=source_file.replace('${os_server}', self.os_server)
permissions=f[1]
#dest_file=self.remote_path+'/'+source_file
dest_file=source_file
try:
if not os.path.isfile(source_file):
self.txt_error="Sorry, you don't have source file to upload "+source_file
return False
dir_file=os.path.dirname(dest_file)
parts_dir_file=dir_file.split('/')
# Create remote directory
try:
f_stat=sftp.stat(dir_file)
except IOError:
try:
final_path=''
for d in parts_dir_file:
final_path+=d+'/'
#print(self.remote_path+'/'+final_path)
try:
f_stat=sftp.stat(final_path)
except IOError:
sftp.mkdir(final_path)
except:
self.txt_error='Sorry, error creating the directories for the files: '+traceback.format_exc()
return False
# Upload file
try:
sftp.put(source_file, dest_file, callback=None, confirm=True)
sftp.chmod(dest_file, permissions)
progress+=percent
self.logtask.insert({'task_id': self.id, 'progress': progress, 'message': I18n.lang('pastafari', 'uploading_files', 'Uploading file: ')+source_file, 'error': 0, 'server': self.server})
except:
self.txt_error='Sorry, cannot upload file '+source_file+': '+traceback.format_exc()
return False
# Create directory recursively if not exists
except:
self.txt_error='Error: '+traceback.format_exc()
return False
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': I18n.lang('pastafari', 'upload_successful', 'Files uploaded successfully...'), 'error': 0, 'server': self.server})
return True
def delete_files_and_dirs(self):
sftp=self.ssh.open_sftp()
c=len(self.delete_files)
if c>0:
percent=100/c
progress=0
for filepath in self.delete_files:
filepath=filepath.replace('${os_server}', self.os_server)
try:
#print(self.remote_path+'/'+filepath)
sftp.remove(filepath)
progress+=percent
self.logtask.insert({'task_id': self.id, 'progress': progress, 'message': I18n.lang('pastafari', 'cleaning_files', 'Cleaning file: ')+filepath, 'error': 0, 'server': self.server})
except IOError:
self.txt_error="Sorry, cannot remove file "+filepath+" from server."
return False
c=len(self.delete_directories)
if c>0:
percent=100/c
progress=0
for path in self.delete_directories:
try:
path=path.replace('${os_server}', self.os_server)
self.delete_dir(path, sftp)
progress+=percent
self.logtask.insert({'task_id': self.id, 'progress': progress, 'message': I18n.lang('pastafari', 'cleaning_directories', 'Cleaning directory: ')+path, 'error': 0, 'server': self.server})
except IOError:
self.txt_error+="Sorry, cannot remove directory "+path+" from server."
return False
return True
def isdir(self, path, sftp):
try:
return S_ISDIR(sftp.stat(path).st_mode)
except IOError:
return False
def delete_dir(self, path, sftp):
#path=self.config.remote_path+'/'+path
if path != "/":
files = sftp.listdir(path)
for f in files:
filepath = os.path.join(path, f)
try:
if self.isdir(filepath, sftp):
self.delete_dir(filepath, sftp)
else:
sftp.remove(filepath)
except IOError:
self.txt_error="Sorry, cannot remove "+filepath+" from server."
return False
sftp.rmdir(path)
return True
def exec(self):
# Get task
#self.id=task_id
self.task.reset_require()
self.task.valid_fields=['name_task', 'description_task', 'error', 'status', 'server']
self.logtask.valid_fields=self.logtask.fields.keys()
if self.id==0:
# Insert the task
self.task.reset_require()
self.task.insert({'name_task': self.name_task, 'description_task': self.description_task, 'server': self.server})
self.id=self.task.insert_id()
if not self.prepare_connection():
#self.task.conditions=['WHERE id=%s', [self.id]]
#self.task.update({'error': 1, 'status': 1})
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': self.txt_error, 'error': 1, 'status': 1, 'server': self.server})
self.make_error_task()
return False
# Pre task
if hasattr(self, 'pre_task'):
self.logtask.insert({'task_id': self.id, 'progress': 0, 'message': I18n.lang('pastafari', 'pre_tasks', 'Begin pre tasks execution...'), 'error': 0, 'status': 0, 'server': self.server})
if self.pre_task():
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': I18n.lang('pastafari', 'pre_tasks_executed', 'Pre tasks executed successfully...'), 'error': 0, 'status': 0, 'server': self.server})
else:
#self.logtask.set_conditions('where id=%s', [last_log_id])
self.logtask.insert({'progress': 100, 'error': 1, 'message': "Error executing pre task "+self.txt_error, 'status': 1, 'server': self.server, 'task_id': self.id})
self.make_error_task()
return False
#Check if script was executed
if self.codename_task!='':
if self.one_time==True:
with self.ssh.open_sftp() as sftp:
try:
with sftp.file(self.remote_path+'/tasks/'+self.codename_task) as f:
version=f.read()
version=version.decode('utf-8').strip()
if version==self.version:
#self.task.conditions=['WHERE id=%s', [self.id]]
#self.task.update({'error': 0, 'status': 1})
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': 'This script was executed correctly in this server', 'error': 0, 'status': 1, 'server': self.server})
return True
except IOError:
# It was not executed
pass
if not self.upload_files():
#self.task.conditions=['WHERE id=%s', [self.id]]
#self.task.update({'error': 1, 'status': 1})
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': self.txt_error, 'error': 1, 'status': 1, 'server': self.server})
self.make_error_task()
return False
self.logtask.insert({'task_id': self.id, 'progress': 0, 'message': 'Executing commands...', 'error': 0, 'status': 0, 'server': self.server})
# Execute commands
json_code=[]
for c in self.commands_to_execute:
try:
command=c[0]
command=command.replace('${os_server}', self.os_server)
arguments=c[1]
sudo_str=''
if len(c)==3:
sudo_str='sudo '
#, get_pty=True
stdin, stdout, stderr = self.ssh.exec_command(sudo_str+command+' '+arguments)
for line in stdout:
if line==None:
line="[]"
line=line.strip()
try:
json_code=json.loads(line)
if not 'progress' in json_code or not 'message' in json_code or not 'error' in json_code:
#self.task.conditions=['WHERE id=%s', [self.id]]
#self.task.update({'error': 1, 'status': 1})
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': 'Malformed json code: '+str(line), 'error': 1, 'status': 1, 'server': self.server})
self.make_error_task()
return False
else:
json_code['task_id']=self.id
json_code['server']=self.server
self.logtask.insert(json_code)
if json_code['error']==1:
self.make_error_task()
return False
except:
#self.task.conditions=['WHERE id=%s', [self.id]]
#self.task.update({'error': 0, 'status':0})
self.logtask.insert({'task_id': self.id, 'progress': 0, 'no_progress': 1, 'message': str(line), 'error': 0, 'status': 0, 'server': self.server})
#return False
last_log_id=self.logtask.insert_id()
if stdout.channel.recv_exit_status()>0:
#line=stdout.readlines()
#logging.warning(action.codename+" WARNING: "+line)
final_text='Error executing the command: %s' % command
#self.task.conditions=['WHERE id=%s', [self.id]]
#self.task.update({'error': 1, 'status': 1})
for line in stdout:
final_text+=' '+line
for line in stderr:
final_text+=' '+line
self.logtask.set_conditions('where id=%s', [last_log_id])
self.logtask.update({'progress': 100, 'error': 1, 'message': final_text, 'status': 1, 'server': self.server})
self.make_error_task()
return False
except:
#self.task.conditions=['WHERE id=%s', [self.id]]
#self.task.update({'error': 1, 'status': 1})
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': traceback.format_exc(), 'error': 1, 'status': 1, 'server': self.server})
self.make_error_task()
return False
# Clean files
if not self.delete_files_and_dirs():
#self.task.conditions=['WHERE id=%s', [self.id]]
#self.task.update({'error': 1, 'status': 1})
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': self.txt_error, 'error': 1, 'status': 1, 'server': self.server})
self.make_error_task()
return False
#Upload files
#self.ssh.close()
# FInish task
#Put this version how executed
if self.codename_task!='':
if self.one_time==True:
with self.ssh.open_sftp() as sftp:
try:
path_check=self.remote_path+'/tasks/'
f_stat=sftp.stat(path_check)
except IOError:
sftp.mkdir(path_check)
with sftp.file(path_check+self.codename_task, 'w') as f:
f.write(self.version)
if hasattr(self, 'post_task'):
self.logtask.insert({'task_id': self.id, 'progress': 0, 'message': I18n.lang('pastafari', 'post_tasks', 'Post tasks executing...'), 'error': 0, 'status': 0, 'server': self.server})
if self.post_task():
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': I18n.lang('pastafari', 'post_tasks_executed', 'Post tasks executed successfully...'), 'error': 0, 'status': 0, 'server': self.server})
else:
#self.logtask.set_conditions('where id=%s', [last_log_id])
#self.logtask.update({'progress': 100, 'error': 1, 'message': "Error executing post task", 'status': 1, 'server': self.server})
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': I18n.lang('pastafari', 'error_post_tasks_executed', 'Error executing post task -> '+self.error_post_task), 'error': 1, 'status': 1, 'server': self.server})
self.make_error_task()
return False
if 'progress' in json_code:
#if json_code['progress']!=100:
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': I18n.lang('pastafari', 'finished_successfully', 'All tasks done successfully...'), 'error': 0, 'status': 1, 'server': self.server})
else:
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': I18n.lang('pastafari', 'finished_successfully', 'All tasks done successfully...'), 'error': 0, 'status': 1, 'server': self.server})
# Add
self.taskdone.create_forms()
self.taskdone.insert({'name_task': self.codename_task, 'ip': self.server})
#self.task.conditions=['WHERE id=%s', [self.id]]
#self.task.update({'error': 0, 'status': 1})
#connection.close()
return True
def make_error_task(self):
if hasattr(self, 'error_task'):
self.logtask.insert({'task_id': self.id, 'progress': 0, 'message': I18n.lang('pastafari', 'error_tasks', 'Error tasks executing...'), 'error': 0, 'status': 0, 'server': self.server})
if self.error_task():
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': I18n.lang('pastafari', 'error_tasks_executed', 'Sorry, you have an error, please, review the log...'), 'error': 1, 'status': 1, 'server': self.server})
else:
self.logtask.insert({'task_id': self.id, 'progress': 100, 'message': I18n.lang('pastafari', 'error_tasks_executed', 'Error Post task cannot be executed...'), 'error': 1, 'status': 1, 'server': self.server})
return False
def __del__(self):
#self.connection.close()
if self.ssh!=None:
self.ssh.close()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, tb):
if exc_type is not None:
traceback.print_exception(exc_type, exc_value, tb)
return True

7
media/css/jquery-ui.min.css vendored Normal file

File diff suppressed because one or more lines are too long

5
media/css/jquery-ui.theme.min.css vendored Normal file

File diff suppressed because one or more lines are too long

6
media/js/jquery-ui.min.js vendored Normal file

File diff suppressed because one or more lines are too long

31
models/pastafari2.py Normal file
View file

@ -0,0 +1,31 @@
from paramecio2.libraries.db.webmodel import WebModel
from paramecio2.libraries.db import corefields
from paramecio2.libraries.db.extrafields.dictfield import DictField
from paramecio2.libraries.db.extrafields.datefield import DateField
from paramecio2.libraries.db.extrafields.datetimefield import DateTimeField
from paramecio2.libraries.db.extrafields.ipfield import IpField
from paramecio2.libraries.db.extrafields.urlfield import UrlField
from paramecio2.libraries.db.extrafields.urlfield import DomainField
from paramecio2.libraries.db.extrafields.dictfield import DictField
from paramecio2.libraries.db.extrafields.jsonfield import JsonValueField
from paramecio2.libraries.db.extrafields.parentfield import ParentField
from paramecio2.libraries.urls import make_media_url
from paramecio2.libraries import datetime
from paramecio2.modules.admin.models.admin import UserAdmin
from modules.monit.models.monit import Server
class ServerGroup(WebModel):
def __init__(self, connection):
super().__init__(connection)
self.register(corefields.CharField('group'), True)
self.register(corefields.CharField('code_group'), True)
class ServerDbTask(Server):
def __init__(self, connection=None):
super().__init__(connection)
self.register(corefields.ForeignKeyField('group_id', ServerGroup(connection), 11, False, 'id', 'group', select_fields=[]))

306
models/tasks.py Normal file
View file

@ -0,0 +1,306 @@
from paramecio2.libraries.db.webmodel import WebModel
from paramecio2.libraries.db import corefields
from paramecio2.libraries.db.extrafields.ipfield import IpField
from paramecio2.libraries.db.extrafields.arrayfield import ArrayField
from paramecio2.libraries.db.extrafields.parentfield import ParentField
from paramecio2.libraries.db.extrafields.datefield import DateField
from paramecio2.libraries.db.extrafields.dictfield import DictField
from paramecio2.libraries.i18n import I18n
import urllib3
try:
import ujson as json
except:
import json
from redis import Redis
from rq import Queue
import importlib
import traceback
from modules.monit.models.monit import LonelyIpField
class Task(WebModel):
def __init__(self, connection):
super().__init__(connection)
self.register(corefields.CharField('name_task'), True)
self.register(corefields.CharField('description_task'), True)
self.register(corefields.CharField('codename_task'), True)
self.register(corefields.CharField('path'))
self.register(IpField('server'))
self.register(corefields.CharField('hostname'))
self.register(corefields.CharField('where_sql_server'), 2000)
self.register(corefields.CharField('user'))
self.register(corefields.CharField('password'), 2000)
self.register(corefields.CharField('user_path'))
self.register(corefields.CharField('os_codename'))
self.register(corefields.CharField('url_return'))
self.register(corefields.CharField('ssh_user'))
self.register(corefields.CharField('ssh_key_pub'))
self.register(corefields.CharField('ssh_key_priv'))
self.register(corefields.CharField('ssh_key_password'))
self.register(DictField('data', corefields.CharField('')))
self.register(corefields.IntegerField('num_servers'))
self.register(corefields.BooleanField('is_parent'))
self.register(ParentField('parent_id', size=11, required=False, field_name='name_task'))
self.fields['where_sql_server'].escape=True
self.txt_error=''
def run_task(self, server, path, name_task, codename_task, description_task, data={}, user='', password='', where_sql_server='', url='', ssh_key_priv='', ssh_key_password='', send_task=True):
logtask=LogTask(self.connection)
#servers=Server(self.connection)
self.safe_query()
logtask.safe_query()
parent_id=None
yes_parent=False
"""
if type(server).__name__=='list':
server_list=server
server=None
yes_parent=True
"""
if self.insert({'name_task': name_task,'description_task': description_task, 'url_return': url, 'server': server, 'where_sql_server': where_sql_server, 'data': data , 'user': user, 'password': password, 'path': path, 'where_sql_server' : where_sql_server, 'ssh_key_priv': ssh_key_priv, 'ssh_key_password': ssh_key_password}):
task_id=self.insert_id()
parent_id=task_id
self.task_id=task_id
arr_ids=[]
if where_sql_server!='':
yes_parent=True
"""
if yes_parent:
for server in server_list:
self.insert({'name_task': name_task,'description_task': description_task, 'url_return': url, 'server': server, 'where_sql_server': '', 'data': data , 'user': user, 'password': password, 'path': path, 'where_sql_server' : where_sql_server, 'ssh_key_priv': ssh_key_priv, 'ssh_key_password': ssh_key_password, 'parent_id': parent_id})
arr_ids.append(self.insert_id())
"""
if send_task:
"""
http = urllib3.PoolManager()
try:
r = http.request('GET', 'http://127.0.0.1:1337', fields={'task_id': task_id, 'api_key': api_key})
if r.status!=200:
self.error=True
self.txt_error="Cannot access to task server: Error "+str(r.status)
return False
else:
resp=json.loads(r.data.decode('utf-8'))
if resp['error']:
self.error=True
self.txt_error=resp['message']
logtask.insert(resp)
return False
except urllib3.exceptions.MaxRetryError:
self.txt_error='Cannot connect to the task server, check if is up'
return False
"""
return self.send_task(task_id, yes_parent, where_sql_server)
"""
q = Queue(connection=Redis(host=redis_host, port=redis_port, password=redis_password))
try:
if where_sql_server=='':
result = q.enqueue('modules.pastafari.servers.server_rq.send_pastafari_task', task_id, server, job_timeout=rq_timeout)
else:
for arr_server in servers.set_conditions(where_sql_server, []).select_to_array(['ip']):
result=q.enqueue('modules.pastafari.servers.server_rq.send_pastafari_task', task_id, arr_server['ip'], job_timeout=rq_timeout)
except:
self.error=True
self.txt_error=traceback.format_exc()
return False
"""
return True
else:
self.error=True
self.txt_error="Cannot insert the task"
return False
def send_task(self, task_id, yes_parent=False, where_sql_server=''):
"""
http = urllib3.PoolManager()
try:
r = http.request('GET', 'http://127.0.0.1:1337', fields={'task_id': task_id, 'api_key': api_key})
if r.status!=200:
self.error=True
self.txt_error="Cannot access to task server: Error "+str(r.status)
return False
else:
resp=json.loads(r.data.decode('utf-8'))
if resp['error']:
self.error=True
self.txt_error=resp['message']
logtask.insert(resp)
return False
except urllib3.exceptions.MaxRetryError:
self.error=True
self.txt_error='Cannot connect to the task server, check if is up'
return False
"""
q = Queue(connection=Redis())
if yes_parent:
arr_task=self.select_a_row(task_id)
#If where sql, send multiple tasks.
sql_insert_values=[]
sql_insert='insert into task (`name_task`, `description_task`, `url_return`, `server`, `hostname`, `data`, `user`, `password`, `path`, `ssh_key_priv`, `ssh_key_password`, `parent_id`) VALUES '
with self.query('select id, hostname from serverdbtask '+where_sql_server) as cursor:
for row in cursor:
arr_task['server']=row['hostname']
sql_insert_values.append("('"+arr_task['name_task']+"', '"+arr_task['description_task']+"', '"+arr_task['url_return']+"', '"+arr_task['server']+"', '"+arr_task['server']+"', '"+arr_task['data']+"', '"+arr_task['user']+"', '"+arr_task['password']+"', '"+arr_task['path']+"', '"+arr_task['ssh_key_priv']+"', '"+arr_task['ssh_key_password']+"', '"+str(task_id)+"')")
#self.insert({'name_task': name_task,'description_task': description_task, 'url_return': url, 'server': server, 'where_sql_server': where_sql_server, 'data': data , 'user': user, 'password': password, 'path': path, 'where_sql_server' : where_sql_server, 'ssh_key_priv': ssh_key_priv, 'ssh_key_password': ssh_key_password})
pass
final_sql=sql_insert+", ".join(sql_insert_values)
self.query(final_sql)
with self.query('select id from task WHERE parent_id=%s', [task_id]) as cursor:
for row in cursor:
#print(row)
result = q.enqueue(task, row['id'], job_timeout=3600)
else:
#Enqueue task function.
result = q.enqueue(task, task_id, job_timeout=3600)
return True
# Function used in rq worker for exec the ssh task.
def task(task_id):
conn=WebModel.connection()
task=Task(conn)
logtask=LogTask(conn)
logtask.safe_query()
arr_task=task.select_a_row(task_id)
if not arr_task:
self.logtask.insert({'task_id': task_id, 'progress': 100, 'message': I18n.lang('pastafari', 'error_task_not_exists', 'Error: task not exists'), 'status': 1, 'error': 1, 'server': ''})
conn.close()
return False
server=arr_task['server']
try:
ssh_task=importlib.import_module(arr_task['path'])
"""
| name_task | varchar(255) | NO | | | |
| description_task | varchar(255) | NO | | | |
| codename_task | varchar(255) | NO | | | |
| path | varchar(255) | NO | | | |
| server | varchar(255) | NO | | | |
| hostname | varchar(255) | NO | | | |
| where_sql_server | varchar(255) | NO | | | |
| user | varchar(255) | NO | | | |
| password | varchar(255) | NO | | | |
| user_path | varchar(255) | NO | | | |
| os_codename | varchar(255) | NO | | | |
| url_return | varchar(255) | NO | | | |
| data | text | NO | | NULL | |
| ssh_key_pub | varchar(255) | NO | | | |
| ssh_key_priv | varchar(255) | NO | | | |
| ssh_user | varchar(255) | NO | | | |
| num_servers | int(11) | NO | | 0 | |
+------------------+--------------+------+-----+---------+----------------+
"""
remote_user=arr_task['user']
remote_password=arr_task['password']
private_key=arr_task['ssh_key_priv']
password_key=arr_task.get('ssh_key_password', '')
final_task=ssh_task.ServerTask(server, conn, remote_user=remote_user, remote_password=remote_password, private_key=private_key, password_key=password_key, remote_path='pastafari2', task_id=task_id, data=json.loads(arr_task['data']))
final_task.exec()
except:
if conn==None:
conn=WebModel.connection()
logtask.sqlclass=conn
logtask.insert({'task_id': task_id, 'progress': 100, 'message': I18n.lang('pastafari', 'error_in_task', 'Error: error in task ')+traceback.format_exc(), 'error': 1, 'status': 1, 'server': server})
conn.close()
return False
conn.close()
return True
class LogTask(WebModel):
def __init__(self, connection):
super().__init__(connection)
self.register(DateField('path'))
self.register(corefields.ForeignKeyField('task_id', Task(connection), size=11, required=False, identifier_field='id', named_field="name_task"))
self.register(IpField('server'))
self.register(corefields.DoubleField('progress'))
self.register(corefields.BooleanField('no_progress'))
self.register(corefields.TextField('message'))
self.register(corefields.BooleanField('error'))
self.register(corefields.BooleanField('status'))
self.register(ArrayField('data', corefields.CharField('data')))
self.register(corefields.BooleanField('code_error'))
# For grouping
class TaskDone(WebModel):
def __init__(self, connection):
super().__init__(connection)
self.register(corefields.CharField('name_task'), True)
self.register(LonelyIpField('ip'), True)

10
scripts/system/alive.sh Normal file
View file

@ -0,0 +1,10 @@
#!/bin/bash
echo '{"progress": 0, "message": "This server is up!!!", "error":0, "code_error": 0, "sucks": 1}'
sleep 1
echo '{"progress": 100, "message": "Finishing scripts without errors", "error":0, "code_error": 0, "sucks": 1}'
exit 0

View file

@ -0,0 +1,29 @@
#!/bin/sh
echo "Installing git"
echo '{"error": 0, "status": 0, "progress": 0, "no_progress":0, "message": "Installing git..."}'
sleep 1
sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y git
if [ $? -eq 0 ]; then
sleep 1
#echo "Installed git sucessfully if not error..."
echo '{"error": 0, "status": 0, "progress": 100, "no_progress":0, "message": "Installed git sucessfully..."}'
sleep 1
else
echo "Sorry, cannot update the server..."
exit;
fi

View file

@ -0,0 +1,19 @@
#!/bin/sh
# Install pip
sleep 1
echo '{"error": 0, "status": 0, "progress": 100, "no_progress":0, "message": "Installing python3-psutil..."}'
sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y python3-pip
#sudo pip3 install psutil
sudo apt-get install -y python3-psutil
#echo "Installed python3-psutil sucessfully if not error..."
sleep 1
echo '{"error": 0, "status": 0, "progress": 100, "no_progress":0, "message": "Installed python3-psutil sucessfully..."}'

View file

@ -0,0 +1,27 @@
#!/bin/sh
sleep 1
echo '{"error": 0, "status": 0, "progress": 0, "no_progress":0, "message": "Installing Python..."}'
sleep 1
sudo apt-get -y install python3 python3-pip
if [ $? -eq 0 ]; then
#echo "Installed python3 sucessfully if not error..."
echo '{"error": 0, "status": 0, "progress": 100, "no_progress":0, "message": "Installed python sucessfully..."}'
sleep 1
else
echo "Sorry, cannot install python..."
exit 1;
fi
sleep 1

View file

@ -0,0 +1,192 @@
#!/usr/bin/python3 -u
# A script for install pzoo user
import subprocess
import argparse
import re
import os
import shutil
import pwd
from subprocess import call
from pathlib import Path
from time import sleep
parser = argparse.ArgumentParser(description='A script for install leviathan user')
#parser.add_argument('--url', help='The url where notify updates', required=True)
parser.add_argument('--url_stats', help='The url where pastafaristats notify the stats', required=True)
parser.add_argument('--user', help='The user for pastafari', required=True)
parser.add_argument('--pub_key', help='The pub key used in pastafari user', required=True)
parser.add_argument('--group', help='Server group', required=False)
args = parser.parse_args()
#url=args.url
check_url = re.compile(
r'^(?:http|ftp)s?://' # http:// or https://
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' #domain...
r'localhost|' #localhost...
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
r'(?::\d+)?' # optional port
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
print('{"error": 0, "status": 0, "progress": 0, "no_progress":0, "message": "Installing tools for monitoring the server..."}')
#check_url.match(args.url) and
if check_url.match(args.url_stats):
try:
u=pwd.getpwnam(args.user)
if call("sudo userdel -r %s" % args.user, shell=True) > 0:
print('Error, user with same username exists and cannot delete of the server')
exit(1)
else:
print('Cleaning user with the same name')
except:
pass
# Create users
if call("sudo useradd -m -s /bin/bash %s" % args.user, shell=True) > 0:
# Delete user with this name, you should not install it in a old server.
if call("sudo userdel -r %s" % args.user, shell=True) > 0:
print('Error, remove the old user')
exit(1)
else:
if call("sudo useradd -m -s /bin/sh %s" % args.user, shell=True) > 0:
print('Error, cannot add a new user')
exit(1)
else:
print('Added user')
if call("sudo mkdir -p /home/"+args.user+"/.ssh && sudo chown "+args.user+":"+args.user+" /home/"+args.user+"/.ssh && sudo chmod 700 /home/"+args.user+"/.ssh", shell=True) > 0:
print('Error, cannot add ssh directory')
exit(1)
else:
print('Added ssh directory')
if call("sudo cp "+args.pub_key+" /home/"+args.user+"/.ssh/authorized_keys && sudo chown "+args.user+":"+args.user+" /home/"+args.user+"/.ssh/authorized_keys && sudo chmod 600 /home/"+args.user+"/.ssh/authorized_keys", shell=True) > 0:
print('Error, cannot pub key to user')
exit(1)
else:
print('Added pub key to user')
# Edit sudo file
with open('modules/pastafari2/scripts/system/sudoers.d/spanel') as f:
sudoers=f.read()
with open('/etc/sudoers.d/spanel', 'w') as f:
sudoers=sudoers.replace("spanel", args.user)
f.write(sudoers)
# Installing composer things for php alerts...
#mkdir $HOME/pzoo/scripts
#chown $USER:$USER $HOME/pzoo/scripts
#su - $USER -s /bin/bash -c "composer --working-dir=$HOME/scripts require guzzlehttp/guzzle:~6.0"
#pt=Path('/home/'+args.user+'/pzoo/tasks')
#pt.mkdir(mode=0o755, parents=True, exist_ok=True)
# Create scripts pzoo
"""
ps=Path('/home/'+args.user+'/pzoo/scripts')
ps.mkdir(mode=0o755, parents=True, exist_ok=True)
shutil.chown('/home/'+args.user+'/pzoo', args.user, args.user)
shutil.chown('/home/'+args.user+'/pzoo/scripts', args.user, args.user)
if call("su - "+args.user+" -s /bin/bash -c \"composer --working-dir=/home/"+args.user+"/pzoo/scripts require guzzlehttp/guzzle:~6.0\"", shell=True)>0:
print('Error, cannot install scripts for use in check scripts')
exit(1)
else:
print('Composer dependencies for check scripts added successfully')
# Edit get_updates.py
with open('scripts/system/get_updates.py') as f:
get_updates=f.read()
with open('/etc/cron.daily/get_updates.py', 'w') as f:
url_updates=args.url.replace('/getinfo/', '/getupdates/')
get_updates=get_updates.replace("http://url/to/server/token/ip", url_updates)
f.write(get_updates)
os.chmod('/etc/cron.daily/get_updates.py', 0o700)
"""
if call("sudo pip3 install --upgrade git+https://bitbucket.org/paramecio/pastafaristats", shell=True)>0:
print('Error, cannot install pastafari stats')
exit(1)
else:
print('Added pastafari stats')
# Add configuration to pastafari stats
if not os.path.isdir('/etc/pastafari'):
# Create pastafari dir
p=Path('/etc/pastafari')
p.mkdir(mode=0o755, parents=False, exist_ok=True)
with open('/etc/pastafari/stats.cfg', 'w') as f:
f.write("[DEFAULT]\n\nurl_server="+args.url_stats+"\ngroup="+args.group)
with open('/etc/systemd/system/pastafaristats.service', 'w') as f:
systemd_unit="""
# Save it in /etc/systemd/system/pastafaristats.service
[Unit]
Description=Pastafari Stats
After=syslog.target
After=network.target
[Service]
Type=simple
User=pzoo
Group=pzoo
ExecStart=pastafaristats
Restart=always
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
"""
systemd_unit=systemd_unit.replace('pzoo', args.user)
f.write(systemd_unit)
if call("sudo systemctl enable pastafaristats.service && sudo systemctl start pastafaristats.service", shell=True)>0:
print('Error, cannot start pastafari stats')
exit(1)
else:
print('Pastafari stats ready')
print('{"error": 0, "status": 0, "progress": 100, "no_progress":0, "message": "Tools installed..."}')
sleep(1)
else:
print('Error installing the module, not valid url')
exit(1)

View file

@ -0,0 +1 @@
spanel ALL=(ALL) NOPASSWD: ALL

10
settings/config_admin.py Normal file
View file

@ -0,0 +1,10 @@
from paramecio2.libraries.config_admin import config_admin
from paramecio2.libraries.i18n import I18n
#modules_admin=[[I18n.lang('admin', 'users_admin', 'User\'s Admin'), 'paramecio.modules.admin.admin.ausers', 'ausers']]
config_admin.append([I18n.lang('pastafari2', 'pastafari_admin', 'Pastafari admin')])
config_admin.append([I18n.lang('pastafari2', 'settings', 'Settings'), 'modules.pastafari2.admin.dashboard', 'admin_app.pastafari2_settings', 'fa-code'])
config_admin.append([I18n.lang('pastafari2', 'servers', 'Servers'), 'modules.pastafari2.admin.dashboard', 'admin_app.pastafari2_dashboard', 'fa-linux'])
config_admin.append([I18n.lang('pastafari2', 'groups', 'Groups'), 'modules.pastafari2.admin.groups', 'admin_app.pastafari2_groups', 'fa-object-group'])

14
tasks/system/ping.py Normal file
View file

@ -0,0 +1,14 @@
from modules.pastafari2.libraries.task import Task
from modules.pastafari2.models.pastafari2 import ServerDbTask
class ServerTask(Task):
def __init__(self, server, conn, remote_user='root', remote_password='', private_key='./ssh/id_rsa', password_key='', remote_path='leviathan', task_id=0, data={}):
super().__init__(server, conn, remote_user, remote_password, private_key, password_key, remote_path, task_id, data)
self.files=[['modules/pastafari2/scripts/system/alive.sh', 0o755]]
self.commands_to_execute=[]
self.commands_to_execute.append(['modules/pastafari2/scripts/system/alive.sh', ''])

38
tasks/system/task.py Normal file
View file

@ -0,0 +1,38 @@
from modules.pastafari2.libraries.task import Task
from modules.pastafari2.models.pastafari2 import ServerDbTask
class ServerTask(Task):
def __init__(self, server, conn, remote_user='root', remote_password='', private_key='./ssh/id_rsa', password_key='', remote_path='leviathan', task_id=0, data={}):
super().__init__(server, conn, remote_user, remote_password, private_key, password_key, remote_path, task_id, data)
#self.files=[['modules/pastafari2/scripts/system/alive.sh', 0o755]]
self.files=[['modules/pastafari2/scripts/system/install_pzoo_stats.py', 0o755]]
self.files.append(['modules/pastafari2/scripts/system/install_python.sh', 0o755])
self.files.append(['modules/pastafari2/scripts/system/install_psutil.sh', 0o755])
self.files.append(['modules/pastafari2/scripts/system/install_git.sh', 0o755])
self.files.append(['modules/pastafari2/scripts/system/sudoers.d/spanel', 0o640])
self.files.append([self.data['pub_key'], 0o600])
self.commands_to_execute=[]
#self.commands_to_execute.append(['modules/pastafari2/scripts/system/alive.sh', ''])
self.commands_to_execute.append(['modules/pastafari2/scripts/system/install_git.sh', ''])
self.commands_to_execute.append(['modules/pastafari2/scripts/system/install_python.sh', ''])
self.commands_to_execute.append(['modules/pastafari2/scripts/system/install_psutil.sh', ''])
self.commands_to_execute.append(['modules/pastafari2/scripts/system/install_pzoo_stats.py', '--user='+self.data['ssh_user']+' --pub_key='+self.data['pub_key']+' --url_stats='+self.data['url_stats']+' --group='+self.data['group_name']])
def post_task(self):
server=ServerDbTask(self.connection)
server.safe_query()
#'subdomain_id': self.data['subdomain_id']
server.insert({'hostname': self.data['hostname'], 'ip': self.data['ip'], 'group_id': self.data['group_id']})
return True

View file

@ -0,0 +1,42 @@
<%inherit file="dashboard.phtml"/>
<%block name="content">
<div id="principal_container">
<p><a href="${url_for('.pastafari2_dashboard')}">Servers</a> &gt;&gt; ${lang('pastafari2', 'add_server', 'Add server')}</p>
<h2>${lang('pastafari2', 'add_server', 'Add server')}</h2>
<div class="form">
<form method="post" name="add_server" id="add_server_form">
<p>Please fill the form for add the new server to the system.</p>
<p><label>${lang('pastafari2', 'server_host', 'Server host')}* <span class="pastafari2_error error" id="server_host_error"></span></label> <input type="text" name="server_host" value=""></p>
<p><label>${lang('pastafari2', 'server_group', 'Server group')} <span class="pastafari2_error error" id="group_id_error"></span></label> ${group_form.form()|n}</p>
<p><label>${lang('pastafari2', 'server_username', 'Server username')} <span class="pastafari2_error error" id="server_username_error"></span></label> <input type="text" name="server_username" value=""></p>
<p><label>${lang('pastafari2', 'server_password', 'Server password.')} <span class="pastafari2_error error" id="server_password_error"></span></label> <input type="password" name="server_password" value=""></p>
<p><label>${lang('pastafari2', 'repeat_server_password', 'Repeat server password')} <span class="pastafari2_error error" id="repeat_server_password_error"></span></label> <input type="password" name="repeat_server_password" value=""></p>
<p><input type="submit" value="${lang('pastafari2', 'send', 'Send')}"/></p>
</form>
</div>
<p><a href="${url_for('.pastafari2_dashboard')}">Servers</a> &gt;&gt; ${lang('pastafari2', 'add_server', 'Add server')}</p>
<script type="text/javascript" src="${make_media_url('js/jsutils/posting2.js', 'monit')}"></script>
<script>
var options={url: "${url_for('.pastafari2_add_server_task')}", loading: '#layer_loading', success: function (data) {
task_id=data.task_id;
if(task_id>0) {
location.href="${url_for('.pastafari2_progress')}?task_id="+task_id;
}
}, error_data: function (data) {
console.log(JSON.stringify(data));
}
};
jQuery('#add_server_form').sendPost(options);
</script>
</div>
</%block>

View file

@ -0,0 +1,135 @@
<%inherit file="dashboard.phtml"/>
<%block name="content">
<div id="principal_container">
<p><a href="${url_for('.pastafari2_add_server')}">${lang('pastafari2', 'add_server', 'Add server')}</a>
<p>${lang('monit', 'choose_group', 'Choose group')}:
<select name="group_id" id="group_id">
</select>
</p>
<input type="button" name="select_all" class="select_all" value="${lang('pastafari2', 'select_all_servers', 'Select all servers')}" />
<input type="button" name="deselect_all" class="deselect_all" value="${lang('pastafari2', 'deselect_all_servers', 'Deselect all servers')}" />
<input type="button" name="update_selected_servers" class="update_selected_servers button_blue" value="${lang('pastafari2', 'update_selected_servers', 'Update selected servers')}" />
<div id="table_servers">
</div>
<input type="button" name="select_all" class="select_all" value="${lang('pastafari2', 'select_all_servers', 'Select all servers')}" />
<input type="button" name="deselect_all" class="deselect_all" value="${lang('pastafari2', 'deselect_all_servers', 'Deselect all servers')}" />
<input type="button" name="update_selected_servers" class="update_selected_servers button_blue" value="${lang('pastafari2', 'update_selected_servers', 'Update selected servers')}" />
</div>
</%block>
<%block name="jscript_block">
<script language="Javascript" src="${make_media_url('js/jsutils/posting2.js', 'monit')}"></script>
<script language="Javascript" src="${make_media_url('js/jsutils/ajax_list.js', 'monit')}"></script>
<script>
$(document).ready(function () {
options={'url': "${url_for('.get_servers_task')}", extra_data: {'group_code': $('#group_servers').val()}};
alist=$('#table_servers').ajaxList('table_list', options);
function update_groups() {
$.ajax({
url: "${url_for('.get_groups_task')}",
data: {},
success: function (data) {
$('#group_id').html('<option value="">All groups</option>');
for(i in data) {
$('#group_id').append('<option value="'+data[i]['id']+'">'+data[i]['group']+'</option>');
}
},
dataType: 'json'
});
}
update_groups();
$('#group_id').click(function () {
options={'url': "${url_for('.get_servers_task')}", extra_data: {'group_id': $('#group_id').val()}};
alist.updateAjax('table_list', options, 0);
});
$('.select_all').click( function () {
$('.server_id').prop('checked', true);
});
$('.deselect_all').click( function () {
$('.server_id').prop('checked', false);
});
$('.update_selected_servers').click( function () {
if($('.server_id:checked').length==0) {
alert("${lang('pastafari2', 'no_servers_selected', 'No servers selected')}");
return false;
}
else {
$('#layer_loading').show();
server_ids=[];
$('.server_id').each( function () {
server_ids.push($(this).val());
});
$.ajax({
url:"${url_for('.pastafari2_update_task')}",
data: {'ids': JSON.stringify(server_ids)},
success: function (data) {
if(!data.error) {
//Redirect to multiprogress
location.href="${url_for('.pastafari2_multiprogress')}?task_id="+data.task_id;
}
else {
alert(data.txt_error);
}
$('#layer_loading').hide();
},
error: function (data) {
$('#layer_loading').hide();
alert('Error: '+data.status+' '+data.statusText);
},
type: 'POST',
dataType: 'json',
});
}
});
});
</script>
</%block>

View file

@ -0,0 +1,104 @@
<%inherit file="dashboard.phtml"/>
<%block name="content">
<h2>${name_task}</h2>
<p>${description_task}</p>
<hr />
<p>${lang('pastafari2', 'num_servers', 'Number of servers')}: <span id="num_servers">${num_servers}</span></p>
<p>${lang('pastafari2', 'completed_tasks', 'Completed tasks')}: <span id="num_completed">0</span></p>
<p id="detecting_servers" style="display:none;">${lang('pastafari2', 'loading_servers', 'Loading servers...')} <i class="fa fa-cog fa-spin fa-fw"></i></p>
<table class="table_servers" style="width:100%;">
<tr class="row_server" id="father_server" style="display:none;">
<td class="hostname">Hostname</td>
<td class="progress"><span class="progress_text">In progress</span> <i class="fa fa-cog fa-spin fa-fw"></i></td>
<td><a href="#" class="server_log">${lang('pastafari2', 'server_log', 'Server log')}</a></td>
</tr>
</table>
<div id="finished" style="display:none;">
<p><strong>All tasks were finished.</strong></p>
</div>
</%block>
<%block name="jscript_block">
<script>
ids=[];
//Get all tasks, next process 50 next progress.
$.ajax({
url: "${url_for('.pastafari2_get_servers_task')}",
data: {task_id: ${task_id}},
success: function (data) {
for(i in data) {
//console.log(data[i]);
new_row=$(father_server).clone().appendTo('.table_servers');
new_row.prop('id', 'task_'+data[i].id);
//console.log(data[i]);
new_row.children('.hostname').html(data[i].hostname);
new_row.find('.server_log').attr('href', "${url_for('.pastafari2_progress')}?task_id="+data[i].id);
new_row.show();
ids.push(data[i].id);
//console.log($('#father_server').attr('id'));
}
get_log();
setInterval(get_log, 1000);
},
dataType: 'json'
});
function get_log() {
$.ajax({
url: "${url_for('.pastafari2_get_multiprogress')}",
data: {ids: JSON.stringify(ids)},
success: function (data) {
/*$('.row_server').each(function () {
console.log($(this).attr('id'));
});*/
for(i in data) {
//console.log(data[i]);
//If is no_progress then show message.
if(!data[i].no_progress) {
//console.log('#server_'+data[i].server);
$('#task_'+data[i].task_id).find('.progress_text').html(data[i].message);
if(data[i].status==1) {
if(data[i].error==0) {
$('#task_'+data[i].task_id).find('i').removeClass('fa-cog fa-spin fa-fw').addClass('fa-check');
}
else {
$('#task_'+data[i].task_id).find('i').removeClass('fa-cog fa-spin fa-fw').addClass('fa-times');
}
}
}
}
},
dataType: 'json'
});
}
</script>
</%block>

View file

@ -0,0 +1,224 @@
<%inherit file="dashboard.phtml"/>
<%block name="extra_css">
<link href="${make_media_url('css/jquery-ui.min.css', 'pastafari2')}" rel="stylesheet">
<link href="${make_media_url('css/jquery-ui-theme.min.css', 'pastafari2')}" rel="stylesheet">
<style>
.ui-progressbar {
position: relative;
}
.progress-label {
position: absolute;
left: 50%;
top: 4px;
font-weight: bold;
color: #fff;
text-shadow: 1px 1px 0 #000;
}
</style>
</%block>
<%block name="content">
<h2>${lang('pastafari2', 'task progress', 'Task progress')} - ${name_task}</h2>
<p>${description_task}</p>
<hr />
<i class="fa fa-cog fa-spin fa-5x fa-fw margin-bottom" id="gear"></i>
<div id="progressbar"><div class="progress-label">${lang('pastafari2', 'processing_task', 'Processing task...')}</div></div>
<div id="no_progress" style="border: solid #cbcbcb 1px;height:150px;overflow:scroll;padding:2px;"></div>
</%block>
<%block name="jscript_block">
<script language="Javascript" src="${make_media_url('js/jquery-ui.min.js', 'pastafari2')}"></script>
<script>
position=${position};
yes_progress=1;
yes_position=0;
last_status=0;
text_complete="Complete!";
var progressbar = $( "#progressbar" ),
progressLabel = $( ".progress-label" );
progressbar.progressbar({
value: false,
change: function() {
if(progressbar.progressbar( "value" )>0)
{
progressLabel.text( progressbar.progressbar( "value" ) + "%" );
console.log('Progress '+progressbar.progressbar( "value" ) + "%");
}
else
{
progressbar.progressbar( "value", false);
progressLabel.text( "Processing task..." );
console.log('Processing task...');
}
},
complete: function() {
progressLabel.text( text_complete );
}
});
objDiv = document.getElementById("no_progress");
function update_messages_queue(message)
{
//timeout=setTimeout(function () {
progressbar.progressbar( "value", false );
$('#no_progress').append(message);
objDiv.scrollTop = objDiv.scrollHeight;
//}, 600);
//return timeout;
}
function update_progress_messages_queue(message, progress)
{
console.log('Getting progress...');
//timeout=setTimeout(function () {
progress=parseInt(progress);
progressbar.progressbar( "value", progress );
$('#no_progress').append(message+'<br />');
objDiv.scrollTop = objDiv.scrollHeight;
//}, 600);
//return timeout;
}
function finish_progress_error(progress)
{
progressbar.progressbar( "value", progress );
progressLabel.text( "ERROR, please see the log" );
}
function update_progress()
{
//pastafari/showprogress/tasks
$.ajax({
url: "${url_for('.pastafari2_getprogress')}?task_id=${task_id}&server=${server}&position="+position,
method: "POST",
dataType: "json",
data: {}
}).done(function(data) {
if(!data.hasOwnProperty("wait"))
{
x=data.length;
for(k=0;k<x;k++)
{
if(data[k].no_progress==1)
{
//yes_progress=0;
//$('#no_progress').append(data[k].message+'<br />');
update_messages_queue(data[k].message+'<br />');
//Scroll
}
else
if(data[k].no_progress==0)
{
update_progress_messages_queue(data[k].message, data[k].progress);
}
if(data[k].status!=1)
{
position+=1;
last_status=0;
}
else
{
position+=1;
last_status=1;
if(data[k].error==1)
{
text_complete='ERROR, please view the log';
finish_progress_error(data[k].progress);
console.log('ERROR, please view the log');
console.log('Error, finishing progress...');
}
else
{
//progressLabel.text( "Complete!" );
}
//clearTimeout(update_interval);
$('#gear').removeClass('fa-spin');
break;
}
}
if(last_status==0)
{
update_interval = setTimeout(update_progress, 1000);
console.log('Updating progress...');
}
else {
console.log('Finishing progress...');
}
}
else
{
console.log('Updating waiting progress...');
update_interval = setTimeout(update_progress, 1000);
}
}).fail(function (data) {
alert('Error: '+data.status+' '+data.statusText);
/*clearInterval(update_interval);*/
text_complete='ERROR, please view the log';
finish_progress_error(100);
$('#gear').removeClass('fa-spin');
});
}
update_progress();
</script>
</%block>

View file

@ -0,0 +1,49 @@
<%inherit file="dashboard.phtml"/>
<%block name="content">
<div id="principal_container">
<form method="post" name="generate_key" id="generate_key">
<h2>${lang('pastafari2', 'global_ssh_keys', 'Global ssh keys')}</h2>
<div class="form">
${txt_error|n}
${txt_generate_key|n}
</div>
% if not regenerate:
<p><input type="submit" value="${txt_generate_key_button}" /></p>
% endif
</form>
</div>
</%block>
<%block name="jscript_block">
<script language="Javascript" src="${make_media_url('js/jsutils/ajax_list.js', 'monit')}"></script>
<script language="Javascript" src="${make_media_url('js/jsutils/posting2.js', 'monit')}"></script>
<script>
% if not regenerate:
var options={url: "${url_for('admin_app.pastafari2_edit_global_ssh_keys')}", loading: '#layer_loading', pre_callback: function (data) {
//alert('This action overwrite all ssh keys');
}, success: function (data) {
/*$('#added_alert_success').show();
setTimeout(function () {
$('#added_alert_success').fadeOut();
}, 3000);*/
location.href="${url_for('admin_app.pastafari2_settings')}";
}
};
$('#generate_key').sendPost(options);
% endif
</script>
</%block>