├── .gitattributes ├── .gitignore ├── AUTHORS ├── CORE.md ├── Dockerfile ├── LICENSE ├── README.md ├── api └── api.py ├── bin ├── cld ├── cld-add ├── cld-auditor ├── cld-creds ├── cld-edit ├── cld-getpasswd ├── cld-groupadd ├── cld-groupdel ├── cld-grouplist ├── cld-groupparser ├── cld-initpasswd ├── cld-modulecreate ├── cld-modules ├── cld-mount ├── cld-sessions ├── cld-setpasswd ├── cld-umount ├── cld-update ├── cld-useradd ├── cld-userdel ├── cld-userlock ├── cld-userunlock ├── cldx ├── cldx-bash-notty ├── cldx-bash-tty ├── cldxmount ├── cldxumount ├── include │ └── cldfuncs └── init-main ├── bot ├── discord │ ├── cld-dcbot.service │ ├── dcbot.py │ └── init └── telegram │ ├── cld-tgbot.service │ ├── init │ └── tgbot.py ├── docker-compose.yml ├── docker ├── docker_init.sh ├── entrypoint.sh ├── init_creds.sh ├── nginx │ ├── cld.conf │ └── sslgen.conf └── scripts │ ├── lets_auto_gen │ ├── lets_auto_sign │ ├── lets_clean_subdomains │ └── lets_renew ├── helpcopyright ├── modules ├── access │ ├── README.md │ ├── api.py │ ├── api │ │ └── preloader.html │ ├── auditor │ ├── bin │ │ ├── cld-accesslist │ │ ├── cld-accesslistdeploy │ │ ├── cld-activateiptoken │ │ ├── cld-activatevpntoken │ │ ├── cld-banip │ │ ├── cld-banlist │ │ ├── cld-enableip │ │ ├── cld-myipbot │ │ ├── cld-myvpnbot │ │ ├── cld-sshkeysdeploy │ │ ├── cld-unbanip │ │ └── include │ │ │ ├── accessfuncs │ │ │ └── ovpnfuncs │ ├── bot.py │ ├── dcbot.py │ ├── examples │ │ ├── banips │ │ ├── custom_ports │ │ ├── custom_ports6 │ │ ├── custom_rules │ │ ├── custom_rules6 │ │ ├── local_nets │ │ ├── local_nets6 │ │ └── protected_ports │ ├── init │ ├── web.py │ └── web │ │ ├── access.html │ │ └── content │ │ └── logo.svg ├── ansible │ ├── README.md │ └── bin │ │ └── cld-ansible ├── backup │ ├── README.md │ ├── bin │ │ ├── cld-backup │ │ └── cld-backupreport │ ├── init │ ├── methods │ │ ├── clickhouse │ │ │ ├── backup │ │ │ └── example │ │ ├── etc │ │ │ ├── backup │ │ │ └── example │ │ ├── files │ │ │ ├── backup │ │ │ └── example │ │ ├── mongo │ │ │ ├── backup │ │ │ └── example │ │ ├── mysql │ │ │ ├── backup │ │ │ └── example │ │ └── postgresql │ │ │ ├── backup │ │ │ └── example │ ├── web.py │ └── web │ │ ├── backup.html │ │ └── content │ │ └── logo.svg ├── cm │ ├── README.md │ ├── bin │ │ ├── cld-cm │ │ ├── cld-cmbackupcheck │ │ ├── cld-cmcontrol │ │ ├── cld-cmcreate │ │ ├── cld-cmmigrate │ │ ├── cld-cmterm │ │ └── include │ │ │ ├── autologin_vars │ │ │ ├── bot │ │ │ ├── create_funcs │ │ │ ├── create_logic │ │ │ ├── create_vars │ │ │ ├── dc_funcs │ │ │ ├── migrate_vars │ │ │ ├── privatenet_vars │ │ │ ├── template_functions │ │ │ ├── template_logic │ │ │ └── template_vars │ ├── init │ ├── web.py │ └── web │ │ ├── cm.html │ │ └── content │ │ ├── cm.css │ │ ├── cm.js │ │ └── logo.svg ├── cmd │ └── bin │ │ └── cld-cmd ├── deploy │ ├── README.md │ ├── api.py │ ├── bin │ │ ├── cld-action │ │ ├── cld-deploy │ │ ├── cld-template │ │ └── include │ │ │ └── deployfuncs │ ├── web.py │ └── web │ │ ├── content │ │ ├── deploy.css │ │ ├── deploy.js │ │ └── logo.svg │ │ └── deploy.html ├── dns │ ├── README.md │ ├── bin │ │ ├── cld-cfcache │ │ ├── cld-cfdel │ │ ├── cld-cfdnsbackup │ │ ├── cld-cfset │ │ ├── cld-cfunderattack │ │ ├── cld-changefront │ │ ├── cld-deldns │ │ ├── cld-dnssync │ │ ├── cld-domain │ │ ├── cld-geo │ │ ├── cld-getdns │ │ ├── cld-getip │ │ ├── cld-getns │ │ ├── cld-listdns │ │ ├── cld-setdns │ │ ├── cld-whois │ │ ├── cld-wildcardssl-deploy │ │ ├── cld-wildcardssl-issue │ │ └── include │ │ │ └── dnsfuncs │ └── init ├── doc │ ├── README.md │ ├── bin │ │ ├── cld-docpublicgen │ │ └── cld-tgcmdgen │ ├── doc-common.py │ ├── doc.py │ ├── web.py │ └── web │ │ ├── content │ │ ├── doc.css │ │ └── logo.svg │ │ └── doc.html ├── filemanager │ ├── README.md │ ├── web.py │ └── web │ │ ├── content │ │ └── logo.svg │ │ └── filemanager.html ├── infraconfig │ ├── README.md │ ├── bin │ │ └── cld-infraconfig │ ├── data │ │ ├── groups │ │ │ └── .gitkeep │ │ └── instances │ │ │ └── .gitkeep │ ├── init │ ├── web.py │ └── web │ │ └── infraconfig.html ├── kubernetes │ ├── README.md │ ├── bin │ │ ├── cld-kubeaccesslistdeploy │ │ ├── cld-kubecluster │ │ └── cld-kubeuseradd │ └── init ├── note │ ├── README.md │ ├── api.py │ ├── bin │ │ └── cld-note │ ├── web.py │ └── web │ │ ├── content │ │ ├── logo.svg │ │ ├── note.css │ │ └── note.js │ │ └── note.html ├── spamcheck │ ├── README.md │ └── bin │ │ ├── cld-spamcheck │ │ └── cld-spamchecker ├── telegramcloud │ ├── README.md │ ├── api.py │ ├── bin │ │ ├── cld-tcloud-message │ │ ├── cld-tcloud-split │ │ ├── cld-tcloud-stream │ │ └── cld-tcloud-upload │ └── bot.py └── zabbix │ ├── README.md │ ├── bin │ ├── cld-webcheckadd │ ├── cld-webcheckdel │ ├── cld-webchecklist │ └── cld-zbxuploadxml │ ├── init │ └── zbx │ ├── scripts │ └── checkssl.sh │ └── templates │ ├── expire_ssl_and_registration.yaml │ └── web_url_check.yaml ├── requirements.txt ├── setup ├── access │ ├── groups │ │ ├── aws │ │ │ ├── parsingscript │ │ │ └── type │ │ ├── default │ │ │ └── clouds │ │ ├── digitalocean │ │ │ ├── clouds │ │ │ ├── funcmount │ │ │ ├── funcs │ │ │ ├── functerm │ │ │ ├── funcumount │ │ │ ├── funcvars │ │ │ ├── parsingscript │ │ │ └── type │ │ ├── openvz │ │ │ ├── clouds │ │ │ ├── funcmount │ │ │ ├── funcs │ │ │ ├── functerm │ │ │ ├── funcumount │ │ │ ├── funcvars │ │ │ ├── parsingscript │ │ │ └── type │ │ ├── proxmox │ │ │ ├── clouds │ │ │ ├── funcmount │ │ │ ├── funcs │ │ │ ├── functerm │ │ │ ├── funcumount │ │ │ ├── funcvars │ │ │ ├── parsingscript │ │ │ └── type │ │ ├── scaleway │ │ │ ├── parsingscript │ │ │ └── type │ │ └── virtuozzo │ │ │ ├── clouds │ │ │ ├── funcmount │ │ │ ├── funcs │ │ │ ├── functerm │ │ │ ├── funcumount │ │ │ ├── funcvars │ │ │ ├── parsingscript │ │ │ └── type │ └── users │ │ └── admin │ │ ├── clouds │ │ ├── groups │ │ └── role ├── creds │ ├── creds │ └── protected_ports ├── etc │ └── cron.d │ │ └── cld └── install_cld.sh ├── supervisord.conf └── web ├── css ├── login.css ├── main.css └── toolkit.css ├── dashboard.py ├── font └── D3Euronism.woff ├── html ├── admin.html ├── cldx.html ├── group.html ├── include │ ├── footer.html │ ├── head.html │ ├── navbar-term.html │ └── navbar.html ├── index.html ├── login.html ├── profile.html ├── socket.html ├── terminal.html ├── toolkit.html └── user.html ├── img ├── administration.svg ├── cld_h.svg ├── cld_v.svg ├── favicon.ico ├── favicon_term.ico ├── geck.svg ├── module.svg ├── plus.svg ├── profile.svg └── shell.svg ├── init └── js ├── tablesort.js ├── terminal.js └── toolkit.js /.gitattributes: -------------------------------------------------------------------------------- 1 | web/html/* linguist-vendored 2 | web/css/* linguist-vendored 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #creds 2 | /creds/ 3 | 4 | #cld modules generated data and temp 5 | /modules/*/data/ 6 | !/modules/infraconfig/data/ 7 | !/modules/infraconfig/data/instances/ 8 | !/modules/infraconfig/data/groups/ 9 | /modules/*/tmp/ 10 | 11 | #local files 12 | *.local 13 | *.local/* 14 | .idea* 15 | 16 | #temp folder 17 | /tmp/ 18 | 19 | # runtime data for Docker deployment 20 | /docker/etc/ 21 | /docker/home/ 22 | /docker/root/ 23 | 24 | #access 25 | /access/ 26 | 27 | #built-in modules 28 | /modules/* 29 | !/modules/access/ 30 | !/modules/ansible/ 31 | !/modules/backup/ 32 | !/modules/cm/ 33 | !/modules/cmd/ 34 | /modules/cmd/bin/cld-cmd* 35 | !/modules/cmd/bin/cld-cmd 36 | !/modules/spamcheck/ 37 | !/modules/doc/ 38 | !/modules/deploy/ 39 | !/modules/dns/ 40 | !/modules/lead/ 41 | !/modules/note/ 42 | !/modules/etcbackup/ 43 | !/modules/filemanager/ 44 | !/modules/kubernetes/ 45 | !/modules/telegramcloud/ 46 | !/modules/zabbix/ 47 | !/modules/infraconfig/ 48 | 49 | #built-in backup methods 50 | /modules/backup/methods/* 51 | !/modules/backup/methods/clickhouse/ 52 | !/modules/backup/methods/etc/ 53 | !/modules/backup/methods/files/ 54 | !/modules/backup/methods/mongo/ 55 | !/modules/backup/methods/mysql/ 56 | !/modules/backup/methods/postgresql/ 57 | 58 | #deploy 59 | /modules/deploy/templates/* 60 | /modules/deploy/deploys/* 61 | /modules/deploy/actions/* 62 | /modules/deploy/repo_list 63 | 64 | #security 65 | /api/accesslist 66 | 67 | #api/web staff 68 | /api/modules/* 69 | /web/modules/* 70 | /web/flask_session/* 71 | /web/html/include/cld_tier* 72 | 73 | #legacy symlink 74 | /ext_srv 75 | 76 | #cloudmaker module 77 | /modules//cm/LOCK 78 | 79 | #logs 80 | /log/ 81 | /logs/ 82 | *screenlog.* 83 | 84 | #pycache 85 | *__pycache__* 86 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Core developers 2 | =============== 3 | 4 | * Aleksandr Chendev 5 | Initial idea. -------------------------------------------------------------------------------- /CORE.md: -------------------------------------------------------------------------------- 1 | Core module of the project, contains the framework and basic scripts that provide the logic of the system -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM almalinux:9 2 | 3 | RUN dnf -y install epel-release \ 4 | && dnf -y install \ 5 | openssh-server nginx supervisor python3 python3-pip cronie screen certbot \ 6 | && dnf clean all 7 | 8 | RUN mkdir -p /var/run/sshd /var/log/nginx /var/cld /root/sbin 9 | 10 | COPY requirements.txt /tmp/requirements.txt 11 | RUN pip3 install --no-cache-dir -r /tmp/requirements.txt && rm -f /tmp/requirements.txt 12 | 13 | COPY supervisord.conf /etc/supervisord.conf 14 | COPY docker/nginx/cld.conf /etc/nginx/conf.d/cld.conf 15 | COPY docker/nginx/sslgen.conf /etc/nginx/sslgen.conf 16 | RUN touch /etc/nginx/accesslist /etc/nginx/deny.conf 17 | 18 | COPY docker/scripts/lets_auto_sign /root/sbin/lets_auto_sign 19 | COPY docker/scripts/lets_renew /root/sbin/lets_renew 20 | COPY docker/scripts/lets_clean_subdomains /root/sbin/lets_clean_subdomains 21 | COPY docker/scripts/lets_auto_gen /etc/cron.d/lets_auto_gen 22 | COPY docker/init_creds.sh /docker/init_creds.sh 23 | RUN chmod 700 /root/sbin/lets_auto_sign /root/sbin/lets_renew /root/sbin/lets_clean_subdomains \ 24 | && chmod 644 /etc/cron.d/lets_auto_gen \ 25 | && screen -m /root/sbin/lets_clean_subdomains 26 | 27 | COPY docker/entrypoint.sh /entrypoint.sh 28 | ENTRYPOINT ["/entrypoint.sh"] 29 | EXPOSE 22 80 443 30 | VOLUME ["/var/cld"] 31 | CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] 32 | -------------------------------------------------------------------------------- /bin/cld-add: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Utility to add new cld instance string 4 | Interactive without arguments 5 | EOL 6 | ) 7 | HELP_ARGS=$(cat << 'EOL' 8 | $1 Full cld string like instance-name_1.2.3.4_22_root 9 | $2 Name of cld instance group to add - "default" is default 10 | EOL 11 | ) 12 | HELP_EXAMPLES=$(cat << 'EOL' 13 | cld-add instance-name_1.2.3.4_22_root 14 | cld-add instance-name_1.2.3.4_22_root groupname 15 | EOL 16 | ) 17 | source /var/cld/bin/include/cldfuncs 18 | CLOUD=$1 19 | GROUP=$2 20 | [ "$GROUP" ] || GROUP=default 21 | CLOUDSFILE=/var/cld/access/groups/$GROUP/clouds 22 | 23 | if egrep -q "^[A-Za-z0-9.-]+_((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" <<< "${CLOUD}" 24 | then 25 | VMN=$(cut -d "_" -f 1 <<< $CLOUD) 26 | SRV=$(cut -d "_" -f 2 <<< $CLOUD) 27 | PRT=$(cut -d "_" -f 3 <<< $CLOUD) 28 | USR=$(cut -d "_" -f 4 <<< $CLOUD) 29 | PWD=$(cut -d _ -f 5- <<< $CLOUD) 30 | [ "${PRT}" ] || PRT=22 31 | [ "${USR}" ] || USR=root 32 | [ "${PWD}" ] && PWD="_${PWD}" 33 | if grep -q "^${VMN}_${SRV}_${PRT}_${USR}${PWD}$" ${CLOUDSFILE} 34 | then 35 | echo "cloud ${VMN}_${SRV}_${PRT}_${USR}${PWD} already exist in group ${GROUP}" 36 | else 37 | echo "${VMN}_${SRV}_${PRT}_${USR}${PWD}" >> ${CLOUDSFILE} && echo instance ${VMN}_${SRV}_${PRT}_${USR} added to group ${GROUP} || echo instance ${VMN}_${SRV}_${PRT}_${USR} was NOT added to group ${GROUP} 38 | fi 39 | else 40 | init-string 'INSTANCE_NAME|server1.example.com|[A-Za-z0-9.-]+' 'INSTANCE_IP|1.2.3.4|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' 'INSTANCE_PORT|22|[0-9]{2,5}' 'INSTANCE_USER|root|[A-Za-z0-9@.-]+' --file=${CLOUDSFILE} 41 | fi -------------------------------------------------------------------------------- /bin/cld-auditor: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Continuous running auditor files code with 5 seconds interval - running from systemd cld-auditor service 4 | EOL 5 | ) 6 | 7 | source /var/cld/bin/include/cldfuncs 8 | 9 | [ -d "/var/cld/tmp/auditor" ] || mkdir -p /var/cld/tmp/auditor 10 | 11 | ( 12 | while :; do 13 | ### Security checks 14 | if [ "$(stat -c "%a" /var/cld)" != "700" ] 15 | then 16 | chattr -i /var/cld 17 | chmod 700 /var/cld 18 | chattr +i /var/cld 19 | fi 20 | 21 | if ! [[ "$(lsattr -d /var/cld)" =~ ^[A-Za-z-]+i[A-Za-z-]+\ +/var/cld$ ]] 22 | then 23 | chattr +i /var/cld 24 | fi 25 | sleep 5s 26 | done 27 | ) & 28 | 29 | for AUDITOR_FILE in $(find /var/cld/* /var/cld/bot/* /var/cld/modules/* -maxdepth 1 -type f -name 'auditor' 2>/dev/null) 30 | do 31 | AUDITOR_FILE_CONTENT="$(cat ${AUDITOR_FILE})" 32 | ( 33 | while :; do 34 | source <(echo "${AUDITOR_FILE_CONTENT}") 35 | sleep 5s 36 | done 37 | ) & 38 | done 39 | wait -------------------------------------------------------------------------------- /bin/cld-creds: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Utility export credentials in human readable or defined application format 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 First PATTERN filtering allowed instances 8 | $2 Second PATTERN filtering allowed instances 9 | $3 Third PATTERN filtering allowed instances 10 | --groups=GROUP1,GROUP2 Filtering by instance groups 11 | --mtputty Export data in mtputty app format to paste as group 12 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to access matrix 13 | --password Admin user option - will show password if it exist at regular CLD instance string 14 | EOL 15 | ) 16 | HELP_EXAMPLES=$(cat << 'EOL' 17 | cld-creds 18 | cld-creds prod 1.2. 19 | cld-creds --groups=gcloud prod --debug 20 | EOL 21 | ) 22 | HELP_ONLY="CLI WEB" 23 | 24 | source /var/cld/bin/include/cldfuncs 25 | 26 | for i in ${CLDOPTS} 27 | do 28 | case $i in 29 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 30 | -m|-mtputty|--mtputty) MTPUTTY_EXPORT=1 ;; 31 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 32 | -p|-password|--password) SHOW_PASS=1 ;; 33 | -*) ;; 34 | *) let ii++; declare ARG$ii=${i} ;; 35 | esac 36 | done 37 | 38 | CLD_USER_ROLE=$(user_is_admin $SUDO_USER) 39 | 40 | showcreds() 41 | { 42 | if [ "$CLD_USER_ROLE" = "0" -a "$SHOW_PASS" = "1" ] 43 | then 44 | echo 45 | for CRED in $(declare -f $CLD_VARS | grep "=" | grep -v "[\|]" | cut -d = -f 1) 46 | do 47 | test ${!CRED} && echo $(echo $CRED | sed -e 's#^VM$#instance#g' -e 's#VMN#Host:#' -e 's#SRV#ip:#' -e 's#USR#user:#' -e 's#PRT#port:#' -e 's#PWD#password:#') ${!CRED} 48 | done 49 | else 50 | echo 51 | for CRED in $(declare -f $CLD_VARS | grep "=" | grep -v "PWD\|[\|]" | cut -d = -f 1) 52 | do 53 | [ "${!CRED}" ] && echo $(echo $CRED | sed -e 's#^VM$#instance#g' -e 's#VMN#Host:#' -e 's#SRV#ip:#' -e 's#USR#user:#' -e 's#PRT#port:#') ${!CRED} 54 | done 55 | fi 56 | } 57 | 58 | exportputty() 59 | { 60 | cat << EOMTPUTTY 61 | Default Settings${VMN}{$(echo $(uuidgen) | tr [:lower:] [:upper:])}${SRV}0${PRT}root0${SRV} -l root -P ${PRT}0 62 | EOMTPUTTY 63 | } 64 | 65 | [ "$MTPUTTY_EXPORT" ] && echo "$(hostname)" 66 | for VM in $(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" "$ARG1" "$ARG2" "$ARG3" "$CLD_ALL_GROUPS_ARG") 67 | do 68 | CLD_LOGS 69 | if [ "$VM" ] 70 | then 71 | INSTANCE_GROUP_FUNCS 72 | $CLD_VARS 73 | [ "$MTPUTTY_EXPORT" ] && exportputty || showcreds 74 | fi 75 | done 76 | [ "$MTPUTTY_EXPORT" ] && echo "" -------------------------------------------------------------------------------- /bin/cld-edit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | CLD group instance list editor 4 | This is "admin" role tool 5 | EOL 6 | ) 7 | HELP_ARGS=$(cat << 'EOL' 8 | $1 CLD group to edit 9 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to access matrix 10 | EOL 11 | ) 12 | HELP_EXAMPLES=$(cat << 'EOL' 13 | cld-edit 14 | cld-edit default 15 | EOL 16 | ) 17 | HELP_ONLY="CLI WEB" 18 | source /var/cld/bin/include/cldfuncs 19 | 20 | for i in ${CLDOPTS} 21 | do 22 | case $i in 23 | -a|-all|--all) CLD_ALL_GROUPS=1 ;; 24 | -*) ;; 25 | *) let ii++; declare ARG$ii=${i} ;; 26 | esac 27 | done 28 | 29 | CLD_GROUP="${ARG1}" 30 | 31 | if [ "${CLD_ALL_GROUPS}" = "1" ] 32 | then 33 | if [ "$(user_is_admin $SUDO_USER)" = "0" ] 34 | then 35 | CLD_FILTER_GROUPS="$(find /var/cld/access/groups/ -mindepth 1 -maxdepth 1 | cut -d / -f 6 | grep "${CLD_GROUPS}")" 36 | else 37 | CLD_FILTER_GROUPS="$(grep "^${SUDO_USER}:" /var/cld/creds/passwd | cut -d : -f 6 | tr ',' '\n' | grep "${CLD_GROUPS}")" 38 | fi 39 | else 40 | CLD_FILTER_GROUPS="$(grep "^${SUDO_USER}:" /var/cld/creds/passwd | cut -d : -f 6 | tr ',' '\n' | grep "${CLD_GROUPS}")" 41 | fi 42 | 43 | ALLOWED_GROUPS=$( 44 | for CLD_FILTER_GROUP in ${CLD_FILTER_GROUPS} 45 | do 46 | grep -qs "1" /var/cld/access/groups/${CLD_FILTER_GROUP}/type || echo ${CLD_FILTER_GROUP} 47 | done 48 | ) 49 | 50 | [ "$ALLOWED_GROUPS" ] || { echo ALLOWED GROUPS for user $SUDO_USER not defined ; exit 1 ; } 51 | 52 | if ! [ "$CLD_GROUP" ] 53 | then 54 | echo "Please choose group to edit instance list" 55 | select CLD_GROUP in ${ALLOWED_GROUPS} 56 | do 57 | CLD_LOGS 58 | if [ "$CLD_GROUP" ] 59 | then 60 | break 61 | fi 62 | done 63 | fi 64 | 65 | if ! [ "$CLD_GROUP" ] 66 | then 67 | echoexit1 Group is not defined 68 | fi 69 | 70 | grep -q "^${CLD_GROUP}$" <<< "${ALLOWED_GROUPS}" || { echo CLD_GROUP is not defined ; exit 1 ; } 71 | 72 | if [ "$(grep -q "^${CLD_GROUP}$" <<< "${ALLOWED_GROUPS}" && echo 0)" = "0" -a "$(user_is_admin ${SUDO_USER?})" = "0" ] 73 | then 74 | nano /var/cld/access/groups/${CLD_GROUP}/clouds 75 | else 76 | echoexit1 Group is not defined 77 | fi 78 | -------------------------------------------------------------------------------- /bin/cld-getpasswd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Get user passwd column 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | --user=username CLD PAM user name - admin setting - without will equal current user value 8 | --[bot|api|modules|tools|groups] Show user column from /var/cld/creds/passwd 9 | EOL 10 | ) 11 | HELP_EXAMPLES=$(cat << 'EOL' 12 | cld-getpasswd --bot 13 | cld-getpasswd -u=user1 -g 14 | cld-getpasswd --user=user1 --groups 15 | EOL 16 | ) 17 | 18 | source /var/cld/bin/include/cldfuncs 19 | 20 | for i in ${CLDOPTS} 21 | do 22 | case $i in 23 | -u=*|-user=*|--user=*) CLD_USER="${i#*=}" ;; 24 | -b|-bot|--bot) CLD_PERMS="bot" ;; 25 | -a|-api|--api) CLD_PERMS="api" ;; 26 | -m|-modules|--modules) CLD_PERMS="modules" ;; 27 | -t|-tools|--tools) CLD_PERMS="tools" ;; 28 | -g|-groups|--groups) CLD_PERMS="groups" ;; 29 | -*) ;; 30 | *) let ii++; declare ARG$ii=${i} ;; 31 | esac 32 | done 33 | 34 | [ "$(user_is_admin ${SUDO_USER})" != "0" ] && { unset CLD_USER ; CLD_USER=${SUDO_USER} ; } 35 | [ "$CLD_USER" ] || CLD_USER=$ARG1 36 | [ "$CLD_USER" ] || { echo CLD_USER is not defined - exit ; exit 1 ; } 37 | CLD_PASSWD_CONTENT="$(cat /var/cld/creds/passwd)" 38 | grep -q "^${CLD_USER}:" <<< "${CLD_PASSWD_CONTENT}" || { echo CLD_USER is not found - exit ; exit 1 ; } 39 | 40 | if [ "$CLD_PERMS" == "bot" ]; then 41 | awk -F ':' '/^'${CLD_USER}':/{print $2}' <<< "${CLD_PASSWD_CONTENT}" | sed -e 's#,,#,#g' -e 's#,:#:#g' -e 's#:,#:#g' 42 | elif [ "$CLD_PERMS" == "api" ]; then 43 | awk -F ':' '/^'${CLD_USER}':/{print $3}' <<< "${CLD_PASSWD_CONTENT}" | sed -e 's#,,#,#g' -e 's#,:#:#g' -e 's#:,#:#g' 44 | elif [ "$CLD_PERMS" == "modules" ]; then 45 | CLD_COLUMN=$(awk -F ':' '/^'${CLD_USER}':/{print $4}' <<< "${CLD_PASSWD_CONTENT}" | sed -e 's#,,#,#g' -e 's#,:#:#g' -e 's#:,#:#g') 46 | [ "$CLD_COLUMN" == "ALL" ] && cat /var/cld/creds/modules_list || echo "$CLD_COLUMN" 47 | elif [ "$CLD_PERMS" == "tools" ]; then 48 | CLD_COLUMN=$(awk -F ':' '/^'${CLD_USER}':/{print $5}' <<< "${CLD_PASSWD_CONTENT}" | sed -e 's#,,#,#g' -e 's#,:#:#g' -e 's#:,#:#g') 49 | [ "$CLD_COLUMN" == "ALL" ] && cat /var/cld/creds/tools_list || echo "$CLD_COLUMN" 50 | elif [ "$CLD_PERMS" == "groups" ]; then 51 | awk -F ':' '/^'${CLD_USER}':/{print $6}' <<< "${CLD_PASSWD_CONTENT}" | sed -e 's#,,#,#g' -e 's#,:#:#g' -e 's#:,#:#g' 52 | fi -------------------------------------------------------------------------------- /bin/cld-groupadd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Add instance group - create files in /var/cld/access/groups/${GROUP}/ 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 Group name 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-groupadd awscloud 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | GROUP=$1 16 | [ "$GROUP" ] || echoexit1 CLD group is not defined 17 | mkdir -p /var/cld/access/groups/${GROUP} 18 | touch /var/cld/access/groups/${GROUP}/clouds 19 | chmod -R 700 /var/cld/access/ 20 | for LOOP_FUNC in funcvars_VARS functerm_TERMINAL funcmount_MOUNT funcumount_UMOUNT funcdeploy_DEPLOY funcdeploynotty_DEPLOY_NOTTY 21 | do 22 | GROUPFUNC=$(cut -d _ -f 1 <<< ${LOOP_FUNC}) 23 | NAMEFUNC=$(cut -d _ -f 2- <<< ${LOOP_FUNC}) 24 | cat > /var/cld/access/groups/${GROUP}/${GROUPFUNC} << EOL 25 | $(declare -f EXTERNAL_${NAMEFUNC} | tail -n +3 | head -n -1) 26 | EOL 27 | done -------------------------------------------------------------------------------- /bin/cld-groupdel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Delete instance group - recursive delete directory /var/cld/access/groups/${GROUP} 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 Group name 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-groupdel awscloud 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | GROUP=$1 16 | [ "$GROUP" ] || echoexit1 CLD group is not defined 17 | if [ ! -z "$GROUP" ] ; then 18 | rm -f /var/cld/access/groups/${GROUP}/* 19 | rmdir /var/cld/access/groups/${GROUP} 20 | sed -i '/'${GROUP}'/d' /var/cld/access/users/*/groups 21 | fi 22 | -------------------------------------------------------------------------------- /bin/cld-grouplist: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Show list of groups 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | --json Json outout option 8 | --beauty Using together with --json option to beautify json output 9 | EOL 10 | ) 11 | HELP_EXAMPLES=$(cat << 'EOL' 12 | cld-grouplist 13 | cld-grouplist --json 14 | EOL 15 | ) 16 | 17 | source /var/cld/bin/include/cldfuncs 18 | 19 | for i in ${CLDOPTS} 20 | do 21 | case $i in 22 | -j|-json|--json) JSON=1 ;; 23 | -b|-beauty|--beauty) JSON_BEAUTY=1 ;; 24 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 25 | -*) ;; 26 | *) let ii++; declare ARG$ii=${i} ;; 27 | esac 28 | done 29 | 30 | if [ "$JSON_BEAUTY" == "1" -a "$FROM" == "API" ]; then 31 | JSON_BEAUTY_ARG='| head -c -1 | jq -R -s -C "split(\"\n\")"' 32 | elif [ "$JSON_BEAUTY" == "1" -a "$FROM" != "API" ]; then 33 | JSON_BEAUTY_ARG='| head -c -1 | jq -R -s "split(\"\n\")"' 34 | elif [ "$JSON" == "1" ]; then 35 | JSON_BEAUTY_ARG='| head -c -1 | jq -R -s -c "split(\"\n\")"' 36 | fi 37 | 38 | source <(echo -n CLOUDS_USER_ALLOWED --grouplist ${CLD_ALL_GROUPS_ARG} ${JSON_BEAUTY_ARG}) -------------------------------------------------------------------------------- /bin/cld-groupparser: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | ClassicDevOps instances group parser - executing parsing scripts of groups marked as "parsing" - not affecting "manual" type groups 4 | Should be setted up on regular cron execution 5 | EOL 6 | ) 7 | HELP_EXAMPLES=$(cat << 'EOL' 8 | cld-groupparser 9 | EOL 10 | ) 11 | source /var/cld/bin/include/cldfuncs 12 | 13 | for GROUP in $(ls /var/cld/access/groups/) 14 | do 15 | export GROUP 16 | grep -qs '1' /var/cld/access/groups/${GROUP}/type && source /var/cld/access/groups/${GROUP}/parsingscript 17 | done 18 | 19 | /var/cld/bin/cld --list --all | sort -u | egrep "^[A-Za-z0-9.-]+_[A-Za-z0-9.-]+_[0-9]{1,5}_[A-Za-z0-9.-]" | awk -F _ '{print "Host "$0"\n HostName "$2"\n User "$4"\n Port "$3"\n StrictHostKeyChecking no\n"}' > /root/.ssh/config.cld.bak 20 | 21 | mv -f /root/.ssh/config.cld.bak /root/.ssh/config.cld 22 | grep -q "Include config.cld" /root/.ssh/config || echo "Include config.cld" >> /root/.ssh/config -------------------------------------------------------------------------------- /bin/cld-modules: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Show list of modules and tools 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 First PATTERN filtering allowed tools 8 | $2 Second PATTERN filtering allowed tools 9 | $3 Third PATTERN filtering allowed tools 10 | --json Json outout option 11 | --beauty Using together with --json option to beautify json output 12 | --modules=MODULE1,MODULE2 Filtering by cld modules 13 | EOL 14 | ) 15 | HELP_EXAMPLES=$(cat << 'EOL' 16 | cld-modules 17 | cld-modules --json 18 | cld-modules cld check --modules=access,dns --json 19 | EOL 20 | ) 21 | 22 | source /var/cld/bin/include/cldfuncs 23 | 24 | for i in ${CLDOPTS} 25 | do 26 | case $i in 27 | -m=*|-modules=*|--modules=*) CLD_MODULES="${i#*=}" ;; 28 | -j|-json|--json) JSON=1 ;; 29 | -b|-beauty|--beauty) JSON_BEAUTY=1 ;; 30 | -*) ;; 31 | *) let ii++; declare ARG$ii=${i} ;; 32 | esac 33 | done 34 | 35 | [ "$JSON" == "1" ] && JSONARG='--json' 36 | [ "$JSON_BEAUTY" == "1" -a "$FROM" == "API" ] && JSON_BEAUTY_ARG='| jq . -C' 37 | [ "$JSON_BEAUTY" == "1" -a "$FROM" != "API" ] && JSON_BEAUTY_ARG='| jq .' 38 | 39 | source <(echo -n MODULES_USER_ALLOWED --modules="${CLD_MODULES}" "${JSONARG}" "$ARG1" "$ARG2" "$ARG3" ${JSON_BEAUTY_ARG}) -------------------------------------------------------------------------------- /bin/cld-mount: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Interactive utility for mount filesystem of instance 4 | Remote filesystem mounting by sshfs (or another method according to custom function) in /home/${USER}/mnt/${CLD_INSTANCE} directory 5 | EOL 6 | ) 7 | HELP_ARGS=$(cat << 'EOL' 8 | $1 First PATTERN filtering allowed instances 9 | $2 Second PATTERN filtering allowed instances 10 | $3 Third PATTERN filtering allowed instances 11 | --groups=GROUP1,GROUP2 Filtering by instance groups 12 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to 13 | EOL 14 | ) 15 | HELP_EXAMPLES=$(cat << 'EOL' 16 | cld-mount 17 | cld-mount prod 1.2. 18 | cld-mount prod 1.2.3.4_instance_22_root --groups=gcloud 19 | EOL 20 | ) 21 | HELP_ONLY="CLI WEB" 22 | source /var/cld/bin/include/cldfuncs 23 | 24 | for i in ${CLDOPTS} 25 | do 26 | case $i in 27 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 28 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 29 | -*) ;; 30 | *) let ii++; declare ARG$ii=${i} ;; 31 | esac 32 | done 33 | 34 | select VM in $(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" "$ARG1" "$ARG2" "$ARG3" "$CLD_ALL_GROUPS_ARG") 35 | do 36 | CLD_LOGS 37 | if [ "$VM" ] 38 | then 39 | INSTANCE_GROUP_FUNCS 40 | $CLD_VARS 41 | echo 42 | $CLD_MOUNT && echo -e "Inctance filesystem mounted to \n$LOCALMOUNTPATH" || echo "Mount FAILED - check manual access to instance or custom mount group funtion" 43 | exit 0 44 | fi 45 | break 46 | done 47 | echo 48 | echo "There is no any allowed instances - try remove filter arguments or ask your system administrator add/share it" -------------------------------------------------------------------------------- /bin/cld-sessions: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Interactive utility to watch active classicdevops user sessions in real time 4 | EOL 5 | ) 6 | HELP_EXAMPLES=$(cat << 'EOL' 7 | cld-sessions 8 | EOL 9 | ) 10 | HELP_ONLY="CLI WEB" 11 | source /var/cld/bin/include/cldfuncs 12 | echo 13 | echo Please choose one of active sessions below 14 | echo 15 | select FILE in $(ps ax | grep tee | grep -v grep | awk '{print $7}') 16 | do 17 | while read -r LINE; do 18 | cat << EOL 19 | $LINE 20 | EOL 21 | read -s < "$(tty 0>&2)" 22 | done < $FILE 23 | break 24 | done 25 | -------------------------------------------------------------------------------- /bin/cld-umount: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Interactive mount utility for mount filesystems of instance 4 | Remote filesystem mounting by sshfs in /home/${USER}/mnt/${CLD_INSTANCE} directory 5 | EOL 6 | ) 7 | HELP_ARGS=$(cat << 'EOL' 8 | $1 First PATTERN filtering allowed instances 9 | $2 Second PATTERN filtering allowed instances 10 | $3 Third PATTERN filtering allowed instances 11 | --groups=GROUP1,GROUP2 Filtering by instance groups 12 | EOL 13 | ) 14 | HELP_EXAMPLES=$(cat << 'EOL' 15 | cld-umount 16 | cld-umount prod 1.2. 17 | cld-umount prod 1.2.3.4_instance_22_root --groups=gcloud 18 | EOL 19 | ) 20 | HELP_ONLY="CLI WEB" 21 | source /var/cld/bin/include/cldfuncs 22 | 23 | for i in ${CLDOPTS} 24 | do 25 | case $i in 26 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 27 | -*) ;; 28 | *) let ii++; declare ARG$ii=${i} ;; 29 | esac 30 | done 31 | 32 | select VM in $(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" "$ARG1" "$ARG2" "$ARG3" | grep "$(df 2>/dev/null | grep /home/${SUDO_USER}/mnt | rev | cut -d / -f 1 | rev)") 33 | do 34 | CLD_LOGS 35 | if [ "$VM" ] 36 | then 37 | INSTANCE_GROUP_FUNCS 38 | $CLD_VARS 39 | echo 40 | $CLD_UMOUNT && echo -e "Inctance filesystem unmounted from \n$LOCALMOUNTPATH" 41 | fi 42 | break 43 | done -------------------------------------------------------------------------------- /bin/cld-userdel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Delete user - remove record of user at /var/cld/creds/passwd and all relevant directories 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 User name 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-userdel johndoe 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | 16 | for i in ${CLDOPTS} 17 | do 18 | case $i in 19 | -*) ;; 20 | *) let ii++; declare ARG$ii=${i} ;; 21 | esac 22 | done 23 | 24 | CLDUSER=${ARG1} 25 | [ "$CLDUSER" ] || echoexit1 CLD user is not defined 26 | userdel ${CLDUSER} 27 | rm -rf /home/${CLDUSER}/ 28 | rm -rf /var/cld/access/users/${CLDUSER}/ 29 | sed -ir "/^${CLDUSER} ALL.*u/d" /etc/sudoers 30 | sed -i '/^'${CLDUSER}':/d' /etc/passwd 31 | sed -i '/^'${CLDUSER}':/d' /var/cld/creds/passwd -------------------------------------------------------------------------------- /bin/cld-userlock: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Lock user - Modifying record of user at /etc/shadow - restricts the ability to login to the CLD server by SSH and web interface 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 User name 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-userlock johndoe 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | 16 | for i in ${CLDOPTS} 17 | do 18 | case $i in 19 | -*) ;; 20 | *) let ii++; declare ARG$ii=${i} ;; 21 | esac 22 | done 23 | 24 | CLD_USER=${ARG1} 25 | [ "$CLD_USER" ] || echoexit1 CLD user is not defined 26 | 27 | sed -i 's#^'${CLD_USER}':\$#'${CLD_USER}':!!\$#g' /etc/shadow -------------------------------------------------------------------------------- /bin/cld-userunlock: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Unlock user - Modifying record of user at /etc/shadow - allow to login to the CLD server by SSH and web interface 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 User name 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-userunlock johndoe 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | 16 | for i in ${CLDOPTS} 17 | do 18 | case $i in 19 | -*) ;; 20 | *) let ii++; declare ARG$ii=${i} ;; 21 | esac 22 | done 23 | 24 | CLD_USER=${ARG1} 25 | [ "$CLD_USER" ] || echoexit1 CLD user is not defined 26 | 27 | sed -i 's#^'${CLD_USER}':!!\$#'${CLD_USER}':\$#g' /etc/shadow -------------------------------------------------------------------------------- /bin/cldx: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Direct instance terminal access CLI utility of ClassicDevOps access system 4 | Will choose first one after all filters 5 | EOL 6 | ) 7 | HELP_ARGS=$(cat << 'EOL' 8 | $1 First PATTERN filtering allowed instances 9 | $2 Second PATTERN filtering allowed instances 10 | $3 Third PATTERN filtering allowed instances 11 | --groups=GROUP1,GROUP2 Filtering by instance groups 12 | --debug Verbose output of connection 13 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to 14 | EOL 15 | ) 16 | HELP_EXAMPLES=$(cat << 'EOL' 17 | cldx prod instance_1.2.3.4_22_root 18 | cldx prod instance_1.2.3.4_22_root --groups=gcloud --debug 19 | EOL 20 | ) 21 | HELP_ONLY="CLI WEB" 22 | 23 | source /var/cld/bin/include/cldfuncs 24 | 25 | for i in ${CLDOPTS} 26 | do 27 | case $i in 28 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 29 | -d|-debug|--debug) VERBOSE=" -v" ;; 30 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 31 | -*) ;; 32 | *) let ii++; declare ARG$ii=${i} ;; 33 | esac 34 | done 35 | 36 | echo $1 37 | VM=$(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" "$ARG1" "$ARG2" "$ARG3" "$CLD_ALL_GROUPS_ARG" | head -1) 38 | CLD_LOGS 39 | if [ "$VM" ] 40 | then 41 | INSTANCE_GROUP_FUNCS 42 | echo "You had chosen ${GROUP} $VM" 43 | $CLD_VARS 44 | echo 45 | $CLD_TERMINAL 46 | fi 47 | -------------------------------------------------------------------------------- /bin/cldx-bash-notty: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Direct instance deploy CLI utility of ClassicDevOps access system 4 | Read pipe input and execute on remote CLD instance 5 | Will choose first one after all filters 6 | EOL 7 | ) 8 | HELP_ARGS=$(cat << 'EOL' 9 | $1 First PATTERN filtering allowed instances 10 | $2 Second PATTERN filtering allowed instances 11 | $3 Third PATTERN filtering allowed instances 12 | --groups=GROUP1,GROUP2 Filtering by instance groups 13 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to 14 | --debug Verbose output of connection 15 | EOL 16 | ) 17 | HELP_EXAMPLES=$(cat << 'EOL' 18 | cldx-bash-notty instance_1.2.3.4_22_root << EOCLD 19 | script 20 | commands 21 | EOCLD 22 | EOL 23 | ) 24 | HELP_ONLY="CLI" 25 | 26 | source /var/cld/bin/include/cldfuncs 27 | 28 | for i in ${CLDOPTS} 29 | do 30 | case $i in 31 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 32 | -l|-list|--list) LIST=1 ;; 33 | -d|-debug|--debug) VERBOSE=" -v" ;; 34 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 35 | -*) ;; 36 | *) let ii++; declare ARG$ii=${i} ;; 37 | esac 38 | done 39 | 40 | VM=$(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" "$ARG1" "$ARG2" "$ARG3" "$CLD_ALL_GROUPS_ARG" | head -1) 41 | CLD_LOGS 42 | if [ "$VM" ] 43 | then 44 | INSTANCE_GROUP_FUNCS 45 | $CLD_VARS 46 | TIMEOUT_NOTTY=${TIMEOUT_NOTTY:-600} 47 | $CLD_DEPLOY_NOTTY 48 | fi 49 | -------------------------------------------------------------------------------- /bin/cldx-bash-tty: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Direct instance deploy CLI utility of ClassicDevOps access system 4 | Read pipe input and execute on remote CLD instance 5 | Require "exit" at the end of input to stop execution 6 | Will choose first one after all filters 7 | EOL 8 | ) 9 | HELP_ARGS=$(cat << 'EOL' 10 | $1 First PATTERN filtering allowed instances 11 | $2 Second PATTERN filtering allowed instances 12 | $3 Third PATTERN filtering allowed instances 13 | --groups=GROUP1,GROUP2 Filtering by instance groups 14 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to 15 | --debug Verbose output of connection 16 | EOL 17 | ) 18 | HELP_EXAMPLES=$(cat << 'EOL' 19 | cldx-bash-tty instance_1.2.3.4_22_root << EOCLD 20 | script 21 | commands 22 | exit 23 | EOCLD 24 | EOL 25 | ) 26 | HELP_ONLY="CLI" 27 | 28 | source /var/cld/bin/include/cldfuncs 29 | 30 | for i in ${CLDOPTS} 31 | do 32 | case $i in 33 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 34 | -l|-list|--list) LIST=1 ;; 35 | -d|-debug|--debug) VERBOSE=" -v" ;; 36 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 37 | -*) ;; 38 | *) let ii++; declare ARG$ii=${i} ;; 39 | esac 40 | done 41 | 42 | VM=$(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" "$ARG1" "$ARG2" "$ARG3" "$CLD_ALL_GROUPS_ARG" | head -1) 43 | CLD_LOGS 44 | if [ "$VM" ] 45 | then 46 | INSTANCE_GROUP_FUNCS 47 | $CLD_VARS 48 | TIMEOUT=600 49 | $CLD_DEPLOY 50 | fi 51 | -------------------------------------------------------------------------------- /bin/cldxmount: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Direct mount utility for mount filesystems of instance 4 | Remote filesystem mounting by sshfs in /home/${USER}/mnt/${CLD_INSTANCE} directory 5 | If there are several after filtering - the first one will be selected 6 | EOL 7 | ) 8 | HELP_ARGS=$(cat << 'EOL' 9 | $1 First PATTERN filtering allowed instances 10 | $2 Second PATTERN filtering allowed instances 11 | $3 Third PATTERN filtering allowed instances 12 | --groups=GROUP1,GROUP2 Filtering by instance groups 13 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to 14 | EOL 15 | ) 16 | HELP_EXAMPLES=$(cat << 'EOL' 17 | cldxmount prod 1.2.3.4_instance_22_root 18 | cldxmount prod 1.2.3.4_instance_22_root --groups=gcloud 19 | EOL 20 | ) 21 | HELP_ONLY="CLI WEB" 22 | source /var/cld/bin/include/cldfuncs 23 | 24 | for i in ${CLDOPTS} 25 | do 26 | case $i in 27 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 28 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 29 | -*) ;; 30 | *) let ii++; declare ARG$ii=${i} ;; 31 | esac 32 | done 33 | 34 | for VM in $(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" "$ARG1" "$ARG2" "$ARG3" "$CLD_ALL_GROUPS_ARG" | head -1) 35 | do 36 | CLD_LOGS 37 | if [ "$VM" ] 38 | then 39 | INSTANCE_GROUP_FUNCS 40 | echo "You had chosen ${GROUP} $VM" 41 | $CLD_VARS 42 | echo 43 | $CLD_MOUNT && echo -e "Inctance filesystem mounted to \n$LOCALMOUNTPATH" 44 | fi 45 | break 46 | done -------------------------------------------------------------------------------- /bin/cldxumount: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Direct mount utility for mount filesystems of instance 4 | Remote filesystem mounting by sshfs in /home/${USER}/mnt/${CLD_INSTANCE} directory 5 | If there are several after filtering - the first one will be selected 6 | EOL 7 | ) 8 | HELP_ARGS=$(cat << 'EOL' 9 | $1 First PATTERN filtering allowed instances 10 | $2 Second PATTERN filtering allowed instances 11 | $3 Third PATTERN filtering allowed instances 12 | --groups=GROUP1,GROUP2 Filtering by instance groups 13 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to 14 | EOL 15 | ) 16 | HELP_EXAMPLES=$(cat << 'EOL' 17 | cldxmount prod 1.2.3.4_instance_22_root 18 | cldxmount prod 1.2.3.4_instance_22_root --groups=gcloud 19 | EOL 20 | ) 21 | HELP_ONLY="CLI WEB" 22 | source /var/cld/bin/include/cldfuncs 23 | 24 | for i in ${CLDOPTS} 25 | do 26 | case $i in 27 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 28 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 29 | -*) ;; 30 | *) let ii++; declare ARG$ii=${i} ;; 31 | esac 32 | done 33 | 34 | for VM in $(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" "$ARG1" "$ARG2" "$ARG3" "$CLD_ALL_GROUPS_ARG" | grep "$(df 2>/dev/null | grep /home/${SUDO_USER}/mnt | rev | cut -d / -f 1 | rev)" | head -1) 35 | do 36 | CLD_LOGS 37 | if [ "$VM" ] 38 | then 39 | INSTANCE_GROUP_FUNCS 40 | $CLD_VARS 41 | echo 42 | $CLD_UMOUNT && echo -e "Inctance filesystem unmounted from \n$LOCALMOUNTPATH" 43 | fi 44 | break 45 | done -------------------------------------------------------------------------------- /bot/discord/cld-dcbot.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=ClassicDevOps Discord bot interface service 3 | After=multi-user.target 4 | PartOf=cld.service 5 | 6 | [Service] 7 | WorkingDirectory=/var/cld/bot/discord 8 | Type=simple 9 | ExecStart=/usr/bin/python3 /var/cld/bot/discord/dcbot.py 10 | RemainAfterExit=no 11 | Restart=always 12 | RestartSec=2 13 | StartLimitBurst=999999 14 | StartLimitInterval=0 15 | KillMode=process 16 | 17 | 18 | [Install] 19 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /bot/discord/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /var/cld/bin/include/cldfuncs 3 | 4 | if ! grep -q "^DISCORD=" /var/cld/creds/creds 5 | then 6 | echo "Are you using Discord ?" 7 | select ANSWER in yes no 8 | do 9 | if [ "${ANSWER}" == "yes" ] 10 | then 11 | init-load-constants DISCORD_BOT_TOKEN\|QTqhVEZUmbj6rBAEzoetk5d6GEwZ63qQv2zdmqNjrzmMqk9dj4u2j0MzFw8 || echo skipped 12 | echo DISCORD=1 >> /var/cld/creds/creds 13 | break 14 | elif [ "${ANSWER}" == "no" ] 15 | then 16 | echo DISCORD=0 >> /var/cld/creds/creds 17 | break 18 | fi 19 | done 20 | fi -------------------------------------------------------------------------------- /bot/telegram/cld-tgbot.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=ClassicDevOps Telegram bot interface service 3 | After=multi-user.target 4 | PartOf=cld.service 5 | 6 | [Service] 7 | WorkingDirectory=/var/cld/bot/telegram 8 | Type=simple 9 | ExecStart=/usr/bin/python3 /var/cld/bot/telegram/tgbot.py 10 | RemainAfterExit=no 11 | Restart=always 12 | RestartSec=2 13 | StartLimitBurst=999999 14 | StartLimitInterval=0 15 | KillMode=process 16 | 17 | 18 | [Install] 19 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /bot/telegram/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /var/cld/bin/include/cldfuncs 3 | 4 | if ! grep -q "^TELEGRAM=" /var/cld/creds/creds 5 | then 6 | echo "Are you using Telegram ?" 7 | select ANSWER in yes no 8 | do 9 | if [ "${ANSWER}" == "yes" ] 10 | then 11 | init-load-constants TELEGRAM_BOT_TOKEN\|1234567890:AAEzBFqFii-uirfyG3PnygA0DAvJvRH7UzB || echo skipped 12 | echo TELEGRAM=1 >> /var/cld/creds/creds 13 | break 14 | elif [ "${ANSWER}" == "no" ] 15 | then 16 | echo TELEGRAM=0 >> /var/cld/creds/creds 17 | break 18 | fi 19 | done 20 | fi -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | cld: 4 | build: . 5 | volumes: 6 | - /var/cld:/var/cld 7 | - /var/cld/docker/etc:/etc 8 | - /var/cld/docker/home:/home 9 | - /var/cld/docker/root:/root 10 | environment: 11 | # Example credentials passed via environment variables 12 | - CLD_CFG_CLD_DOMAIN=cld.example.com 13 | # CLD_CFG_* variables will be written to /var/cld/creds/creds_env 14 | ports: 15 | - "22:22" 16 | - "80:80" 17 | - "443:443" 18 | -------------------------------------------------------------------------------- /docker/docker_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Build the CLD image and extract default credentials. 3 | set -e 4 | IMAGE_NAME=cld-image 5 | DATA_DIR=${1:-/var/cld} 6 | 7 | docker build -t $IMAGE_NAME . 8 | mkdir -p "$DATA_DIR" 9 | # Use the container to populate default credentials and home dirs 10 | # into the target directory. 11 | docker run --rm -v "$DATA_DIR":/var/cld $IMAGE_NAME bash -c "/docker/init_creds.sh /var/cld" 12 | 13 | echo "Credentials prepared under $DATA_DIR" 14 | 15 | -------------------------------------------------------------------------------- /docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | mkdir -p /var/cld/creds 4 | 5 | # If an existing creds file is present from a non-containerized setup, convert 6 | # it into creds_static so future runs use symlinks. 7 | if [ -f /var/cld/creds/creds ] && [ ! -L /var/cld/creds/creds ]; then 8 | [ -f /var/cld/creds/creds_static ] || mv /var/cld/creds/creds /var/cld/creds/creds_static 9 | fi 10 | 11 | # If environment variables prefixed with CLD_CFG_ are provided, 12 | # write them into creds_env and use it. Otherwise fall back to creds_static. 13 | if env | grep -q '^CLD_CFG_' ; then 14 | CREDS_ENV=/var/cld/creds/creds_env 15 | : > "$CREDS_ENV" 16 | for VAR in $(env | grep '^CLD_CFG_' | sort); do 17 | KEY=${VAR%%=*} 18 | VALUE=${VAR#*=} 19 | KEY=${KEY#CLD_CFG_} 20 | echo "${KEY}=${VALUE}" >> "$CREDS_ENV" 21 | done 22 | ln -sf creds_env /var/cld/creds/creds 23 | else 24 | # Ensure a static credentials file exists. If a plain creds file exists from 25 | # a previous setup, move it so future runs use the symlink. 26 | if [ -f /var/cld/creds/creds ] && [ ! -L /var/cld/creds/creds ]; then 27 | [ -f /var/cld/creds/creds_static ] || mv /var/cld/creds/creds /var/cld/creds/creds_static 28 | fi 29 | [ -f /var/cld/creds/creds_static ] || touch /var/cld/creds/creds_static 30 | ln -sf creds_static /var/cld/creds/creds 31 | fi 32 | 33 | exec /usr/bin/supervisord -c /etc/supervisord.conf 34 | -------------------------------------------------------------------------------- /docker/init_creds.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copy container credentials and home directories to the provided directory. 3 | # Usage: ./docker/init_creds.sh [TARGET_DIR] 4 | set -e 5 | TARGET=${1:-/var/cld} 6 | 7 | mkdir -p "$TARGET/docker/etc" "$TARGET/docker/home" "$TARGET/docker/root" "$TARGET/creds" 8 | 9 | cp -a /etc/. "$TARGET/docker/etc/" 10 | cp -a /home/. "$TARGET/docker/home/" 2>/dev/null || true 11 | cp -a /root/. "$TARGET/docker/root/" 2>/dev/null || true 12 | 13 | # prepare default credentials file 14 | touch "$TARGET/creds/creds_static" 15 | ln -sf creds_static "$TARGET/creds/creds" 16 | 17 | echo "Credentials prepared under $TARGET/docker" 18 | -------------------------------------------------------------------------------- /docker/nginx/cld.conf: -------------------------------------------------------------------------------- 1 | map $http_upgrade $connection_upgrade { 2 | default upgrade; 3 | '' close; 4 | } 5 | map $http_x_forwarded_proto $real_scheme { 6 | default $http_x_forwarded_proto; 7 | '' $scheme; 8 | } 9 | upstream cldweb { 10 | server 127.0.0.1:8080; 11 | } 12 | upstream cldapi { 13 | server 127.0.0.1:8085; 14 | } 15 | limit_req_zone $binary_remote_addr zone=apiall:10m rate=1r/s; 16 | server { 17 | listen 80; 18 | include sslgen.conf; 19 | access_log /var/log/nginx-main-access.log; 20 | server_name ${CLD_DOMAIN}; 21 | 22 | add_header X-Content-Type-Options nosniff; 23 | 24 | location / { 25 | if ($real_scheme = http) { 26 | return 301 https://$host$request_uri; 27 | } 28 | include accesslist; 29 | deny all; 30 | proxy_pass http://cldweb; 31 | proxy_redirect off; 32 | proxy_buffering off; 33 | proxy_request_buffering off; 34 | proxy_http_version 1.1; 35 | proxy_set_header Host $host; 36 | proxy_set_header Upgrade $http_upgrade; 37 | proxy_set_header Connection $connection_upgrade; 38 | proxy_set_header X-Forwarded-For $remote_addr; 39 | proxy_set_header X-Forwarded-Proto $real_scheme; 40 | } 41 | 42 | location /api { 43 | if ($real_scheme = http) { 44 | return 301 https://$host$request_uri; 45 | } 46 | include accesslist; 47 | deny all; 48 | rewrite ^/api(.*)$ $1 break; 49 | proxy_pass http://cldapi; 50 | proxy_redirect off; 51 | proxy_buffering off; 52 | proxy_request_buffering off; 53 | proxy_set_header Host $host; 54 | proxy_set_header X-Forwarded-For $remote_addr; 55 | proxy_set_header X-Forwarded-Proto $real_scheme; 56 | } 57 | 58 | location /api/all { 59 | include /etc/nginx/deny.conf; 60 | if ($real_scheme = http) { 61 | return 301 https://$host$request_uri; 62 | } 63 | add_header Access-Control-Allow-Origin *; 64 | limit_req zone=apiall burst=5 nodelay; 65 | rewrite ^/api(.*)$ $1 break; 66 | proxy_pass http://cldapi; 67 | proxy_redirect off; 68 | proxy_buffering off; 69 | proxy_request_buffering off; 70 | proxy_set_header Host $host; 71 | proxy_set_header X-Forwarded-For $remote_addr; 72 | proxy_set_header X-Forwarded-Proto $real_scheme; 73 | } 74 | 75 | location /documentation { 76 | if ($real_scheme = http) { 77 | return 301 https://$host$request_uri; 78 | } 79 | limit_req zone=apiall burst=5 nodelay; 80 | alias /var/www/cld/doc/; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /docker/nginx/sslgen.conf: -------------------------------------------------------------------------------- 1 | listen *:443 ssl http2; 2 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 3 | ssl_certificate /etc/letsencrypt/live/$ssl_server_name/fullchain.pem; 4 | ssl_certificate_key /etc/letsencrypt/live/$ssl_server_name/privkey.pem; 5 | location ^~ /.well-known/acme-challenge/ { 6 | default_type "text/plain"; 7 | alias /usr/share/nginx/html/.well-known/acme-challenge/; 8 | } 9 | error_log /var/log/nginx-ssl-error.log; 10 | -------------------------------------------------------------------------------- /docker/scripts/lets_auto_gen: -------------------------------------------------------------------------------- 1 | MAILTO="" 2 | * * * * * root /root/sbin/lets_auto_sign 3 | 0 14 * * 1 root /root/sbin/lets_renew 4 | -------------------------------------------------------------------------------- /docker/scripts/lets_auto_sign: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if ps axfu | grep -v grep | grep -q "certonly"; then 3 | echo There is already exist running letsencrypt instance 4 | exit 1 5 | else 6 | for DOMAIN in $(grep 'cannot load certificate' /var/log/nginx-ssl-error.log | cut -d '"' -f 2 | cut -d / -f 5 | egrep "^[0-9a-z-]+\.([0-9a-z-]+\.)?[a-z]+$" | sort -u) 7 | do 8 | letsencrypt certonly -a webroot -n -m certbot@cldcloud.com --agree-tos --webroot-path=/usr/share/nginx/html -d ${DOMAIN} ; chmod 755 /etc/letsencrypt /etc/letsencrypt/{live,archive} ; chmod -R 755 /etc/letsencrypt/live/$DOMAIN ; chmod -R 755 /etc/letsencrypt/archive/$DOMAIN 9 | done 10 | truncate -s 0 /var/log/nginx-ssl-error.log 11 | fi 12 | -------------------------------------------------------------------------------- /docker/scripts/lets_clean_subdomains: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for DOMAIN in $(ls /etc/letsencrypt/live/ | egrep "[a-z0-9-]+\.[a-z0-9-]+\.[a-z0-9-]+") 3 | do 4 | echo "${DOMAIN}" 5 | find /etc/letsencrypt/ -name "${DOMAIN}*" | egrep -o "/etc/letsencrypt/.*" | xargs -d "\n" -I {} rm -rf "{}" 6 | done 7 | -------------------------------------------------------------------------------- /docker/scripts/lets_renew: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | check_ssl() 3 | { 4 | expr \( `echo|timeout 5s openssl s_client -connect ${DOMAIN}:443 -servername ${DOMAIN} 2>/dev/null| timeout 5s openssl x509 -noout -enddate|cut -d'=' -f2|xargs -I ^ date +%s -d "^"` - `date +%s` \) / 24 / 3600 5 | } 6 | 7 | truncate -s 0 /tmp/ssl_domains 8 | for DOMAIN in $(ls /etc/letsencrypt/live/ | grep -v README) 9 | do 10 | echo Check $DOMAIN 11 | unset DAYS_LEFT 12 | DAYS_LEFT=$(check_ssl 2>/dev/null) 13 | [ "$DAYS_LEFT" ] || { echo Certificate not defined for $DOMAIN - skip ; continue ; } 14 | echo ${DAYS_LEFT}_$DOMAIN >> /tmp/ssl_domains 15 | done 16 | 17 | cat /tmp/ssl_domains 18 | 19 | for EXDOMAIN in $(cat /tmp/ssl_domains | uniq) 20 | do 21 | EXDAYS=$(echo $EXDOMAIN | cut -d _ -f 1) 22 | DOMAIN=$(echo $EXDOMAIN | cut -d _ -f 2) 23 | if [ "$EXDAYS" -lt "30" ] 24 | then 25 | letsencrypt certonly -a webroot -n -m certbot@cldcloud.com --agree-tos --webroot-path=/usr/share/nginx/html -d ${DOMAIN} ; chmod -R 755 /etc/letsencrypt 26 | fi 27 | done 28 | -------------------------------------------------------------------------------- /helpcopyright: -------------------------------------------------------------------------------- 1 | © classicdevops.com 2 | Released under the GNU General Public License v2.0 3 | -------------------------------------------------------------------------------- /modules/access/README.md: -------------------------------------------------------------------------------- 1 | Module for `protect network ports` of servers, with the ability to `access only by allowed lists` of ip addresses, as well as `blocking all connections` to any of the servers using `prohibited lists` of ip addresses 2 | 3 | The module is a centralized system for managing access lists to instances managed by CLD. The main recommended module is to provide controlled and secure user access to instances. In addition, the module implements the functionality of managing secure access between instances to allow the required services and services. This module has a fairly wide range of applications: 4 | 1. Allows you to completely restrict access to your instances, in parallel forming and updating the list of allowed IP addresses for connection. 5 | 2. Implements functionality that allows you to delimit access to a list or even a range of ports. 6 | 3. Has the ability to customize the rules for accessing instances under CLD control and allows you to define a list of protected ports for connection to each of the instances. 7 | 8 | The Access-module also includes the following functionality: 9 | - A utility that allows you to selectively add users' IP addresses to the list of allowed connections using a special one-time token. This allows not only to increase the level of security, but also ensures that links and tokens cannot be made publicly available. 10 | - If the user who is granted access by IP address does not have a static IP address and is faced with the need to constantly update the IP address - the functionality of the Access module includes the ability to generate a unique access key via VPN. Key generation occurs in a fully automatic mode and is transmitted to the user who requested the VPN key. Further, within the framework of a secure VPN connection - the user does not need to update his IP address, everything happens automatically. 11 | - As part of security work, the Access module has a convenient, simple and straightforward functionality to block unwanted IP addresses. In the event of an attack on any of the CLD instances, you can completely block the connection from a specific IP address and completely exclude the unwanted IP address in a short time. Also, at any time you can display a list of blocked IP addresses that are in the banlist and make a further decision depending on your goals. You can also remove an IP address from a banlist centrally using the built-in utility. 12 | 13 | Below is a list of the Access-module initial variables. 14 | 15 | | Variable | Description | 16 | | ------ | ----------- | 17 | | CLD_IP | The IP address of the instance where CLD is installed. | 18 | | MIKROTIK | if the architecture of the system implies the use of microtic - the variable that determines its use. | 19 | | MIKROTIK_USER | username mikrotik. | 20 | | MIKROTIK_PASSWORD | password of user mikrotik. | 21 | | MIKROTIK_HOST | The IP address at which mikrotik is located. | 22 | -------------------------------------------------------------------------------- /modules/access/api.py: -------------------------------------------------------------------------------- 1 | @app.route('/all/myipinit') 2 | def myip(): 3 | if 'token' in request.args: 4 | if re.findall(r'(AppleWebKit|Chrome|Safari|KHTML|Gecko)', request.headers.get('User-Agent')): 5 | token = re.fullmatch(r'[A-Za-z0-9]+', request.args['token']).string 6 | output = bash('FROM=API /var/cld/modules/access/bin/cld-activateiptoken '+vld(remoteaddr())+' '+token) 7 | resp = Response(output, status=200, mimetype='text/plain') 8 | return resp 9 | else: 10 | return Response('403', status=403, mimetype='text/plain') 11 | else: 12 | return Response('403', status=403, mimetype='text/plain') 13 | 14 | @app.route('/myvpninit') 15 | def myvpninit(): 16 | if 'token' in request.args: 17 | if re.findall(r'(AppleWebKit|Chrome|Safari|KHTML|Gecko)', request.headers.get('User-Agent')): 18 | token = re.fullmatch(r'[A-Za-z0-9]+', request.args['token']).string 19 | text = 'CLD VPN key generating...' 20 | successtext = 'CLD VPN key generated successfully' 21 | failtext = 'Link expired' 22 | link = f'/api/myvpnget?token={token}' 23 | return render_template('modules/access/preloader.html', text=text, successtext=successtext, failtext=failtext, link=link) 24 | else: 25 | return Response('403', status=403, mimetype='text/plain') 26 | else: 27 | return Response('403', status=403, mimetype='text/plain') 28 | 29 | @app.route('/myvpnget') 30 | def myvpnget(): 31 | if 'token' in request.args: 32 | if re.findall(r'(AppleWebKit|Chrome|Safari|KHTML|Gecko)', request.headers.get('User-Agent')): 33 | token = re.fullmatch(r'[A-Za-z0-9]+', request.args['token']).string 34 | filepath = bash('FROM=API /var/cld/modules/access/bin/cld-activatevpntoken '+token) 35 | if os.path.exists(filepath) != True: 36 | return Response('404', status=404, mimetype='text/plain') 37 | filename = os.path.basename(filepath) 38 | resp = Response(stream_file(filepath), status=200, mimetype='application/octet-stream') 39 | resp.headers['Content-Disposition'] = "attachment; filename="+filename 40 | return resp 41 | else: 42 | return Response('403', status=403, mimetype='text/plain') 43 | else: 44 | return Response('403', status=403, mimetype='text/plain') -------------------------------------------------------------------------------- /modules/access/api/preloader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 79 | 80 |
{{ text }}
81 | 82 | 108 | -------------------------------------------------------------------------------- /modules/access/auditor: -------------------------------------------------------------------------------- 1 | if ! [ "${ACCESS_INIT_RUN}" ]; then 2 | source /var/cld/modules/access/bin/include/accessfuncs 3 | [ -f "/var/cld/tmp/auditor/prev_passwd_hash" ] || touch /var/cld/tmp/auditor/prev_passwd_hash 4 | ACCESS_INIT_RUN=1 5 | fi 6 | 7 | ### Check permission matrix changes 8 | PASSWD_CURRENT_HASH=$(md5sum /var/cld/creds/passwd | cut -d ' ' -f 1) 9 | PASSWD_PREVIOUS_HASH=$(cat /var/cld/tmp/auditor/prev_passwd_hash) 10 | echo "${PASSWD_CURRENT_HASH}" > /var/cld/tmp/auditor/prev_passwd_hash 11 | 12 | ACCESS_CURRENT_HASH=$({ echo ${PASSWD_CURRENT_HASH} ; du -b -d 0 /var/cld/access/ /var/cld/creds/passwd /var/cld/modules/access/data/{instances,groups,myips,enabledips,banips ; } | md5sum | awk '{print $1}') 13 | ACCESS_PREVIOUS_HASH=$(cat /var/cld/tmp/auditor/prev_access_hash) 14 | echo "${ACCESS_CURRENT_HASH}" > /var/cld/tmp/auditor/prev_access_hash 15 | CURRENT_ACCESS_MAP_DIR=$(head -1 /var/cld/tmp/auditor/current_access_map) 16 | 17 | if [ "$ACCESS_CURRENT_HASH" != "$ACCESS_PREVIOUS_HASH" -o "$({ du -bd 0 ${CURRENT_ACCESS_MAP_DIR} 2>/dev/null || echo 0 ; } | awk '{print $1}')" -lt "12300" ] 18 | then 19 | bash -lc "/var/cld/bin/cld-initpasswd" 20 | generate_access_map 21 | echo "${CLD_FILTER_DIR}" > /var/cld/tmp/auditor/current_access_map_tmp 22 | unset mv &>/dev/null 23 | mv -f /var/cld/tmp/auditor/current_access_map_tmp /var/cld/tmp/auditor/current_access_map 24 | ls -h /var/cld/tmp/access_instances_* -d -h -t | tail -n +10 | xargs -I ^ rm -rf ^ 25 | find /var/cld/tmp/access_instances_* -type d -empty -exec rmdir {} \; 26 | fi -------------------------------------------------------------------------------- /modules/access/bin/cld-activateiptoken: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Add or update private IP of user to access list 4 | Tool oriented to BOT and API interfaces 5 | Arguments filling automatically by passing link after using /myip command at Messenger chat with bot 6 | By this tool IP address of user detecting automatically from incoming get request 7 | To add an IP address to access list via CLI - use cld-enableip 8 | EOL 9 | ) 10 | HELP_ARGS=$(cat << 'EOL' 11 | $1 IP address 12 | $2 Temporary token created by cld-myipbot tool used via /myip command at Messenger chat with bot 13 | EOL 14 | ) 15 | HELP_ONLY="API" 16 | source /var/cld/bin/include/cldfuncs 17 | source /var/cld/modules/access/bin/include/accessfuncs 18 | 19 | [ "${FROM}" != "API" ] && cldhelp 20 | 21 | for i in ${CLDOPTS} 22 | do 23 | case $i in 24 | -*) ;; 25 | *) let ii++; declare ARG$ii=${i} ;; 26 | esac 27 | done 28 | 29 | [ -d /var/cld/modules/access/data ] || mkdir -p /var/cld/modules/access/data/ &>/dev/null 30 | 31 | IP=${ARG1} 32 | TOKEN_SET=$(grep "^${ARG2}," /var/cld/modules/access/data/myip_tokens) 33 | [ "$TOKEN_SET" ] || { echo 403 ; exit 1 ; } 34 | 35 | init-load-constants TELEGRAM_BOT_TOKEN\|1234567890:AAEzBFqFii-uirfyG3PnygA0DAvJvRH7UzB 36 | 37 | TOKEN=$(cut -d ',' -f 1 <<< ${TOKEN_SET}) 38 | USERID=$(cut -d ',' -f 2 <<< ${TOKEN_SET}) 39 | USERNAME=$(cut -d ',' -f 3 <<< ${TOKEN_SET}) 40 | 41 | CHAT_SET=$(grep "^${ARG2}_" /var/cld/modules/access/data/myip_token_chats) 42 | MESSAGE_ID=$(cut -d _ -f 2 <<< ${CHAT_SET}) 43 | TG_GROUP=$(cut -d _ -f 3 <<< ${CHAT_SET}) 44 | 45 | if grep -q "${USERID}" /var/cld/modules/access/data/myips; then 46 | sed -i "s#.*${USERID}.*#${IP}_${USERID}_${USERNAME}_`TZ=Europe/Moscow date +%F-%H-%M`#g" /var/cld/modules/access/data/myips 47 | echo "private IP ${IP} successfully updated for user ${USERNAME}" 48 | else 49 | echo "${IP}_${USERID}_${USERNAME}_`TZ=Europe/Moscow date +%F-%H-%M`" >> /var/cld/modules/access/data/myips 50 | echo "private IP ${IP} successfully added to access list for user ${USERNAME}" 51 | fi 52 | 53 | sed -i "/${TOKEN}/d" /var/cld/modules/access/data/myip_tokens /var/cld/modules/access/data/myip_token_chats &>/dev/null 54 | 55 | updateaccesslists 56 | 57 | [ "${TG_GROUP}" != "" -a "${MESSAGE_ID}" != "" ] && curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/editMessageText?chat_id=${TG_GROUP}&message_id=${MESSAGE_ID}&parse_mode=markdown&text=\`ip added - token cleared\`" &>/dev/null -------------------------------------------------------------------------------- /modules/access/bin/cld-activatevpntoken: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Get personal user openvpn key 4 | Tool oriented to BOT and API interfaces 5 | Arguments filling automatically by using /myvpn command at Messenger chat with bot 6 | EOL 7 | ) 8 | HELP_ARGS=$(cat << 'EOL' 9 | $1 Temporary token created by cld-myvpnbot tool used via /myvpn command at Messenger chat with bot 10 | EOL 11 | ) 12 | HELP_ONLY="API" 13 | source /var/cld/bin/include/cldfuncs 14 | source /var/cld/modules/access/bin/include/ovpnfuncs 15 | 16 | [ "${FROM}" != "API" ] && cldhelp 17 | 18 | for i in ${CLDOPTS} 19 | do 20 | case $i in 21 | -*) ;; 22 | *) let ii++; declare ARG$ii=${i} ;; 23 | esac 24 | done 25 | 26 | [ -d /var/cld/modules/access/data ] || mkdir -p /var/cld/modules/access/data/ &>/dev/null 27 | 28 | TOKEN_SET=$(grep "^${ARG1}," /var/cld/modules/access/data/myvpn_tokens) 29 | [ "$TOKEN_SET" ] || { echo 403 ; exit 1 ; } 30 | 31 | init-load-constants CLD_DOMAIN\|cld.yourdomain.com TELEGRAM_BOT_TOKEN\|1234567890:AAEzBFqFii-uirfyG3PnygA0DAvJvRH7UzB 32 | init-load-constant --constant=NETWORK_POLICY --example=general --regex="(general|private|paranoid)" --default=general 33 | 34 | TOKEN=$(cut -d ',' -f 1 <<< ${TOKEN_SET}) 35 | USERID=$(cut -d ',' -f 2 <<< ${TOKEN_SET}) 36 | USERNAME=$(cut -d ',' -f 3 <<< ${TOKEN_SET}) 37 | VPN_MODE=$(cut -d ',' -f 4 <<< ${TOKEN_SET}) 38 | 39 | CHAT_SET=$(grep "^${ARG1}_" /var/cld/modules/access/data/myvpn_token_chats) 40 | MESSAGE_ID=$(cut -d _ -f 2 <<< ${CHAT_SET}) 41 | TG_GROUP=$(cut -d _ -f 3 <<< ${CHAT_SET}) 42 | 43 | sed -i "/${TOKEN}/d" /var/cld/modules/access/data/myvpn_tokens /var/cld/modules/access/data/myvpn_token_chats &>/dev/null 44 | 45 | CLD_USER_VPN_FILE=$(ls /var/cld/modules/access/data/ovpn/${CLD_DOMAIN}_${USERNAME}-${USERID}.ovpn) 46 | 47 | if [ -f "${CLD_USER_VPN_FILE}" ] 48 | then 49 | echo ${CLD_USER_VPN_FILE} 50 | else 51 | ovpngenerate --id=${USERNAME}-${USERID} --mode=${VPN_MODE} 52 | fi 53 | 54 | { grep -s "^server " /etc/openvpn/server/server_*.conf | awk '{print $2"/28"}' ; cat /var/cld/modules/access/data/instances/cld/local_nets ; } | sort -u > /var/cld/modules/access/data/instances/cld/local_nets.tmp ; mv -f /var/cld/modules/access/data/instances/cld/local_nets.tmp /var/cld/modules/access/data/instances/cld/local_nets 55 | 56 | [ "${TG_GROUP}" != "" -a "${MESSAGE_ID}" != "" ] && curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/editMessageText?chat_id=${TG_GROUP}&message_id=${MESSAGE_ID}&parse_mode=markdown&text=\`OpenVPN key sent - token cleared\`" &>/dev/null -------------------------------------------------------------------------------- /modules/access/bin/cld-banip: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Utility to add IP address to the ban list. 4 | Access for the specified ip address is blocked on all instances under CLD control, for all ports. 5 | It is possible to exclude an ip address from the banlist using the unbanip command. 6 | To check the list of blocked ip addresses, you can use the banlist command. 7 | EOL 8 | ) 9 | HELP_ARGS=$(cat << 'EOL' 10 | $1 IP address 11 | $2 Comment 12 | EOL 13 | ) 14 | HELP_EXAMPLES=$(cat << 'EOL' 15 | cld-banip 1.2.3.4 somereason 16 | EOL 17 | ) 18 | source /var/cld/bin/include/cldfuncs 19 | source /var/cld/modules/access/bin/include/accessfuncs 20 | 21 | for i in ${CLDOPTS} 22 | do 23 | case $i in 24 | -*) ;; 25 | *) let ii++; declare ARG$ii=${i} ;; 26 | esac 27 | done 28 | 29 | mkdir -p /var/cld/modules/access/data/ &>/dev/null 30 | 31 | if ! echo ${ARG1} | egrep -q "^(${IPV4REGEX}|${IPV6REGEX})$"; then 32 | echo "ip address is incorrect please fix it and try again" 33 | exit 1 34 | else 35 | if grep -q "${ARG1}" /var/cld/modules/access/data/banips; then 36 | echo "ip ${ARG1} already is in ban list" 37 | else 38 | echo "${ARG1}_${SUDO_USER}@${ARG2}_`TZ=Europe/Moscow date +%F-%H-%M`" >> /var/cld/modules/access/data/banips && echo "ip ${ARG1} successfully added to ban list with comment ${ARG2}" 39 | fi 40 | fi 41 | 42 | BAN_IP="${ARG1}" 43 | COMMENT="${ARG2}" 44 | source /var/cld/modules/dns/bin/include/dnsfuncs 45 | for CFAPI in $(cat /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 46 | do 47 | cf-dns-api-creds 48 | cf-firewall-rules-ip-ban-add ${BAN_IP} ${SUDO_USER}@${COMMENT}_$(TZ=Europe/Moscow date +%F-%H-%M) | grep -q '"success": true' && echo "ip ${BAN_IP} successfully banned by CloudFlare for account ${CFACC}" 49 | done 50 | -------------------------------------------------------------------------------- /modules/access/bin/cld-banlist: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Displays a banlist of blocked IP addresses with comments at the time of blocking. 4 | For each blocked ip address, information about the date and time of blocking is displayed automatically. 5 | EOL 6 | ) 7 | HELP_EXAMPLES=$(cat << 'EOL' 8 | cld-banlist 9 | EOL 10 | ) 11 | source /var/cld/bin/include/cldfuncs 12 | cat /var/cld/modules/access/data/banips | tr '_' ' ' #| awk -v f="$F" -v b="$B" '{print f$0f}' 13 | -------------------------------------------------------------------------------- /modules/access/bin/cld-enableip: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Utility with which you can add the specified IP address to the list of allowed for access. 4 | Adding an IP address allows connection from it to all instances running CLD. 5 | The date and time of adding an IP address is recorded automatically. 6 | EOL 7 | ) 8 | HELP_ARGS=$(cat << 'EOL' 9 | $1 IP address 10 | $2 Comment 11 | EOL 12 | ) 13 | HELP_EXAMPLES=$(cat << 'EOL' 14 | cld-enableip 1.2.3.4 somereason 15 | EOL 16 | ) 17 | source /var/cld/bin/include/cldfuncs 18 | source /var/cld/modules/access/bin/include/accessfuncs 19 | 20 | for i in ${CLDOPTS} 21 | do 22 | case $i in 23 | -*) ;; 24 | *) let ii++; declare ARG$ii=${i} ;; 25 | esac 26 | done 27 | 28 | [ "$ARG2" ] || { echo comment is not defined - exit ; exit 1 ; } 29 | 30 | mkdir -p /var/cld/modules/access/data/ &>/dev/null 31 | if ! echo ${ARG1} | egrep -q "^(${IPV4REGEX}|${IPV6REGEX})$"; then 32 | echo "ip address is incorrect please fix it and try again" 33 | exit 1 34 | else 35 | if grep -q "${ARG1}_${SUDO_USER}" /var/cld/modules/access/data/enabledips; then 36 | echo "ip ${ARG1} already enabled in access list" 37 | else 38 | echo "${ARG1}_${SUDO_USER}@${ARG2}_`TZ=Europe/Moscow date +%F-%H-%M`" >> /var/cld/modules/access/data/enabledips && echo "ip ${ARG1} successfully added to access list with comment ${ARG2}" 39 | fi 40 | fi 41 | 42 | updateaccesslists 43 | -------------------------------------------------------------------------------- /modules/access/bin/cld-myipbot: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Add or update private IP of user to access list 4 | Tool oriented to BOT and API interfaces 5 | Arguments filling automatically by using /myip command at Messenger chat with bot 6 | If IP address is not detected - return api link with temporary token to add IP auto detected just by click 7 | To add an IP address to access list via CLI - use cld-enableip 8 | EOL 9 | ) 10 | HELP_ARGS=$(cat << 'EOL' 11 | $1 Messenger user id 12 | $2 Messenger user name 13 | $3 IP address 14 | EOL 15 | ) 16 | HELP_EXAMPLES=$(cat << 'EOL' 17 | cld-myip #BOT 18 | cld-myip 1.2.3.4 #BOT 19 | EOL 20 | ) 21 | HELP_ONLY="BOT" 22 | source /var/cld/bin/include/cldfuncs 23 | source /var/cld/modules/access/bin/include/accessfuncs 24 | 25 | [ "${FROM}" != "BOT" ] && cldhelp 26 | 27 | for i in ${CLDOPTS} 28 | do 29 | case $i in 30 | -*) ;; 31 | *) let ii++; declare ARG$ii=${i} ;; 32 | esac 33 | done 34 | 35 | init-load-constants TELEGRAM_BOT_TOKEN\|1234567890:AAEzBFqFii-uirfyG3PnygA0DAvJvRH7UzB CLD_DOMAIN\|cldapi.yourdomain.com 36 | if ! echo ${ARG3} | egrep -q "^(${IPV4REGEX}|${IPV6REGEX})$"; then 37 | export TOKEN="$(passwordgen 35)" 38 | echo "${TOKEN},${ARG1},${SUDO_USER}@${ARG2},`TZ=Europe/Moscow date +%F-%H-%M`" >> /var/cld/modules/access/data/myip_tokens 39 | echo "To add your IP address to the access list, please CLICK link below: 40 | https://${CLD_DOMAIN}/api/all/myipinit?token=${TOKEN}" 41 | exit 0 42 | else 43 | if grep -q ${ARG1} /var/cld/modules/access/data/myips; then 44 | sed -i "s#.*${ARG1}.*#${ARG3}_${ARG1}_${SUDO_USER}@${ARG2}_`TZ=Europe/Moscow date +%F-%H-%M`#g" /var/cld/modules/access/data/myips 45 | echo "private IP ${ARG3} successfully updated for user ${SUDO_USER}@${ARG2}" 46 | else 47 | echo "${ARG3}_${ARG1}_${SUDO_USER}@${ARG2}_`date +%F-%H-%M`" >> /var/cld/modules/access/data/myips 48 | echo "private IP ${ARG3} successfully added to access list for user ${SUDO_USER}@${ARG2}" 49 | fi 50 | updateaccesslists 51 | fi 52 | -------------------------------------------------------------------------------- /modules/access/bin/cld-myvpnbot: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Get personal user openvpn key 4 | Tool oriented to BOT and API interfaces 5 | Arguments filling automatically by using /myvpn command at Messenger chat with bot 6 | EOL 7 | ) 8 | HELP_ARGS=$(cat << 'EOL' 9 | $1 Messenger user id 10 | $2 Messenger user name 11 | --regen Regeneration OpenVPN key - delete existed 12 | --noinet Switch VPN to AUTH mode without push gateway and no passing traffic through CLD server - forced value for non "general" network policy 13 | EOL 14 | ) 15 | HELP_EXAMPLES=$(cat << 'EOL' 16 | cld-myvpn #BOT 17 | cld-myvpn -regen #BOT 18 | cld-myvpn -regen -noinet #BOT 19 | EOL 20 | ) 21 | HELP_ONLY="BOT" 22 | source /var/cld/bin/include/cldfuncs 23 | [ "${FROM}" != "BOT" ] && cldhelp 24 | init-load-constants TELEGRAM_BOT_TOKEN\|1234567890:AAEzBFqFii-uirfyG3PnygA0DAvJvRH7UzB CLD_DOMAIN\|cldapi.yourdomain.com 25 | 26 | for i in ${CLDOPTS} 27 | do 28 | case $i in 29 | -r|-regen|--regen) VPN_REGEN=1 ;; 30 | -n|-noinet|--noinet) VPN_MODE="AUTH" ;; 31 | -*) ;; 32 | *) let ii++; declare ARG$ii=${i} ;; 33 | esac 34 | done 35 | 36 | VPN_MODE=${VPN_MODE:-GATEWAY} 37 | 38 | if [ "$VPN_REGEN" = "1" ] 39 | then 40 | 41 | VPN_ID=${SUDO_USER}@${ARG2}-${ARG1} 42 | if [ "$VPN_ID" ] 43 | then 44 | rm -f /etc/openvpn/*${VPN_ID}* 45 | systemctl stop openvpn@server_${VPN_ID}.service 46 | systemctl disable openvpn@server_${VPN_ID}.service 47 | rm -f /var/cld/modules/access/data/ovpn/*${VPN_ID}*.ovpn 48 | fi 49 | 50 | fi 51 | 52 | [ -d "/var/cld/modules/access/data/ovpn" ] || mkdir -p /var/cld/modules/access/data/ovpn 53 | 54 | export TOKEN="$(passwordgen 35)" ; echo "${TOKEN},${ARG1},${SUDO_USER}@${ARG2},${VPN_MODE},`date +%F-%H-%M`" >> /var/cld/modules/access/data/myvpn_tokens ; echo "First request for generating OpenVPN key can take up to 3 minutes - CLICK download link: 55 | https://${CLD_DOMAIN}/api/myvpninit?token=${TOKEN}" -------------------------------------------------------------------------------- /modules/access/bin/cld-unbanip: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Utility to remove IP address from ban list 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 IP address 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-unbanip 1.2.3.4 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | source /var/cld/modules/access/bin/include/accessfuncs 16 | 17 | for i in ${CLDOPTS} 18 | do 19 | case $i in 20 | -*) ;; 21 | *) let ii++; declare ARG$ii=${i} ;; 22 | esac 23 | done 24 | 25 | mkdir -p /var/cld/modules/access/data/ &>/dev/null 26 | if ! echo ${ARG1} | egrep -q "^(${IPV4REGEX}|${IPV6REGEX})$"; then 27 | echo "ip address is incorrect please fix it and try again" 28 | exit 1 29 | else 30 | if grep -q "${ARG1}" /var/cld/modules/access/data/banips; then 31 | sed -i '/'${ARG1}'/d' /var/cld/modules/access/data/banips && echo "ip ${ARG1} successfully deleted from ban list" 32 | else 33 | echo "ip ${ARG1} not in ban list" 34 | fi 35 | fi 36 | 37 | UNBAN_IP=${ARG1} 38 | egrep -q "^${IPV6REGEX}$" <<< ${UNBAN_IP} && UNBAN_IP=$(sipcalc ${UNBAN_IP} | grep "^Expanded" | cut -d '-' -f 2 | tr -d ' ') 39 | 40 | source /var/cld/modules/dns/bin/include/dnsfuncs 41 | for CFAPI in $(cat /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 42 | do 43 | cf-dns-api-creds 44 | RULE_ID=$(cf-firewall-rules-ip-ban-get | jq ".result[] | select(.mode == \"block\" and .configuration.value == \"${UNBAN_IP}\")" | jq -r .id) 45 | cf-firewall-rules-ip-ban-del ${RULE_ID} | grep -q '"success": true' && echo "ip ${ARG1} successfully unbanned by CloudFlare for account ${CFACC}" 46 | done -------------------------------------------------------------------------------- /modules/access/dcbot.py: -------------------------------------------------------------------------------- 1 | @bot.command(name='myip') 2 | async def cmd_myip(message, *args): 3 | checkresult = checkresult = checkperms(cldmodule, "cld-myipbot", message.author.id, message.channel.id) 4 | if checkresult[0] != "granted": return await message.reply("user id is "+vld(message.author.id)+", access denied for "+vld(message.author).replace('#','-')) 5 | cmd_args='' 6 | try: 7 | for arg in args: cmd_args=cmd_args+" "+re.match('^[A-z0-9.,@=/:_-]+$', arg).string 8 | except: pass 9 | user = bash('grep "[:,]'+checkresult[1]+'[:,]" /var/cld/creds/passwd | cut -d : -f 1 | head -1') 10 | if re.findall(r'[\d]+\.[\d]+\.[\d]+\.[\d]+', cmd_args): 11 | myip = re.search('([\d]+\.[\d]+\.[\d]+\.[\d]+)', cmd_args).group(1) 12 | cmdoutput = bash('sudo -u '+user+' sudo FROM=BOT /var/cld/modules/access/bin/cld-myipbot '+vld(message.author.id)+' '+vld(message.author).replace('#','-')+' '+vld(myip)) 13 | await message.send('`'+cmdoutput+'`') 14 | else: 15 | myip = 'TOKEN' 16 | cmdoutput = bash('sudo -u '+user+' sudo FROM=BOT /var/cld/modules/access/bin/cld-myipbot '+vld(message.author.id)+' '+vld(message.author).replace('#','-')+' '+vld(myip)) 17 | await message.send(cmdoutput) 18 | 19 | @bot.command(name='myvpn') 20 | async def cmd_myvpn(message, *args): 21 | checkresult = checkresult = checkperms(cldmodule, "cld-myvpnbot", message.author.id, message.channel.id) 22 | if checkresult[0] != "granted": return await message.reply("user id is "+vld(message.author.id)+", access denied for "+vld(message.author).replace('#','-')) 23 | cmd_args='' 24 | try: 25 | for arg in args: cmd_args=cmd_args+" "+re.match('^[A-z0-9.,@=/:_-]+$', arg).string 26 | except: pass 27 | user = bash('grep "[:,]'+checkresult[1]+'[:,]" /var/cld/creds/passwd | cut -d : -f 1 | head -1') 28 | cmdoutput = bash('sudo -u '+user+' sudo FROM=BOT /var/cld/modules/access/bin/cld-myvpnbot '+vld(message.author.id)+' '+vld(message.author).replace('#','')+' '+cmd_args) 29 | await message.send(cmdoutput) 30 | -------------------------------------------------------------------------------- /modules/access/examples/banips: -------------------------------------------------------------------------------- 1 | 1.2.3.4 2 | -------------------------------------------------------------------------------- /modules/access/examples/custom_ports: -------------------------------------------------------------------------------- 1 | # Set custom CIDR of networks to generate rules for them on targeted ports "-" is a delimeter between pairs of cidrs/ports 2 | CIDRS=1.1.1.1/32,1.0.0.1/32 3 | PORTS=22,33,44:45 4 | - 5 | CIDRS=8.8.8.8/32,8.8.4.4/32 6 | PORTS=21,32,42:43 -------------------------------------------------------------------------------- /modules/access/examples/custom_ports6: -------------------------------------------------------------------------------- 1 | # Set custom CIDR of networks to generate rules for them on targeted ports "-" is a delimeter between pairs of cidrs/ports 2 | CIDRS=2a01:4f8:c0c:ed56::1/128,2a01:4f8:c0c:ed56::2/128 3 | PORTS=22,33,44:45 4 | - 5 | CIDRS=2a01:4f8:c0c:ed56::3/128,fdfb:bb7c:5000:553a::/128 6 | PORTS=21,32,42:43 -------------------------------------------------------------------------------- /modules/access/examples/custom_rules: -------------------------------------------------------------------------------- 1 | #Custom iptables rules which will be inserted after CLD generated rules list - should contain iptables comment "-m comment --comment cldcustom" 2 | -A INPUT -m comment --comment cldcustom -j ACCEPT -------------------------------------------------------------------------------- /modules/access/examples/custom_rules6: -------------------------------------------------------------------------------- 1 | #Custom iptables rules which will be inserted after CLD generated rules list - should contain iptables comment "-m comment --comment cldcustom" 2 | -A INPUT -m comment --comment cldcustom -j ACCEPT -------------------------------------------------------------------------------- /modules/access/examples/local_nets: -------------------------------------------------------------------------------- 1 | 172.16.0.0/24 -------------------------------------------------------------------------------- /modules/access/examples/local_nets6: -------------------------------------------------------------------------------- 1 | fc00::/120 -------------------------------------------------------------------------------- /modules/access/examples/protected_ports: -------------------------------------------------------------------------------- 1 | 21 2 | 22 3 | 3306 4 | 5432 5 | 6379 6 | 8006 7 | 8123 8 | 9000 9 | 11211 10 | 27017 11 | -------------------------------------------------------------------------------- /modules/access/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /var/cld/bin/include/cldfuncs 3 | 4 | init-load-constant --constant=CLD_IP --example=1.2.3.4 --default='$(wget -qO- ip.cldcloud.com)' 5 | 6 | if ! grep -q "^NETWORK_POLICY=" /var/cld/creds/creds 7 | then 8 | echo "Select network security policy" 9 | select ANSWER in general private paranoid 10 | do 11 | if [ "${ANSWER}" == "general" ]; then 12 | echo NETWORK_POLICY=general >> /var/cld/creds/creds 13 | break 14 | elif [ "${ANSWER}" == "private" ]; then 15 | echo NETWORK_POLICY=private >> /var/cld/creds/creds 16 | break 17 | elif [ "${ANSWER}" == "paranoid" ]; then 18 | echo NETWORK_POLICY=paranoid >> /var/cld/creds/creds 19 | break 20 | else 21 | echo NETWORK_POLICY=general >> /var/cld/creds/creds 22 | break 23 | fi 24 | done 25 | fi 26 | 27 | if ! grep -q "^MIKROTIK=" /var/cld/creds/creds 28 | then 29 | echo "Are you using MIKROTIK ?" 30 | select ANSWER in yes no 31 | do 32 | if [ "${ANSWER}" == "yes" ] 33 | then 34 | init-load-constants MIKROTIK_USER\|admin MIKROTIK_PASSWORD\|Y0uRM1kr071Kp455W0rD MIKROTIK_HOST\|1.2.3.4 || echo skipped 35 | echo MIKROTIK=1 >> /var/cld/creds/creds 36 | break 37 | elif [ "${ANSWER}" == "no" ] 38 | then 39 | echo MIKROTIK=0 >> /var/cld/creds/creds 40 | break 41 | fi 42 | done 43 | fi -------------------------------------------------------------------------------- /modules/ansible/README.md: -------------------------------------------------------------------------------- 1 | Integration of CLD with ansible, for convenient launch of playbooks on instances connected to the system also used as a centralized playbooks storage 2 | 3 | The module is under development 4 | 5 | Playbooks path: `/var/cld/modules/ansible/data/playbook/` -------------------------------------------------------------------------------- /modules/ansible/bin/cld-ansible: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Tool for deploy Ansible playbooks 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 First PATTERN filtering allowed instances 8 | $2 Second PATTERN filtering allowed instances 9 | $3 Third PATTERN filtering allowed instances 10 | --playbook=foobar Name of playbook in /var/cld/modules/ansible/data/playbook/ 11 | --vars=foo=bar,key=val Argument to pass variables to playbook 12 | --groups=GROUP1,GROUP2 Filtering by instance groups 13 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to access matrix 14 | EOL 15 | ) 16 | HELP_EXAMPLES=$(cat << 'EOL' 17 | cld-ansible --group=kube --playbook=kubespray 18 | cld-ansible instancepattern --group=kube --playbook=kubespray --vars=var1=value1,var2=value2 19 | EOL 20 | ) 21 | 22 | source /var/cld/bin/include/cldfuncs 23 | 24 | for i in ${CLDOPTS} 25 | do 26 | case $i in 27 | -p=*|-playbook=*|--playbook=*) PLAYBOOK="${i#*=}" ;; 28 | -v=*|-vars=*|--vars=*) PLAYBOOK_VARS="${i#*=}" ;; 29 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 30 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 31 | -*) ;; 32 | *) let ii++; declare ARG$ii=${i} ;; 33 | esac 34 | done 35 | 36 | CLD_INSTANCES=$(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" "$ARG1" "$ARG2" "$ARG3" "$CLD_ALL_GROUPS_ARG") 37 | PLAYBOOK_INSTANCES=$(tr '\n' ',' <<< "${CLD_INSTANCES}") 38 | 39 | [ "${PLAYBOOK_INSTANCES}" ] || { echo "There is no any allowed instances - try remove filter arguments or ask your system administrator add/share it" ; exit 1 ; } 40 | [ "${PLAYBOOK}" ] || { echo Playbook is not defined - exit ; exit 1 ; } 41 | [ -f "/var/cld/modules/ansible/data/playbook/$PLAYBOOK/environment.yml" ] || { echo "Playbook \"$PLAYBOOK\" is not exist - exit" ; exit 1 ; } 42 | echo -e "Playbook will affect folowing instances:\n${CLD_INSTANCES}" 43 | echo 44 | echo Run playbook 45 | cd /var/cld/modules/ansible/data/playbook/$PLAYBOOK/ && ansible-playbook -i ${PLAYBOOK_INSTANCES} environment.yml $([ "${PLAYBOOK_VARS}" ] && echo --extra-vars \"${PLAYBOOK_VARS}\") | sed -u 's#*##g' 46 | [ "${PIPESTATUS[0]}" != "0" ] && { echo PLAYBOOK FAILED ; exit 1 ; } 47 | -------------------------------------------------------------------------------- /modules/backup/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /var/cld/bin/include/cldfuncs 3 | 4 | if grep -q "^BACKUPMODULE=" /var/cld/creds/creds 5 | then 6 | echo -n "" 7 | else 8 | echo "Are you using BACKUPMODULE ?" 9 | select ANSWER in yes no 10 | do 11 | if [ "${ANSWER}" == "yes" ] 12 | then 13 | BACKUP_SERVER_SET=$(cat /var/cld/creds/creds_dns_cf_api_list 2>/dev/null) 14 | [ "$BACKUP_SERVER_SET" ] || init-string 'BACKUP_SERVER|backup1.example.com|[A-Za-z0-9@._-]+' 'BACKUP_SERVER_DIR|/backup|[A-Za-z0-9._/-]+' --file=/var/cld/modules/backup/data/servers 15 | echo BACKUPMODULE=1 >> /var/cld/creds/creds 16 | break 17 | elif [ "${ANSWER}" == "no" ] 18 | then 19 | echo BACKUPMODULE=0 >> /var/cld/creds/creds 20 | break 21 | fi 22 | done 23 | fi 24 | 25 | -------------------------------------------------------------------------------- /modules/backup/methods/clickhouse/backup: -------------------------------------------------------------------------------- 1 | TOOLDEPLOY=$(cat << 'EOTOOLDEPLOY' 2 | install-clickhouse-backup() 3 | { 4 | wget https://github.com/AlexAkulov/clickhouse-backup/releases/download/v1.2.1/clickhouse-backup.tar.gz 5 | tar -zxvf clickhouse-backup.tar.gz 6 | cp clickhouse-backup/clickhouse-backup /usr/local/bin/ 7 | chmod 755 /usr/local/bin/clickhouse-backup 8 | } 9 | [ -f /usr/local/bin/clickhouse-backup ] || install-clickhouse-backup 10 | EOTOOLDEPLOY 11 | ) 12 | 13 | CLICKHOUSE_USER="${CLICKHOUSE_USER:-default}" 14 | [ "${CLICKHOUSE_PASSWORD}" ] && CLICKHOUSE_PASSWORD=" password: '${CLICKHOUSE_PASSWORD}'" 15 | [ "${CLICKHOUSE_HOST}" ] && CLICKHOUSE_HOST=" host: '${CLICKHOUSE_HOST}'" 16 | [ "${CLICKHOUSE_PORT}" ] && CLICKHOUSE_PORT=" port: '${CLICKHOUSE_PORT}'" 17 | 18 | CLICKHOUSE_CONFIG=$(grep -v "^$" << EOCLICKHOUSE 19 | clickhouse: 20 | username: ${CLICKHOUSE_USER} 21 | ${CLICKHOUSE_PASSWORD} 22 | ${CLICKHOUSE_HOST} 23 | ${CLICKHOUSE_PORT} 24 | general: 25 | remote_storage: none 26 | backups_to_keep_local: 1 27 | log_level: info 28 | EOCLICKHOUSE 29 | ) 30 | 31 | $CLD_VARS 32 | $CLD_DEPLOY_NOTTY << EOCONFIG 33 | ${TOOLDEPLOY} 34 | cat > /etc/clickhouse-backup/config.yml << 'EOBACKUPCONF' 35 | ${CLICKHOUSE_CONFIG} 36 | EOBACKUPCONF 37 | EOCONFIG 38 | 39 | $CLD_DEPLOY_NOTTY <<< "/usr/local/bin/clickhouse-backup create" 40 | 41 | rsync -avP -e "ssh -p $PRT -T -o Compression=no -x -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" ${USR}@${SRV}:/var/lib/clickhouse/backup/ ${SERVER_BACKUP_DIR}/${INSTANCE}/${DATE}/${BACKUP_METHOD}/ -------------------------------------------------------------------------------- /modules/backup/methods/clickhouse/example: -------------------------------------------------------------------------------- 1 | CLICKHOUSE_USER="default" # Default is empty "default" 2 | #CLICKHOUSE_PASSWORD="HetgPDbDyBuDJBdaHXzbe" # Default is empty "" 3 | #KEEPLAST='7' # How many copies will remain after rotation - default - '7' 4 | #CRON="0 0 * * *" # Default - "0 0 * * *" 5 | #SERVER="backup1.example.com_1.2.3.4_22_root" # Default first from backup server list 6 | #SERVER_BACKUP_DIR="/backup" # Backup server backup directory - default - /backup 7 | cat << EOCLICKHOUSE 8 | clickhouse-client --query "CREATE USER ${USER} IDENTIFIED BY '${PASSWORD}'" 9 | clickhouse-client --query "SET allow_introspection_functions=1" 10 | clickhouse-client --query "GRANT ALL on *.* TO ${USER}" 11 | EOCLICKHOUSE -------------------------------------------------------------------------------- /modules/backup/methods/etc/backup: -------------------------------------------------------------------------------- 1 | [ "${DIR_LIST}" ] || DIR_LIST="/etc/" 2 | EXCLUDE_LIST="${EXCLUDE_LIST:-'*.log,*.gz,*/selinux/targeted/*'}" 3 | EXCLUDE_ARGS=$(echo "${EXCLUDE_LIST}" | tr ',' '\n' | xargs -I ^ echo -n "--exclude='^' ") 4 | $CLD_VARS 5 | for BACKUP_ITEM in $(tr ',' ' ' <<< "${DIR_LIST}") 6 | do 7 | $CLD_DEPLOY_NOTTY <<< "ionice -c3 tar czf - ${EXCLUDE_ARGS} ${BACKUP_ITEM}" > ${SERVER_BACKUP_DIR}/${INSTANCE}/${DATE}/${BACKUP_METHOD}/${BACKUP_ITEM//\//_}.tar.gz 8 | done -------------------------------------------------------------------------------- /modules/backup/methods/etc/example: -------------------------------------------------------------------------------- 1 | #DIR_LIST="/etc/nginx/,/var/lib/postgre/" # default - /etc/ 2 | #EXCLUDE_LIST="*.log,*.gz" # Default - "*.log,*.gz,*/selinux/targeted/*" - allow to be empty "" 3 | #KEEPLAST='7' # How many copies will remain after rotation - default - '7' 4 | #CRON="0 0 * * *" # Default - "0 0 * * *" 5 | #SERVER="backup1.example.com_1.2.3.4_22_root" # Default first from backup server list 6 | #SERVER_BACKUP_DIR="/backup" # Backup server backup directory - default - /backup -------------------------------------------------------------------------------- /modules/backup/methods/files/backup: -------------------------------------------------------------------------------- 1 | [ "${DIR_LIST}" ] || { echo DIR_LIST IS NOT DEFINED - exit ; exit 1 ; } 2 | EXCLUDE_LIST="${EXCLUDE_LIST:-'*.log,*.gz'}" 3 | EXCLUDE_ARGS=$(echo "${EXCLUDE_LIST}" | tr ',' '\n' | xargs -I ^ echo -n "--exclude='^' ") 4 | $CLD_VARS 5 | for BACKUP_ITEM in $(tr ',' ' ' <<< "${DIR_LIST}") 6 | do 7 | $CLD_DEPLOY_NOTTY <<< "ionice -c3 tar czf - ${EXCLUDE_ARGS} ${BACKUP_ITEM}" > ${SERVER_BACKUP_DIR}/${INSTANCE}/${DATE}/${BACKUP_METHOD}/${BACKUP_ITEM//\//_}.tar.gz 8 | done -------------------------------------------------------------------------------- /modules/backup/methods/files/example: -------------------------------------------------------------------------------- 1 | DIR_LIST="/etc/nginx/,/var/www/site.com/" # Will not start if not set 2 | EXCLUDE_LIST="*.log,*.gz" # Default - "*.log,*.gz" - allow to be empty "" 3 | #KEEPLAST='7' # How many copies will remain after rotation - default - '7' 4 | #CRON="0 0 * * *" # Default - "0 0 * * *" 5 | #SERVER="backup1.example.com_1.2.3.4_22_root" # Default first from backup server list 6 | #SERVER_BACKUP_DIR="/backup" # Backup server backup directory - default - /backup -------------------------------------------------------------------------------- /modules/backup/methods/mongo/backup: -------------------------------------------------------------------------------- 1 | ionice -c3 mongodump --forceTableScan --host ${MONGO_HOST} -u "${MONGO_USER}" -p "${MONGO_PASSWORD}" --authenticationDatabase "admin" --gzip --out ${SERVER_BACKUP_DIR}/${INSTANCE}/${DATE}/${BACKUP_METHOD}/ 2 | -------------------------------------------------------------------------------- /modules/backup/methods/mongo/example: -------------------------------------------------------------------------------- 1 | MONGO_HOST="1.2.3.4" 2 | MONGO_USER="backup" 3 | MONGO_PASSWORD="ySRDCjYjvMZw9d91QxQV6" 4 | #KEEPLAST='7' # How many copies will remain after rotation - default - '7' 5 | #CRON="0 0 * * *" # Default - "0 0 * * *" 6 | #SERVER="backup1.example.com_1.2.3.4_22_root" # Default first from backup server list 7 | #SERVER_BACKUP_DIR="/backup" # Backup server backup directory - default - /backup 8 | 9 | #Print command to create user 10 | cat << EONOTICE 11 | mongo admin --eval " 12 | db.createUser( 13 | { 14 | user: '${MONGO_USER}', 15 | pwd: '${MONGO_PASSWORD}', 16 | roles: [ { role: 'userAdminAnyDatabase', db: 'admin' }, 'readWriteAnyDatabase' ] 17 | } 18 | )" 19 | EONOTICE -------------------------------------------------------------------------------- /modules/backup/methods/mysql/backup: -------------------------------------------------------------------------------- 1 | 2 | if [ "${MYSQL_HOST}" = "127.0.0.1" -o "${MYSQL_HOST}" = "localhost" ]; then 3 | [ "${MYSQL_USER}" ] && MYSQL_USER="--user='${MYSQL_USER}'" || MYSQL_USER="--user='root'" 4 | [ "${MYSQL_PASSWORD}" ] && MYSQL_PASSWORD="--password='${MYSQL_PASSWORD}'" 5 | [ "${MYSQL_DATABASES}" ] || MYSQL_DATABASES="--all-databases" 6 | [ "${MYSQL_HOST}" = "127.0.0.1" ] && MYSQL_HOST="--host='${MYSQL_HOST}'" 7 | [ "${MYSQL_HOST}" = "localhost" ] && MYSQL_HOST="" 8 | $CLD_VARS 9 | for MYSQL_DATABASE in $(tr ',' ' ' <<< "${MYSQL_DATABASES}") 10 | do 11 | $CLD_DEPLOY_NOTTY <<< "mysqldump --single-transaction ${MYSQL_HOST} ${MYSQL_USER} ${MYSQL_PASSWORD} ${MYSQL_DATABASE}" > ${SERVER_BACKUP_DIR}/${INSTANCE}/${DATE}/${BACKUP_METHOD}/${MYSQL_DATABASE//-/}.tar.gz 12 | done 13 | 14 | else 15 | 16 | if [ "${MYSQL_DATABASES}" ]; then 17 | for MYSQL_DATABASE in $(tr ',' ' ' <<< "${MYSQL_DATABASES}") 18 | do 19 | mkdir -p ${SERVER_BACKUP_DIR}/${INSTANCE}/${DATE}/${BACKUP_METHOD}/${MYSQL_DATABASE} &> /dev/null 20 | ionice -c3 mydumper --host=${MYSQL_HOST} --user=${MYSQL_USER} --password=${MYSQL_PASSWORD} --database=${MYSQL_DATABASE} -o ${SERVER_BACKUP_DIR}/${INSTANCE}/${DATE}/${BACKUP_METHOD}/${MYSQL_DATABASE} --compress --triggers --events --routines --build-empty-files --less-locking --use-savepoints --success-on-1146 --compress-protocol --threads=1 --verbose=3 21 | done 22 | else 23 | ionice -c3 mydumper --host=${MYSQL_HOST} --user=${MYSQL_USER} --password=${MYSQL_PASSWORD} -o ${SERVER_BACKUP_DIR}/${INSTANCE}/${DATE}/${BACKUP_METHOD} --compress --triggers --events --routines --build-empty-files --less-locking --use-savepoints --success-on-1146 --compress-protocol --threads=1 --verbose=3 24 | fi 25 | 26 | fi -------------------------------------------------------------------------------- /modules/backup/methods/mysql/example: -------------------------------------------------------------------------------- 1 | MYSQL_HOST="1.2.3.4" # if MySQL behind firewall you can use 127.0.0.1 or localhost(socket) then backup will perform via SSH by mysqldump 2 | MYSQL_USER="backup" # default is "root" 3 | MYSQL_PASSWORD="HetgPDbDyBuDJBdaHXzbe" # can be empty for localhost backup 4 | MYSQL_SOURCE="$(wget -qO- ip.cldcloud.com)" # can be commented for localhost backup 5 | #MYSQL_DATABASES="database1,database2" # default is empty "" for all databases 6 | #KEEPLAST='7' # How many copies will remain after rotation - default - '7' 7 | #CRON="0 0 * * *" # Default - "0 0 * * *" 8 | #SERVER="backup1.example.com_1.2.3.4_22_root" # Default first from backup server list 9 | #SERVER_BACKUP_DIR="/backup" # Backup server backup directory - default - /backup 10 | #Print command to create user 11 | cat << EONOTICE 12 | ###MYSQL/PERCONA 13 | CREATE USER ${MYSQL_USER}@'${MYSQL_SOURCE}' IDENTIFIED BY '${MYSQL_PASSWORD}'; 14 | GRANT ALL ON *.* TO ${MYSQL_USER}@'${MYSQL_SOURCE}'; 15 | ALTER USER ${MYSQL_USER}@'${MYSQL_SOURCE}' IDENTIFIED WITH mysql_native_password BY '${MYSQL_PASSWORD}'; FLUSH PRIVILEGES; 16 | # 17 | ###MARIADB 18 | GRANT ALL ON *.* TO ${MYSQL_USER}@'${MYSQL_SOURCE}' IDENTIFIED BY '${MYSQL_PASSWORD}'; 19 | ##### THEN PRESS ENTER TO CONTINUE 20 | EONOTICE -------------------------------------------------------------------------------- /modules/backup/methods/postgresql/backup: -------------------------------------------------------------------------------- 1 | export PGPASSWORD="${POSTGRE_PASSWORD}" ; ionice -c3 pg_dumpall --host=${POSTGRE_HOST} --username=${POSTGRE_USER} --clean | gzip > ${SERVER_BACKUP_DIR}/${INSTANCE}/${DATE}/${BACKUP_METHOD}/dumpall.sql.gz -------------------------------------------------------------------------------- /modules/backup/methods/postgresql/example: -------------------------------------------------------------------------------- 1 | POSTGRE_HOST="1.2.3.4" 2 | POSTGRE_USER="postgres" 3 | POSTGRE_PASSWORD="LUVCD3T1Ue3C671r1n2g0" 4 | #KEEPLAST='7' # How many copies will remain after rotation - default - '7' 5 | #CRON="0 0 * * *" # Default - "0 0 * * *" 6 | #SERVER="backup1.example.com_1.2.3.4_22_root" # Default first from backup server list 7 | #SERVER_BACKUP_DIR="/backup" # Backup server backup directory - default - /backup -------------------------------------------------------------------------------- /modules/cm/README.md: -------------------------------------------------------------------------------- 1 | Cloud manage module provides such functionality as creation, configuration and management of KVM servers on hypervisors running "Proxmox VE (Virtualization Management Platform)". The existing toolkit allows in the console mode to carry out all basic operations with KVM servers located on hypervisors under the control of CLD. 2 | Main functions and features: 3 | - KVM creation supports interactive mode, servers are created based on operating system (OS) templates such as Centos, Debian, Ubuntu, Fedora, FreeBSD 4 | - OS templates are loaded onto the hypervisor automatically 5 | - basic configuration of OS, network, access credentials is done directly during KVM deployment from a template, each KVM server parameter is configured by arguments, or interactively 6 | - support for creating several types of file systems is available (zfs, lvm, qcow2), it is recommended to use zfs - it has high quality and stability when working in production 7 | - control over the assignment and operation of ip addresses for each KVM is set during deployment 8 | - QEMU guest agent is installed in each OS, all control options from the hypervisor are available 9 | - for each KVM during deployment, a serial port is connected, the serial console is configured in all OS templates 10 | - auto login option for serial console 11 | - changing the root password for KVM in soft (without rebooting) and hard modes (by mounting the FS on a switched off KVM) 12 | - migration of KVM between hypervisors in interactive and direct modes (zfs), (other filesystems through shared network storage) 13 | - centralized KVM server management functionality (start, stop reset, destroy) 14 | - support for api OVH, Hetzner, Online.net (ordering ip addresses, migrating ip addresses between services, creating MAC) 15 | - daily check of KVM backups on hypervisors, clear report in telegram or by email. 16 | - scripts for deploying hypervisors (debian 9, debian 10), full OS configuration, network configuration, network storages -------------------------------------------------------------------------------- /modules/cm/bin/cld-cm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Show list of hypervisors and KVMs of cloud manager platform 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 First PATTERN filtering allowed KVMs 8 | $2 Second PATTERN filtering allowed KVMs 9 | $3 Third PATTERN filtering allowed KVMs 10 | --json Json outout option 11 | --beauty Using together with --json option to beautify json output 12 | --nocache Force hypervisors parsing without cache output 13 | --hypers=HPR-pattern Filter hypervisors by pattern 14 | EOL 15 | ) 16 | HELP_EXAMPLES=$(cat << 'EOL' 17 | cld-cm 18 | cld-cm --json 19 | EOL 20 | ) 21 | 22 | source /var/cld/bin/include/cldfuncs 23 | source /var/cld/modules/cm/bin/include/create_funcs 24 | ARG1=$(echo "${@:1}" | tr ' ' '\n' | grep -v '\--' | head -1) 25 | ARG2=$(echo "${@:1}" | tr ' ' '\n' | grep -v '\--' | head -2 | tail -1) 26 | ARG3=$(echo "${@:1}" | tr ' ' '\n' | grep -v '\--' | head -3 | tail -1) 27 | 28 | init-load-constants HYPERVISOR_NAME_PREFIX\|HPR 29 | 30 | for i in ${CLDOPTS} 31 | do 32 | case $i in 33 | -H=*|-hypers=*|--hypers=*) HPRS="${i#*=}" ;; 34 | -j|-json|--json) JSON=1 ;; 35 | -b|-beauty|--beauty) JSON_BEAUTY=1 ;; 36 | -m|-minify|--minify) JSON_MINIFY=1 ;; 37 | -n|-nocache|--nocache) NOCACHE=1 ;; 38 | *) ;; 39 | esac 40 | done 41 | 42 | ALLOWED_HPRS=$(CLOUDS_USER_ALLOWED ${HPRS} | grep -i "^$HYPERVISOR_NAME_PREFIX" | cut -d _ -f 1 | head -c -1) 43 | [ "$ALLOWED_HPRS" ] || { echo There is not allowed hypervisors for this user $SUDO_USER 1>&2 ; echo '[]' ; exit 1 ;} 44 | 45 | [ "$NOCACHE" ] || NOCACHE=0 46 | 47 | if [ "$JSON_BEAUTY" == "1" -a "$FROM" == "API" ] 48 | then 49 | JSON_BEAUTY_ARG=$(cat << EOL 50 | | jq -C '[ .[] | select( .hypervisor | contains($(echo "$ALLOWED_HPRS" | awk '{print "\x22"$1"\x22,"}' | head -c -2))) ]' 51 | EOL 52 | ) 53 | elif [ "$JSON_MINIFY" == "1" ] 54 | then 55 | JSON_BEAUTY_ARG=$(cat << EOL 56 | | jq -c '[ .[] | select( .hypervisor | contains($(echo "$ALLOWED_HPRS" | awk '{print "\x22"$1"\x22,"}' | head -c -2))) ]' 57 | EOL 58 | ) 59 | else 60 | JSON_BEAUTY_ARG=$(cat << EOL 61 | | jq '[ .[] | select( .hypervisor | contains($(echo "$ALLOWED_HPRS" | awk '{print "\x22"$1"\x22,"}' | head -c -2))) ]' 62 | EOL 63 | ) 64 | fi 65 | 66 | if [ "$JSON" == "1" ] 67 | then 68 | source <(echo -n get-kvm-list-json "$ARG1" "$ARG2" "$ARG3" ${JSON_BEAUTY_ARG}) 69 | else 70 | get-kvm-list | grep -i "$ARG1" | grep -i "$ARG2" | grep -i "$ARG3" 71 | fi 72 | grep -vs "^#" /etc/cron.d/* | egrep -s "cld-cm \-\-json.+\-\-nocache" | grep -qs root || echo '* * * * * root /var/cld/modules/cm/bin/cld-cm --json --nocache &>/dev/null' >> /etc/cron.d/cld -------------------------------------------------------------------------------- /modules/cm/bin/include/bot: -------------------------------------------------------------------------------- 1 | BOT_TOKEN="" 2 | TG_GROUP="" 3 | send_tg() 4 | { 5 | (wget -qO- "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage?chat_id=${TG_GROUP}&parse_mode=Markdown&text=$(echo -n ${@:1} | sed -e 's#\\n#%0A#g' -e 's##*#g' -e 's#&#%26#g')" &>/dev/null ) &>/dev/null & 6 | cat >> /tmp/tg_send << EOLOG 7 | ${@:1} 8 | wget -qO- "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage?chat_id=${TG_GROUP}&parse_mode=Markdown&text=$(echo -n ${@:1} | sed -e 's#\\n#%0A#g' -e 's##*#g' -e 's#&#%26#g')" 9 | EOLOG 10 | } 11 | -------------------------------------------------------------------------------- /modules/cm/bin/include/privatenet_vars: -------------------------------------------------------------------------------- 1 | PRIVATE_NET_FILTER_SET=$(cat << 'EOL' 2 | private-net-filter-add() 3 | { 4 | mkdir /etc/pve/firewall -p &>/dev/null 5 | cat >> /etc/pve/firewall/${VMID}.fw << EOIP 6 | [IPSET ipfilter-net1] # only allow specified IPs on net1 7 | ${PRIVATENET} 8 | EOIP 9 | qm set $VMID --net1 virtio,bridge=vmbr1,firewall=1 10 | } 11 | 12 | private-net-filter-change() 13 | { 14 | PRIVATE_NET_LINE=$(($(grep -n "IPSET ipfilter-net1" /etc/pve/firewall/${VMID}.fw | cut -d : -f 1)+1)) 15 | sed -i ${PRIVATE_NET_LINE}'s#.*#'${PRIVATENET}'#g' /etc/pve/firewall/${VMID}.fw 16 | qm set $VMID --net1 virtio,bridge=vmbr1,firewall=1 17 | } 18 | 19 | grep -q 'ipfilter-net1' /etc/pve/firewall/${VMID}.fw && private-net-filter-change || private-net-filter-add 20 | EOL 21 | ) 22 | 23 | PRIVATE_NET_FILTER_DELETE=$(cat << 'EOL' 24 | PRIVATE_NET_LINE=$(grep -n "IPSET ipfilter-net1" /etc/pve/firewall/${VMID}.fw | cut -d : -f 1) 25 | sed -i ${PRIVATE_NET_LINE}',$d' /etc/pve/firewall/${VMID}.fw 26 | qm set $VMID --delete net1 27 | EOL 28 | ) 29 | 30 | -------------------------------------------------------------------------------- /modules/cm/bin/include/template_functions: -------------------------------------------------------------------------------- 1 | template-user-data() 2 | { 3 | source /var/cm/bin/include/template_vars 4 | [ "$TEMPLATE" != '' ] && ${TEMPLATE}-send-user-data 5 | } 6 | -------------------------------------------------------------------------------- /modules/cm/bin/include/template_logic: -------------------------------------------------------------------------------- 1 | if echo "$TEMPLATE" | grep --quiet "C7WP" ; then 2 | KVM_CREATE=$C7WP_CREATE 3 | TEMPLATE_CONFIGURE=$C7WP_CONFIGURATION 4 | TEMPLATE_AFTER_START='qm set $VMID -delete ide2' 5 | elif echo "$TEMPLATE" | grep --quiet "C7SNT" ; then 6 | KVM_CREATE=$C7SNT_CREATE 7 | TEMPLATE_CONFIGURE=$C7SNT_CONFIGURATION 8 | TEMPLATE_AFTER_START='qm set $VMID -delete ide2' 9 | elif echo "$TEMPLATE" | grep --quiet "C7MNCRFT" ; then 10 | KVM_CREATE=$C7MNCRFT_CREATE 11 | TEMPLATE_CONFIGURE=$C7MNCRFT_CONFIGURATION 12 | TEMPLATE_AFTER_START='qm set $VMID -delete ide2' 13 | elif echo "$TEMPLATE" | grep --quiet "C7GTLB" ; then 14 | KVM_CREATE=$C7GTLB_CREATE 15 | TEMPLATE_CONFIGURE=$C7GTLB_CONFIGURATION 16 | TEMPLATE_AFTER_START='qm set $VMID -delete ide2' 17 | elif echo "$TEMPLATE" | grep --quiet "C7YII2" ; then 18 | KVM_CREATE=$C7YII2_CREATE 19 | TEMPLATE_CONFIGURE=$C7YII2_CONFIGURATION 20 | TEMPLATE_AFTER_START='qm set $VMID -delete ide2' 21 | elif echo "$TEMPLATE" | grep --quiet "C7WBMN" ; then 22 | KVM_CREATE=$C7WBMN_CREATE 23 | TEMPLATE_CONFIGURE=$C7WBMN_CONFIGURATION 24 | TEMPLATE_AFTER_START='qm set $VMID -delete ide2' 25 | elif echo "$TEMPLATE" | grep --quiet "U18JTSMT" ; then 26 | KVM_CREATE=$U18JTSMT_CREATE 27 | TEMPLATE_CONFIGURE=$U18JTSMT_CONFIGURATION 28 | TEMPLATE_AFTER_START='qm set $VMID -delete ide2' 29 | elif echo "$TEMPLATE" | grep --quiet "C7CWP" ; then 30 | KVM_CREATE=$C7CWP_CREATE 31 | TEMPLATE_CONFIGURE=$C7CWP_CONFIGURATION 32 | TEMPLATE_AFTER_START='qm set $VMID -delete ide2' 33 | fi 34 | 35 | -------------------------------------------------------------------------------- /modules/cm/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /var/cld/bin/include/cldfuncs 3 | 4 | if grep -q "^OVH=" /var/cld/creds/creds 5 | then 6 | echo -n "" 7 | else 8 | echo "Are you using OVH ?" 9 | select ANSWER in yes no 10 | do 11 | if [ "${ANSWER}" == "yes" ] 12 | then 13 | init-load-constants HYPERVISOR_NAME_PREFIX\|HPR OVH_CONSUMER_KEY\|uAjAWotdxHyxQ7ddvAFCco3sa990wHqsy OVH_APP_KEY\|X05b2oM4vmsc4Nz8F OVH_APP_SECRET\|nW76Meps7rZGFLFrR7XgL4dsKS6xJwEF 14 | echo OVH=1 >> /var/cld/creds/creds 15 | break 16 | elif [ "${ANSWER}" == "no" ] 17 | then 18 | echo OVH=0 >> /var/cld/creds/creds 19 | break 20 | fi 21 | done 22 | fi 23 | 24 | if grep -q "^ONLINE_NET=" /var/cld/creds/creds 25 | then 26 | echo -n "" 27 | else 28 | echo "Are you using ONLINE_NET ?" 29 | select ANSWER in yes no 30 | do 31 | if [ "${ANSWER}" == "yes" ] 32 | then 33 | init-load-constants HYPERVISOR_NAME_PREFIX\|HPR ONLINE_NET_PRIVATE_ACCESS_TOKEN\|jdhnkxyrhngvjycfny1w00nlvwkejkgrwx6zjv8v 34 | echo ONLINE_NET=1 >> /var/cld/creds/creds 35 | break 36 | elif [ "${ANSWER}" == "no" ] 37 | then 38 | echo ONLINE_NET=0 >> /var/cld/creds/creds 39 | break 40 | fi 41 | done 42 | fi 43 | 44 | if grep -q "^HETZNER=" /var/cld/creds/creds 45 | then 46 | echo -n "" 47 | else 48 | echo "Are you using HETZNER ?" 49 | select ANSWER in yes no 50 | do 51 | if [ "${ANSWER}" == "yes" ] 52 | then 53 | init-load-constants HYPERVISOR_NAME_PREFIX\|HPR HETZNER_ROBOT_LOGIN\|hetzner@login.con HETZNER_ROBOT_PASSWORD\|oe9AK11KMG3FceJmakXMu 54 | echo HETZNER=1 >> /var/cld/creds/creds 55 | break 56 | elif [ "${ANSWER}" == "no" ] 57 | then 58 | echo HETZNER=0 >> /var/cld/creds/creds 59 | break 60 | fi 61 | done 62 | fi -------------------------------------------------------------------------------- /modules/cm/web.py: -------------------------------------------------------------------------------- 1 | webmodule["cm"] = {} 2 | webmodule["cm"]["homename"] = "Cloud manager" 3 | webmodule["cm"]["desc"] = "Virtual environment control" 4 | @app.route("/cm") 5 | def cm_index(): 6 | if 'username' in session: 7 | user = session['username'] 8 | checkresult = checkpermswhiteip(cldmodule, 'NOTOOL', user, remoteaddr()) 9 | if checkresult[0] != "granted": return Response("403", status=403, mimetype='application/json') 10 | cld_clouds = json.loads(bash('sudo -u '+vld(user)+' sudo FROM=CLI /var/cld/modules/cm/bin/cld-cm --json')) 11 | return render_template('modules/cm/cm.html', username=user, cld_clouds=cld_clouds) 12 | -------------------------------------------------------------------------------- /modules/cm/web/content/cm.css: -------------------------------------------------------------------------------- 1 | #ServerListUl li a { 2 | border: 1px solid #1e88e5; 3 | margin-top: -1px; 4 | background-color: white; 5 | padding: 2px; 6 | text-decoration: none; 7 | color: black; 8 | display: block; 9 | font-size: 12; 10 | color: lightslategray; 11 | border-right-width: 0; 12 | border-left-width: 0; 13 | border-bottom-width: 0; 14 | } -------------------------------------------------------------------------------- /modules/cm/web/content/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | background 5 | 6 | 7 | 8 | Layer 1 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /modules/cmd/bin/cld-cmd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Create any custom CLD command tool for sharing any user 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | --name="mycmd" Name of custom CMD - should be unique 8 | --command=/cmd,args,ARG1 Custom command with arguments - comma separated and absolute path - ARG1-20 will take value of passing arguments to custom tool while using 9 | --debug Debug output of created CLD tool 10 | EOL 11 | ) 12 | HELP_EXAMPLES=$(cat << 'EOL' 13 | cld-cmd --name=my_cmd --command=helm,upgrade,somehelm,--set=git.commit=ARG1 14 | EOL 15 | ) 16 | 17 | source /var/cld/bin/include/cldfuncs 18 | 19 | for i in ${CLDOPTS} 20 | do 21 | case $i in 22 | -n=*|-name=*|--name=*) CUSTOM_NAME="${i#*=}" ;; 23 | -c=*|-command=*|--command=*) CUSTOM_COMMAND="${i#*=}" ;; 24 | -d|-debug|--debug) DEBUG="1" ;; 25 | -*) ;; 26 | *) let ii++; declare ARG$ii=${i} ;; 27 | esac 28 | done 29 | 30 | CUSTOM_NAME=$(tr -d -c '[:alnum:]' <<< "$CUSTOM_NAME") 31 | 32 | if [ "$CUSTOM_NAME" == "" ] 33 | then 34 | while ! [[ "$CUSTOM_NAME" =~ ^[a-z0-9-]{3,25}$ ]] 35 | do 36 | echo "Please enter new CUSTOM COMMAND NAME name using only 'a-z 0-9 -' symbols 37 | Example: somename" 38 | echo -n '#? '; read CUSTOM_NAME 39 | echo 40 | [ -f /var/cld/modules/cmd/bin/cld-cmd${CUSTOM_NAME} ] && unset CUSTOM_NAME && echo NAME already in use 41 | done 42 | fi 43 | 44 | if [ "$CUSTOM_COMMAND" == "" ] 45 | then 46 | while ! [[ "$CUSTOM_COMMAND" =~ ^[A-Za-z0-9=/\"_.\ -]{3,1024}$ ]] 47 | do 48 | echo "Please enter new CUSTOM COMMAND with arguments using only 'A-z 0-9' symbols 49 | Example: helm upgrade somehelm --set=git.commit=ARG1" 50 | echo -n '#? '; read CUSTOM_COMMAND 51 | echo 52 | done 53 | fi 54 | 55 | [ -f /var/cld/modules/cmd/bin/cld-cmd${CUSTOM_NAME} ] && { echo Command name already in use - exit ; exit 1 ; } 56 | 57 | CUSTOM_COMMAND_USE="$(echo "${CUSTOM_COMMAND}" | tr ',' ' ' | sed -e 's#ARG1#"$ARG1"#g')" 58 | 59 | cat > /var/cld/modules/cmd/bin/cld-cmd${CUSTOM_NAME} << EOCUSTOMCMD 60 | #!/bin/bash 61 | HELP_DESC=\$(cat << 'EOL' 62 | Custom CLD tool for command "$CUSTOM_COMMAND_USE" 63 | EOL 64 | ) 65 | HELP_ARGS=\$(cat << 'EOL' 66 | \$1 ARG1 67 | \$2 ARG2 68 | \$20 ARG20 69 | EOL 70 | ) 71 | HELP_EXAMPLES=\$(cat << 'EOL' 72 | cld-cmd${CUSTOM_NAME} arg1 arg2 arg3 73 | EOL 74 | ) 75 | 76 | source /var/cld/bin/include/cldfuncs 77 | 78 | for i in \${CLDOPTS} 79 | do 80 | case \$i in 81 | -*) ;; 82 | *) let ii++; declare ARG\$ii=\${i} ;; 83 | esac 84 | done 85 | 86 | set -e 87 | 88 | ${CUSTOM_COMMAND_USE} 89 | EOCUSTOMCMD 90 | chmod 700 /var/cld/modules/cmd/bin/cld-cmd${CUSTOM_NAME} 91 | 92 | [ "$DEBUG" ] && { 93 | echo /var/cld/modules/cmd/bin/cld-cmd${CUSTOM_NAME} 94 | cat /var/cld/modules/cmd/bin/cld-cmd${CUSTOM_NAME} 95 | } -------------------------------------------------------------------------------- /modules/deploy/README.md: -------------------------------------------------------------------------------- 1 | Deploy bash scripts to servers in the system. 2 | The module structure consists of templates, deployments and actions. Each of these components makes it possible to compose tasks in an understandable way for subsequent execution on the servers of the system. 3 | - templates contain the deployment script itself, a test script, a list of files and folders for a preliminary backup, settings for the deployment process, the template can also contain custom backup and restaurant scripts (example) 4 | - a deployment is a script containing everything you need to launch an action, it can be created based on a template, or interactively during the first launch, in addition it includes - a list of servers, groups, or a name pattern (cli, api) (example) 5 | - actions contain the result of the deployment, including detailed logs (execution time and output of each command in terminal format as in manual line-by-line execution) for all servers, test results (example) 6 | - deployments can be used both for prompt mass installation of something, for example, salt agents, zabbix, or for urgent fixing, monitoring, launching, including the crown, and for full-fledged deployment of applications of any complexity from a template, it can also work in conjunction with a virtualization module, for directly fine-tuning the environment of a virtual machine, immediately after creation, scenarios with sequential execution of deployments are also possible -------------------------------------------------------------------------------- /modules/deploy/api.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | @app.route("/deploy///") 3 | def deploy_get_file(deploytype, deploy, file): 4 | apihash = request.args['hash'] 5 | for line in open('/var/cld/creds/passwd').read().strip().split('\n'): 6 | token = line.split(':')[2] 7 | checkhash = hashlib.md5(str(deploytype+deploy+file+token).encode('utf-8')).hexdigest() 8 | print(token+" "+checkhash+" "+apihash, flush=True) 9 | if checkhash == apihash: 10 | user = line.split(':')[0] 11 | break 12 | try: user 13 | except: return Response("404", status=403, mimetype='text/plain') 14 | checkresult = checkpermswhiteip(cldmodule, "NONE", token, remoteaddr()) 15 | if checkresult[0] != "granted": return Response("403", status=403, mimetype='text/plain') 16 | user = userbytoken(checkresult[1]) 17 | user = str(re.match('^[A-z0-9.,@=/_ -]+', user)[0]) 18 | user_allowed_deploys = json.loads(bash('sudo -u '+user+' sudo FROM=CLI /var/cld/modules/deploy/bin/cld-deploy --list --json')) 19 | if deploytype == "templates": 20 | deploys = user_allowed_deploys[0]['content'] 21 | elif deploytype == "deploys": 22 | deploys = user_allowed_deploys[1]['content'] 23 | if deploy in deploys: 24 | return Response(open('/var/cld/modules/deploy/'+deploytype+'/'+deploy+'/'+file).read(), status=200, mimetype='text/plain') 25 | else: 26 | return Response(deploytype[:-1].capitalize()+" not found", status=404, mimetype='text/plain') -------------------------------------------------------------------------------- /modules/deploy/bin/cld-action: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Information action tool 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | --deploy=deploy_name Name of deploy 8 | --action=action_prefix Action prefix 9 | EOL 10 | ) 11 | HELP_EXAMPLES=$(cat << 'EOL' 12 | cld-action 13 | cld-action --deploy=deployname 14 | EOL 15 | ) 16 | source /var/cld/bin/include/cldfuncs 17 | 18 | for i in ${CLDOPTS} 19 | do 20 | case $i in 21 | -d=*|-deploy=*|--deploy=*) DEPLOY="${i#*=}" ;; 22 | -a=*|-action=*|--action=*) ACTION="${i#*=}" ;; 23 | *) ;; 24 | esac 25 | done 26 | 27 | if [ "$DEPLOY" != "" -a "$ACTION" != "" ] 28 | then 29 | ls /var/cld/modules/deploy/actions/${DEPLOY}/${ACTION}/deploy_log/ | wc -w 30 | cat /var/cld/modules/deploy/actions/${DEPLOY}/${ACTION}/test_status/status_log | head -1 | cut -d ' ' -f 1 2>/dev/null | grep '/' || echo - 31 | grep -qs "DONE=1" /var/cld/modules/deploy/actions/${DEPLOY}/${ACTION}/vars && echo done || echo unfinished 32 | elif [ "$DEPLOY" ] 33 | then 34 | ls -t /var/cld/modules/deploy/actions/${DEPLOY}/* -d | rev | cut -d / -f 1 | rev 35 | else 36 | ls /var/cld/modules/deploy/actions/ 37 | fi 38 | 39 | -------------------------------------------------------------------------------- /modules/deploy/bin/include/deployfuncs: -------------------------------------------------------------------------------- 1 | defaultvars() 2 | { 3 | [ "$DESCRIPTION" ] || DESCRIPTION="${DESCRIPTION}" 4 | [ "$CLD_GROUPS" ] || CLD_GROUPS="${CLD_GROUPS}" 5 | [ "$BACKUP" ] || BACKUP="0" 6 | [ "$CUSTOM_BACKUP" ] || CUSTOM_BACKUP="0" 7 | [ "$TEST" ] || TEST="0" 8 | [ "$RETRY" ] || RETRY="1" 9 | [ "$TIMEOUT" ] || TIMEOUT="60" 10 | [ "$TEST_TIMEOUT" ] || TEST_TIMEOUT="60" 11 | [ "$BACKUP_TIMEOUT" ] || BACKUP_TIMEOUT="60" 12 | [ "$ASYNC" ] || ASYNC="0" 13 | [ "$NEXT_DEPLOY" ] || NEXT_DEPLOY="" 14 | [ "$NEXT_DEPLOY_WAIT" ] || NEXT_DEPLOY_WAIT="" 15 | [ "$NEXT_DEPLOY_ARGS" ] || NEXT_DEPLOY_ARGS="" 16 | [ "$DEBUG" ] || DEBUG="0" 17 | [ "$CRON" ] || CRON="0" 18 | } 19 | 20 | deploys-user-allowed() 21 | { 22 | for OPTS in ${@:1} 23 | do 24 | echo $OPTS | grep -q '^\--json' && JSONFUNCOUT=1 25 | done 26 | if [ "$JSONFUNCOUT" == "1" ] 27 | then 28 | { 29 | printf '[' 30 | printf '{"type":"templates",' 31 | printf '"content":[' 32 | printf '"' ; ls /var/cld/modules/deploy/templates/ | cat | head -c -1 | tr '\n' ',' | sed 's#,#","#g' ; printf '"' 33 | printf ']},' 34 | printf '{"type":"deploys",' 35 | printf '"content":[' 36 | printf '"' ; for CHECK_GROUP in $(/var/cld/bin/cld-getpasswd --user=$SUDO_USER --groups | tr ',' '\n'); do egrep -l "CLD_GROUPS\"?.+?(\,|\"|\=)${CHECK_GROUP}(\,|\"|$).+?\"?"\|"CLD_GROUPS=(\"\"|$)" /var/cld/modules/deploy/deploys/*/vars; done | sort -u | rev | cut -d / -f 2 | rev | head -c -1 | tr '\n' ',' | sed 's#,#","#g' ; printf '"' 37 | printf ']}' 38 | echo ']' 39 | } 40 | else 41 | for CHECK_GROUP in $(/var/cld/bin/cld-getpasswd --user=$SUDO_USER --groups | tr ',' '\n'); do egrep -l "CLD_GROUPS=\"?.+?(\,|\"|\=)${CHECK_GROUP}(\,|\"|\=).+?\"?"\|"CLD_GROUPS=(\"\"|$)" /var/cld/modules/deploy/deploys/*/vars; done | sort -u | rev | cut -d / -f 2 | rev 42 | fi 43 | } 44 | -------------------------------------------------------------------------------- /modules/deploy/web/content/deploy.css: -------------------------------------------------------------------------------- 1 | #ServerListUl li a { 2 | border: 1px solid #1e88e5; 3 | margin: 0px; 4 | background-color: white; 5 | padding: 0px; 6 | padding-left: 4px; 7 | text-decoration: none; 8 | display: block; 9 | font-size: 14; 10 | color: lightslategray; 11 | border-right-width: 0; 12 | border-left-width: 0; 13 | border-bottom-width: 0; 14 | } -------------------------------------------------------------------------------- /modules/deploy/web/content/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | background 5 | 6 | 7 | 8 | Layer 1 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /modules/dns/bin/cld-cfcache: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | CloudFlare cache cleaner 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 DNS zone - FQDN 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-cfcache example.com 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | source /var/cld/modules/dns/bin/include/dnsfuncs 16 | DNS_ZONE=${1,,} 17 | MAIN_ZONE=$(echo $DNS_ZONE | rev | cut -d . -f -2 | rev) 18 | 19 | echo $DNS_ZONE | egrep -q "^[a-z0-9.*-]+\.[a-z0-9.-]+$" \ 20 | || echoexit1 "incorrect domain - only full domain names allowed: example.com test.example.com" 21 | 22 | #[ $CFACC || CFACC=$(grep -s "${MAIN_ZONE}" /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F)/cf_dns_list | head -1 | cut -d _ -f 3) 23 | #[ $CFACC || CFACC=$(grep -s "${MAIN_ZONE}" /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F --date=yesterday)/cf_dns_list | head -1 | cut -d _ -f 3) 24 | [ "$CFACC" ] && { 25 | CFAPI=$(grep "$CFACC" /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 26 | cf-dns-api-creds 27 | CF_ZONE_ID=$(cf-dns-get-zone-id ${MAIN_ZONE}) 28 | } 29 | [ "$CFAPI" ] || for CFAPI in $(cat /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 30 | do 31 | cf-dns-api-creds 32 | CF_ZONE_ID=$(cf-dns-get-zone-id ${MAIN_ZONE}) 33 | [ "${CF_ZONE_ID}" ] && break 34 | done 35 | 36 | [ "$CF_ZONE_ID" ] || echoexit1 "domain $MAIN_ZONE not found in known accounts" 37 | 38 | cf-clean-cache ${CF_ZONE_ID} -------------------------------------------------------------------------------- /modules/dns/bin/cld-cfdel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Delete Zone (domain) from CloudFlare 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 DNS zone - FQDN 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-cfdel example.com 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | source /var/cld/modules/dns/bin/include/dnsfuncs 16 | DNS_ZONE=${1,,} 17 | MAIN_ZONE=$(echo $DNS_ZONE | rev | cut -d . -f -2 | rev) 18 | 19 | echo $DNS_ZONE | egrep -q "^[a-z0-9.*-]+\.[a-z0-9.-]+$" \ 20 | || echoexit1 "incorrect domain - only full domain names allowed: example.com test.example.com" 21 | 22 | #[ $CFACC || CFACC=$(grep -s "${MAIN_ZONE}" /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F)/cf_dns_list | head -1 | cut -d _ -f 3) 23 | #[ $CFACC || CFACC=$(grep -s "${MAIN_ZONE}" /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F --date=yesterday)/cf_dns_list | head -1 | cut -d _ -f 3) 24 | [ "$CFACC" ] && { 25 | CFAPI=$(grep "$CFACC" /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 26 | cf-dns-api-creds 27 | CF_ZONE_ID=$(cf-dns-get-zone-id ${MAIN_ZONE}) 28 | } 29 | [ "$CFAPI" ] || for CFAPI in $(cat /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 30 | do 31 | cf-dns-api-creds 32 | CF_ZONE_ID=$(cf-dns-get-zone-id ${MAIN_ZONE}) 33 | [ "${CF_ZONE_ID}" ] && break 34 | done 35 | 36 | [ "$CF_ZONE_ID" ] || echoexit1 "domain $MAIN_ZONE not found in known accounts" 37 | 38 | cf-dns-domain-del ${CF_ZONE_ID} -------------------------------------------------------------------------------- /modules/dns/bin/cld-cfdnsbackup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Backup DNS zones by API of all your CloudFlare accounts setted up in /var/cld/creds/creds_dns_cf_api_list 4 | Should be setted up for daily cron 5 | EOL 6 | ) 7 | HELP_EXAMPLES=$(cat << 'EOL' 8 | cld-cfdnsbackup 9 | EOL 10 | ) 11 | source /var/cld/bin/include/cldfuncs 12 | [ -e /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F) ] || mkdir -p /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F) 13 | truncate -s 0 /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F)/cf_dns_list 14 | for CFAPI in $(cat /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 15 | do 16 | echo "${CFAPI}" 17 | CFACC=`echo "${CFAPI}" | cut -d "_" -f 1` ; echo $CFACC 18 | CFKEY=`echo "${CFAPI}" | cut -d "_" -f 2` ; echo $CFKEY 19 | curl -sX GET "https://api.cloudflare.com/client/v4/zones?page=1&per_page=1000&order=status&direction=desc&match=all" \ 20 | -H "X-Auth-Email: ${CFACC}" \ 21 | -H "X-Auth-Key: ${CFKEY}" \ 22 | -H "Content-Type: application/json" | jq '.result[] | {name, id}' | grep "name\|id" | sed -e ':a;N;$!ba;s#,\n##g' -e 's#"##g' | sed 's#$#_'${CFACC}'#g' | awk '{print $2"_"$4}' >> /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F)/cf_dns_list 23 | done 24 | 25 | for CFSITE in $(cat /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F)/cf_dns_list ) 26 | do 27 | CFNAME=`echo "$CFSITE" | cut -d "_" -f 1` ; echo $CFNAME 28 | CFID=`echo "$CFSITE" | cut -d "_" -f 2` ; echo $CFID 29 | CFACC=`echo "$CFSITE" | cut -d "_" -f 3` ; echo $CFACC 30 | CFKEY=`grep $CFACC /var/cld/creds/creds_dns_cf_api_list | cut -d "_" -f 2` ; echo $CFKEY 31 | 32 | curl -sX GET "https://api.cloudflare.com/client/v4/zones/${CFID}/dns_records/export" \ 33 | -H "X-Auth-Email: ${CFACC}" \ 34 | -H "X-Auth-Key: ${CFKEY}" \ 35 | -H "Content-Type: application/json" > /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F)/${CFNAME} 36 | done 37 | -------------------------------------------------------------------------------- /modules/dns/bin/cld-cfunderattack: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Utility to check if there is attack for site and enable "under_attack" mode at CloudFlare - output is RPS amount 4 | Can be settet up for cron or to Zabbix as data item with system.run key or ClassicDevOps API by URL 5 | EOL 6 | ) 7 | HELP_ARGS=$(cat << 'EOL' 8 | --domain=example.com Domain name setted up in the web server config 9 | --instance=cloud1_1.2.3.4_22_root CLD instance where this utility whill check access_log 10 | --rps=100 Limit of RPS - higher will considering as attack 11 | --groups=group1,group2 Filtering by instance groups - field can be blank 12 | --accesslog=/var/log/access.log Target access log - default is /var/log/nginx-main-access.log 13 | --logpattern=someword_or_empty Defined pattern for count RPS by it - field can be blank 14 | EOL 15 | ) 16 | HELP_EXAMPLES=$(cat << 'EOL' 17 | cld-cfunderattack --instance=cloud1_1.2.3.4 --domain=example.com --rps=100 --logpattern=/login 18 | EOL 19 | ) 20 | source /var/cld/bin/include/cldfuncs 21 | source /var/cld/modules/dns/bin/include/dnsfuncs 22 | 23 | for i in ${CLDOPTS} 24 | do 25 | case $i in 26 | -d=*|-domain=*|--domain=*) DOMAIN="${i#*=}" ;; 27 | -i=*|-instance=*|--instance=*) VMPATTERN="${i#*=}" ;; 28 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 29 | -r=*|-rps=*|--rps=*) LIMIT_RPS="${i#*=}" ;; 30 | -a=*|-accesslog=*|--accesslog=*) ACCESS_LOG="${i#*=}" ;; 31 | -l=*|-logpattern=*|--logpattern=*) ACCESS_LOG_PATTERN="${i#*=}" ;; 32 | *) ;; 33 | esac 34 | done 35 | 36 | [ "$ACCESS_LOG" ] || export ACCESS_LOG=/var/log/nginx-main-access.log 37 | 38 | VM=$(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" | grep -i "$VMPATTERN" | tail -1) 39 | 40 | INSTANCE_GROUP_FUNCS 41 | 42 | $CLD_VARS 43 | CURRENT_RPS=$($CLD_DEPLOY_NOTTY << EOSSH 44 | timeout 1s tail -n 0 -f ${ACCESS_LOG} | grep "$ACCESS_LOG_PATTERN" > /tmp/${DOMAIN}rps ; cat /tmp/${DOMAIN}rps | wc -l 45 | EOSSH 46 | ) 47 | 48 | for CFAPI in $(cat /var/cld/creds/creds_dns_cf_api_list) 49 | do 50 | cf-dns-api-creds 51 | 52 | CURRENT_MODE=$(cf-underattack-get ${DOMAIN}) 53 | echo $CURRENT_RPS 54 | if [ "${CURRENT_RPS}" -gt "${LIMIT_RPS}" -a "${CURRENT_MODE}" != "under_attack" ] 55 | then 56 | cf-underattack-set $DOMAIN under_attack 1>&2 57 | elif [ "${CURRENT_RPS}" -lt "${LIMIT_RPS}" -a "${CURRENT_MODE}" = "under_attack" ] 58 | then 59 | cf-underattack-set $DOMAIN medium 1>&2 60 | fi 61 | done 62 | -------------------------------------------------------------------------------- /modules/dns/bin/cld-changefront: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Generate command list for massive change of all targeted DNS zones from source ip to new destination ip - checking based on CloudFlare DNS backup files - cf_dns_backup will run before generating commands 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 Source IP address 8 | $2 Destination IP address 9 | EOL 10 | ) 11 | HELP_EXAMPLES=$(cat << 'EOL' 12 | cld-changefront 1.2.3.4 2.3.4.5 13 | EOL 14 | ) 15 | source /var/cld/bin/include/cldfuncs 16 | ARG1=$(echo "${@:1}" | tr ' ' '\n' | grep -v '\--' | head -1) 17 | ARG2=$(echo "${@:1}" | tr ' ' '\n' | grep -v '\--' | head -2 | tail -1) 18 | 19 | ORIGIN_IP=$ARG1 20 | TARGET_IP=$ARG2 21 | 22 | for OPTS in ${@:1} 23 | do 24 | echo $OPTS | grep -q '^\--proxy\|^\-proxy' && CFPROXY="-proxy" 25 | done 26 | 27 | CURR_DATE=$(TZ=Europe/Moscow date +%F) 28 | echo Start DNS zones parsing at all known CloudFlare accounts 29 | /var/cld/modules/dns/bin/cld-cfdnsbackup 1>&2 30 | echo done 31 | echo 32 | 33 | A_RECORD_LIST=$(grep "$ORIGIN_IP" -R /var/cld/modules/dns/data/cf/${CURR_DATE}/ | cut -d : -f 2- | grep -P "\tA\t$ORIGIN_IP" | cut -d A -f 1 | rev | cut -d . -f 2- | rev) 34 | 35 | for A_RECORD in ${A_RECORD_LIST} 36 | do 37 | echo cld-setdns A ${A_RECORD} ${ORIGIN_IP}_${TARGET_IP} ${CFPROXY} 38 | done -------------------------------------------------------------------------------- /modules/dns/bin/cld-deldns: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Delete DNS record from CloudFlare 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 DNS record type 8 | $2 DNS zone - FQDN 9 | $3+ DNS zone content 10 | EOL 11 | ) 12 | HELP_EXAMPLES=$(cat << 'EOL' 13 | cld-deldns a subdomain.example.com 1.2.3.4 14 | EOL 15 | ) 16 | source /var/cld/bin/include/cldfuncs 17 | source /var/cld/modules/dns/bin/include/dnsfuncs 18 | TYPE=${1^^} 19 | DNS_ZONE=${2,,} 20 | MAIN_ZONE=$(echo $DNS_ZONE | rev | cut -d . -f -2 | rev) 21 | CONTENT=${@:3} 22 | 23 | 24 | echo $TYPE | grep -q "^A$\|^AAAA$\|^CNAME$\|^TXT$\|^SRV$\|^LOC$\|^MX$\|^NS$\|^SPF$\|^CERT$\|^DNSKEY$\|^DS$\|^NAPTR$\|^SMIMEA$\|^SSHFP$\|^TLSA$\|^URI$" \ 25 | || echoexit1 "incorrect type - allowed types: A, AAAA, CNAME, TXT, SRV, LOC, MX, NS, SPF, CERT, DNSKEY, DS, NAPTR, SMIMEA, SSHFP, TLSA, URI" 26 | echo $DNS_ZONE | egrep -q "^[a-z0-9.*-]+\.[a-z0-9.-]+$" \ 27 | || echoexit1 "incorrect domain - only full domain names allowed: example.com test.example.com" 28 | [ "$CONTENT" ] || echoexit1 DNS content not defined 29 | 30 | [ "$CONTENT" == "@" ] && CONTENT=$MAIN_ZONE 31 | [ "$NEW_CONTENT" == "@" ] && NEW_CONTENT=$MAIN_ZONE 32 | [ "$CONTENT" == "$NEW_CONTENT" ] && echoexit1 Old and New DNS record content are the same - exit 33 | #[ $CFACC || CFACC=$(grep -s "${MAIN_ZONE}" /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F)/cf_dns_list | head -1 | cut -d _ -f 3) 34 | #[ $CFACC || CFACC=$(grep -s "${MAIN_ZONE}" /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F --date=yesterday)/cf_dns_list | head -1 | cut -d _ -f 3) 35 | [ "$CFACC" ] && CFAPI=$(grep "$CFACC" /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 36 | [ "$CFAPI" ] || for CFAPI in $(cat /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 37 | do 38 | cf-dns-api-creds 39 | CF_ZONE_ID=$(cf-dns-get-zone-id ${MAIN_ZONE}) 40 | [ "${CF_ZONE_ID}" ] && break 41 | done 42 | ( 43 | [ "$CF_ZONE_ID" ] || echoexit1 "domain $MAIN_ZONE not found in known accounts" 44 | 45 | CF_RECORD_RESULT=$(cf-dns-records-get $CF_ZONE_ID | jq ".result[] | select(.type == \"$TYPE\" and .name == \"$DNS_ZONE\" and .content == \"$CONTENT\")") 46 | CF_RECORD_ID=$(echo "${CF_RECORD_RESULT}" | jq -r .id) 47 | CF_RECORD_CONTENT=$(echo "${CF_RECORD_RESULT}" | jq -r .content) 48 | 49 | [ "$CF_RECORD_CONTENT" != "$CONTENT" ] && echoexit1 "Record $TYPE $DNS_ZONE $CONTENT doesn't exist" 50 | 51 | [ "$CF_RECORD_ID" != "" ] && CF_RECORD_DELETE_RESULT=$(cf-dns-record-delete $TYPE $DNS_ZONE $CONTENT | jq -r .success) 52 | [ "$CF_RECORD_ID" != "" -a "$CF_RECORD_DELETE_RESULT" == "true" ] && echo "DNS record $TYPE $DNS_ZONE $CONTENT successfully deleted" 53 | [ "$CF_RECORD_ID" != "" -a "$CF_RECORD_DELETE_RESULT" != "true" ] && echoexit1 "DNS record $TYPE $DNS_ZONE $CONTENT delete error" 54 | ) #| awk -v f="$F" -v b="$B" '{print f$0f}' -------------------------------------------------------------------------------- /modules/dns/bin/cld-dnssync: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | DNS domain name A records synchronizer to ip addresses of filtered istances 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 First PATTERN filtering allowed instances 8 | $2 Second PATTERN filtering allowed instances 9 | $3 Third PATTERN filtering allowed instances 10 | --proxy Set up CloudFlare proxyfying 11 | --cfacc=youracc@at.cf Email of your CloudFlare account - if you have several at /var/cld/creds/creds_dns_cf_api_list 12 | --ttl=60 TTL of DNS records - default is 300 13 | --groups=GROUP1,GROUP2 Filtering by instance groups 14 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to access matrix 15 | EOL 16 | ) 17 | HELP_EXAMPLES=$(cat << 'EOL' 18 | cld-dnssync ^node --domain=app.example.com 19 | cld-dnssync -g=kubenodes -d=app.example.com --proxy 20 | cld-dnssync ^node -g=kube -d=app.example.com -p 21 | EOL 22 | ) 23 | 24 | source /var/cld/bin/include/cldfuncs 25 | 26 | for i in ${CLDOPTS} 27 | do 28 | case $i in 29 | -d=*|-domain=*|--domain=*) DOMAIN="${i#*=}" ;; 30 | -c=*|-cfacc=*|--cfacc=*) CFACC="${i#*=}" ;; 31 | -p|-proxy|--proxy) CFPROXY=1 ;; 32 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 33 | -t=*|-ttl=*|--ttl=*) DNS_TTL="${i#*=}" ;; 34 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 35 | -*) ;; 36 | *) let ii++; declare ARG$ii=${i} ;; 37 | esac 38 | done 39 | 40 | [ "${DOMAIN}" ] || { echo DOMAIN is not defined - exit ; exit 1 ; } 41 | 42 | echo DNS records synchronizing 43 | DOMAIN_DNS_IPS=$(/var/cld/modules/dns/bin/cld-getdns $DOMAIN | grep "^A" | awk '{print $3}') 44 | 45 | DOMAIN_INSTANCES=$(CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" "$ARG1" "$ARG2" "$ARG3" "$CLD_ALL_GROUPS_ARG") 46 | 47 | DOMAIN_INSTANCE_IPS=$(cut -d _ -f 2 <<< "${DOMAIN_INSTANCES}" | sort -u) 48 | 49 | DOMAIN_DNS_IPS_FOR_DELETE=$(if [ "${DOMAIN_INSTANCE_IPS}" ] 50 | then 51 | echo "${DOMAIN_DNS_IPS}" | grep -v "${DOMAIN_INSTANCE_IPS}" 52 | else 53 | echo "${DOMAIN_DNS_IPS}" 54 | fi 55 | ) 56 | 57 | for DOMAIN_DNS_IP_FOR_DELETE in ${DOMAIN_DNS_IPS_FOR_DELETE} 58 | do 59 | /var/cld/modules/dns/bin/cld-deldns a ${DOMAIN} ${DOMAIN_DNS_IP_FOR_DELETE} 60 | done 61 | 62 | DOMAIN_DNS_IPS_FOR_ADD=$(if [ "${DOMAIN_DNS_IPS}" ] 63 | then 64 | echo "${DOMAIN_INSTANCE_IPS}" | grep -v "${DOMAIN_DNS_IPS}" 65 | else 66 | echo "${DOMAIN_INSTANCE_IPS}" 67 | fi 68 | ) 69 | 70 | for DOMAIN_DNS_IP_FOR_ADD in ${DOMAIN_DNS_IPS_FOR_ADD} 71 | do 72 | /var/cld/modules/dns/bin/cld-setdns a ${DOMAIN} ${DOMAIN_DNS_IP_FOR_ADD} -force $([ "$CFPROXY" = "1" ] && echo "--proxy") $([ "$CFACC" ] && echo "--cfacc=${CFACC}") 73 | done 74 | 75 | echo DNS records: 76 | /var/cld/modules/dns/bin/cld-getdns $DOMAIN -------------------------------------------------------------------------------- /modules/dns/bin/cld-domain: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Get information filtering by domain name - based on classicdevops DNS backup information 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 FQDN 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-domain example.com 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | grep --color=always -s "^$1" /var/cld/modules/dns/data/{cf,ibs}/`TZ=Europe/Moscow date +%F`/{cf,ibs}_dns_list 16 | tail -n 999 /var/cld/modules/dns/data/{cf,ibs}/`TZ=Europe/Moscow date +%F`/*$1* 2>/dev/null | grep -v "\;\;" | ack --color --passthru $1 | less -R | cat 17 | -------------------------------------------------------------------------------- /modules/dns/bin/cld-geo: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Return json of geo information for IP address or FQDN - using for ip-api.com service 4 | Note: it have limit of free requests 5 | EOL 6 | ) 7 | HELP_ARGS=$(cat << 'EOL' 8 | $1 IP address or FQDN 9 | EOL 10 | ) 11 | HELP_EXAMPLES=$(cat << 'EOL' 12 | cld-geo 1.2.3.4 13 | cld-geo example.com 14 | EOL 15 | ) 16 | source /var/cld/bin/include/cldfuncs 17 | source /var/cld/modules/dns/bin/include/dnsfuncs 18 | DNS_ZONE=${1,,} 19 | 20 | echo $DNS_ZONE | egrep -q "^[a-z0-9.:-]+$" \ 21 | || echoexit1 "incorrect ip or domain - only ip or full domain names allowed: example.com or 1.2.3.4" 22 | 23 | wget -qO- http://ip-api.com/json/${DNS_ZONE} | jq . | sed -e 's#\\n#\n#g' -e 's#\\r##g' | grep -v "%" #| awk -v f="$F" -v b="$B" '{print f$0f}' -------------------------------------------------------------------------------- /modules/dns/bin/cld-getdns: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Get DNS record information from CloudFlare 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 DNS zone - FQDN 8 | $2 DNS zone content - Empty or "ALL" 9 | EOL 10 | ) 11 | HELP_EXAMPLES=$(cat << 'EOL' 12 | cld-getdns subdomain.example.com 13 | cld-getdns subdomain.example.com all 14 | EOL 15 | ) 16 | source /var/cld/bin/include/cldfuncs 17 | source /var/cld/modules/dns/bin/include/dnsfuncs 18 | DNS_ZONE=${1,,} 19 | MAIN_ZONE=$(echo $DNS_ZONE | rev | cut -d . -f -2 | rev) 20 | CONTENT=$(echo $2 | cut -d _ -f 1) 21 | 22 | echo $DNS_ZONE | egrep -q "^[a-z0-9.*-]+\.[a-z0-9.-]+$" \ 23 | || echoexit1 "incorrect domain - only full domain names allowed: example.com test.example.com" 24 | 25 | [ "$CONTENT" == "@" ] && CONTENT=$MAIN_ZONE 26 | [ "$NEW_CONTENT" == "@" ] && NEW_CONTENT=$MAIN_ZONE 27 | #[ $CFACC || CFACC=$(grep -s "${MAIN_ZONE}" /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F)/cf_dns_list | head -1 | cut -d _ -f 3) 28 | #[ $CFACC || CFACC=$(grep -s "${MAIN_ZONE}" /var/cld/modules/dns/data/cf/$(TZ=Europe/Moscow date +%F --date=yesterday)/cf_dns_list | head -1 | cut -d _ -f 3) 29 | [ "$CFACC" ] && { 30 | CFAPI=$(grep "$CFACC" /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 31 | cf-dns-api-creds 32 | CF_ZONE_ID=$(cf-dns-get-zone-id ${MAIN_ZONE}) 33 | } 34 | [ "$CFAPI" ] || for CFAPI in $(cat /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 35 | do 36 | cf-dns-api-creds 37 | CF_ZONE_ID=$(cf-dns-get-zone-id ${MAIN_ZONE}) 38 | [ "${CF_ZONE_ID}" ] && break 39 | done 40 | ( 41 | [ "$CF_ZONE_ID" ] || echoexit1 "domain $MAIN_ZONE not found in known accounts" 42 | 43 | [ "$CONTENT" == "all" -o "$CONTENT" == "-all" ] && cf-dns-records-get $CF_ZONE_ID | jq -r ".result[] | [.type,.name,.content,.proxied]|@tsv" 44 | [ "$CONTENT" != "" -a "$CONTENT" != "all" ] && cf-dns-records-get $CF_ZONE_ID | jq -r ".result[] | select(.content == \"$CONTENT\") | [.type,.name,.content,.proxied]|@tsv" 45 | [ "$CONTENT" == "" ] && cf-dns-records-get $CF_ZONE_ID | jq -r ".result[] | select(.name == \"$DNS_ZONE\") | [.type,.name,.content,.proxied]|@tsv" 46 | ) | sed -r -e 's#\tfalse$##g' -e 's#\ttrue$# proxied#g' #| awk -v f="$F" -v b="$B" '{print f$0f}' -------------------------------------------------------------------------------- /modules/dns/bin/cld-getip: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Get information filtering by IP address - based on ClassicDevOps instance lists and DNS backup infromation 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 IP address 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-getip 1.2.3.4 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | source /var/cld/modules/dns/bin/include/dnsfuncs 16 | CHECKIP=$(echo "$1" | egrep -o "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"\|"all") 17 | test $CHECKIP || echoexit1 incorrect ip address 18 | 19 | [ "$SUDO_USER" = "" ] && SUDO_USER=admin 20 | 21 | test "$CHECKIP" == "all" && ( 22 | echo Instances info: 23 | CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" | cut -d : -f 2- | cut -d _ -f -2 | sed 's#_# - #g' 24 | ) | awk '{print "`"$0"`"}' 25 | 26 | test "$CHECKIP" != "all" && ( 27 | echo Instance info: 28 | CLOUDS_USER_ALLOWED --groups="${CLD_GROUPS}" | grep "$CHECKIP" /var/cld/access/groups/*/clouds | cut -d : -f 2- | cut -d _ -f -2 | sed 's#_# - #g' 29 | echo 30 | echo DNS info: 31 | grep "$CHECKIP" -R /var/cld/modules/dns/data/cf/`TZ=Europe/Moscow date +%F`/ | cut -d : -f 2- 32 | ) #| awk -v f="$F" -v b="$B" '{print f$0f}' -------------------------------------------------------------------------------- /modules/dns/bin/cld-getns: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Get NS information from CloudFlare 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 DNS zone - FQDN 8 | --cfacc=youracc@at.cf Email of your CloudFlare account - if you have several at /var/cld/creds/creds_dns_cf_api_list 9 | EOL 10 | ) 11 | HELP_EXAMPLES=$(cat << 'EOL' 12 | cld-getns example.com 13 | cld-getns example.com --cfacc=user@example.com 14 | EOL 15 | ) 16 | source /var/cld/bin/include/cldfuncs 17 | source /var/cld/modules/dns/bin/include/dnsfuncs 18 | 19 | for i in ${CLDOPTS} 20 | do 21 | case $i in 22 | -c=*|-cfacc=*|--cfacc=*) CFACC="${i#*=}" ;; 23 | -*) ;; 24 | *) let ii++; declare ARG$ii=${i} ;; 25 | esac 26 | done 27 | 28 | DNS_ZONE=${ARG1,,} 29 | MAIN_ZONE=$(echo $DNS_ZONE | rev | cut -d . -f -2 | rev) 30 | 31 | echo $DNS_ZONE | egrep -q "^[a-z0-9.*-]+\.[a-z0-9.-]+$" \ 32 | || echoexit1 "incorrect domain - only full domain names allowed: example.com test.example.com" 33 | 34 | [ "$CFACC" ] && { 35 | CFAPI=$(grep "$CFACC" /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 36 | cf-dns-api-creds 37 | CF_ZONE_ID=$(cf-dns-get-zone-id ${MAIN_ZONE}) 38 | } 39 | [ "$CFAPI" ] || for CFAPI in $(cat /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 40 | do 41 | cf-dns-api-creds 42 | CF_ZONE_ID=$(cf-dns-get-zone-id ${MAIN_ZONE}) 43 | [ "${CF_ZONE_ID}" ] && break 44 | done 45 | 46 | [ "$CF_ZONE_ID" ] || echoexit1 "domain $MAIN_ZONE not found in known accounts" 47 | 48 | cf-dns-zone-details ${CF_ZONE_ID} | jq '.result | {Domain: .name, Status: .status, Target_NS: .name_servers, Original_NS: .original_name_servers} | if .Status == "active" then {Domain: .Domain, Status: .Status, Target_NS: .Target_NS} else {Domain: .Domain, Status: .Status, Target_NS: .Target_NS, Original_NS: .Original_NS} end' -------------------------------------------------------------------------------- /modules/dns/bin/cld-listdns: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | List all domains at your CloudFlare accounts 4 | EOL 5 | ) 6 | HELP_EXAMPLES=$(cat << 'EOL' 7 | cld-listdns 8 | EOL 9 | ) 10 | source /var/cld/bin/include/cldfuncs 11 | source /var/cld/modules/dns/bin/include/dnsfuncs 12 | DNS_ZONE=${1,,} 13 | MAIN_ZONE=$(echo $DNS_ZONE | rev | cut -d . -f -2 | rev) 14 | 15 | for CFAPI in $(cat /var/cld/creds/creds_dns_cf_api_list | grep -v "^#") 16 | do 17 | cf-dns-api-creds 18 | cf-dns-get-zone ${MAIN_ZONE} 19 | done | grep "${MAIN_ZONE}" | tr -s ' ' | column -t #| awk -v f="$F" -v b="$B" '{print f$2f}' -------------------------------------------------------------------------------- /modules/dns/bin/cld-whois: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Return json of whois information for FQDN - using for api.whois.vu service 4 | Note: it have limit of free requests 5 | EOL 6 | ) 7 | HELP_ARGS=$(cat << 'EOL' 8 | $1 FQDN 9 | -i/-exp/--expire Show domain expire information only 10 | EOL 11 | ) 12 | HELP_EXAMPLES=$(cat << 'EOL' 13 | cld-whois example.com 14 | EOL 15 | ) 16 | source /var/cld/bin/include/cldfuncs 17 | source /var/cld/modules/dns/bin/include/dnsfuncs 18 | 19 | for i in ${CLDOPTS} 20 | do 21 | case $i in 22 | -e|-exp|-expire|--exp|--expire) EXPIRE=1 ;; 23 | *) ;; 24 | esac 25 | done 26 | 27 | ARG1=$(echo "${@:1}" | tr ' ' '\n' | grep -v '\--' | head -1) 28 | 29 | DNS_ZONE=${ARG1,,} 30 | MAIN_ZONE=$(echo $DNS_ZONE | rev | cut -d . -f -2 | rev) 31 | CONTENT=$(echo $2 | cut -d _ -f 1) 32 | 33 | echo $DNS_ZONE | egrep -q "^[a-z0-9.*-]+\.[a-z0-9.-]+$" \ 34 | || echoexit1 "incorrect domain - only full domain names allowed: example.com test.example.com" 35 | 36 | if [ "$EXPIRE" ] 37 | then 38 | EXPIRE_TIMESTAMP=$(wget -qO- "http://api.whois.vu/?q=${MAIN_ZONE}&clean" | jq .expires) 39 | cat << EOL | jq . 40 | { 41 | "Expire days": $(echo $EXPIRE_TIMESTAMP $(date +%s) | awk '{print ($1-$2)/60/60/24}' | cut -d . -f 1), 42 | "Expire date": "$(date +%F --date=@$EXPIRE_TIMESTAMP)", 43 | "Expire timestamp": $EXPIRE_TIMESTAMP 44 | } 45 | EOL 46 | else 47 | wget -qO- "http://api.whois.vu/?q=${MAIN_ZONE}&clean" | jq . | sed -e 's#\\n#\n#g' -e 's#\\r##g' | grep -v "%" | tr '\n' '№' | awk -F 'Last update' '{print $1}' | tr '№' '\n' | grep -v '>>>' #| awk -v f="$F" -v b="$B" '{print f$0f}' 48 | fi -------------------------------------------------------------------------------- /modules/dns/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /var/cld/bin/include/cldfuncs 3 | 4 | if grep -q "^CLOUDFLARE=" /var/cld/creds/creds 5 | then 6 | echo -n "" 7 | else 8 | echo "Are you using CLOUDFLARE ?" 9 | select ANSWER in yes no 10 | do 11 | if [ "${ANSWER}" == "yes" ] 12 | then 13 | CFAPI=$(cat /var/cld/creds/creds_dns_cf_api_list 2>/dev/null) 14 | [ "$CFAPI" ] || init-string 'CFACC|mymail@atcloud.flare|[A-Za-z0-9@.-]+' 'CFKEY|y0urcf4pi70keny0urcf4pi70keny0urcf4pi|[a-z0-9]{37}' 'CF_ACC_ID|y0urcfaccidy0urcfaccidy0urcfacci|[a-z0-9]{32}' --file=/var/cld/creds/creds_dns_cf_api_list 15 | echo CLOUDFLARE=1 >> /var/cld/creds/creds 16 | break 17 | elif [ "${ANSWER}" == "no" ] 18 | then 19 | echo CLOUDFLARE=0 >> /var/cld/creds/creds 20 | break 21 | fi 22 | done 23 | fi 24 | 25 | -------------------------------------------------------------------------------- /modules/doc/README.md: -------------------------------------------------------------------------------- 1 | Module for automatic generation of documentation consisting of`README.md`files and help output of all `cld*` utilities: 2 | - OpenApi specification is generated by script `/var/cld/modules/doc/doc.py` 3 | - Generation is done automatically each time the command `cld-update` is executed 4 | - A copy of this documentation with an up-to-date example of the domain for the Web and the API interface is available in the Web interface of each copy of a CLD at `https://your.cld.domain/doc` -------------------------------------------------------------------------------- /modules/doc/bin/cld-docpublicgen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Public documentation generation tool 4 | Clean CLD repo documentation will be able at https://cld.yourdomain.com/documentation/ 5 | EOL 6 | ) 7 | HELP_EXAMPLES=$(cat << 'EOL' 8 | cld-docpublicgen 9 | EOL 10 | ) 11 | source /var/cld/bin/include/cldfuncs 12 | python3 /var/cld/modules/doc/doc-common.py 13 | mkdir -p /var/www/cld/doc/ &>/dev/null 14 | rm -rf /var/www/cld/doc/* 15 | mkdir -p /var/www/cld/doc/{doc,img} 16 | mkdir -p /var/www/cld/doc/modules/doc/content/ 17 | cp /var/cld/web/img/cld_h.svg /var/www/cld/doc/img/ 18 | cp /var/cld/modules/doc/web/doc.html /var/www/cld/doc/index.html 19 | cp /var/cld/modules/doc/data/doc-common.json /var/www/cld/doc/doc/doc.json 20 | cp /var/cld/modules/doc/web/content/doc.css /var/www/cld/doc/modules/doc/content/ 21 | -------------------------------------------------------------------------------- /modules/doc/bin/cld-tgcmdgen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Telegram bot commands description generator 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | --show Just get stored commands from telegram bot api 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-tgcmdgen 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | init-load-constants TELEGRAM_BOT_TOKEN\|1234567890:AAEzBFqFii-uirfyG3PnygA0DAvJvRH7UzB 16 | 17 | for i in ${CLDOPTS} 18 | do 19 | case $i in 20 | -s|-show|--show) SHOW=1 ;; 21 | *) ;; 22 | esac 23 | done 24 | 25 | if [ "$SHOW" = "1" ] 26 | then 27 | curl -s https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMyCommands | jq . 28 | else 29 | curl -s --request POST \ 30 | --url https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/setMyCommands \ 31 | --header 'Content-Type: application/json' \ 32 | --data "{\"commands\":$(cat /var/cld/modules/doc/data/doc.json | jq '.paths | .[].options | select(."x-codeSamples"[].lang == "BOT") | {'command': .summary, 'description': ("/" + .summary + " -h [show help] | " + .description)}' | sed -e 's#\\n.*#"#g' | sed -e 's# "#"#g' -e 's#""#"None"#g' -e 's#cld-##g' -e 's#myipbot#myip#g' -e 's#myvpnbot#myvpn#g' | jq -c . | tr -d '\n' | sed 's#}{#},{#g' | cat <(echo [) - <(echo ]) | jq .)}" 33 | fi -------------------------------------------------------------------------------- /modules/doc/web.py: -------------------------------------------------------------------------------- 1 | webmodule["doc"] = {} 2 | webmodule["doc"]["homename"] = "Documentation" 3 | webmodule["doc"]["desc"] = "CLD handbook" 4 | @app.route("/doc") 5 | def doc_index(): 6 | if 'username' in session: 7 | user = session['username'] 8 | checkresult = checkpermswhiteip(cldmodule, 'NOTOOL', user, remoteaddr()) 9 | if checkresult[0] != "granted": return Response("403", status=403, mimetype='application/json') 10 | return render_template('modules/doc/doc.html') 11 | else: 12 | return redirect('/login', code=302) 13 | 14 | @app.route("/doc/doc.json") 15 | def doc_spec(): 16 | if 'username' in session: 17 | user = session['username'] 18 | checkresult = checkpermswhiteip(cldmodule, 'NOTOOL', user, remoteaddr()) 19 | if checkresult[0] != "granted": return Response("403", status=403, mimetype='application/json') 20 | if os.path.isfile('/var/cld/modules/doc/data/doc.json') != True: 21 | bash('python3 /var/cld/modules/doc/doc.py &>/dev/null') 22 | return Response(open('/var/cld/modules/doc/data/doc.json', 'r').read(), status=200, mimetype='application/json') 23 | else: 24 | return redirect('/login', code=302) -------------------------------------------------------------------------------- /modules/doc/web/doc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CLD - Documentation 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /modules/filemanager/README.md: -------------------------------------------------------------------------------- 1 | File manager module in the web interface for administrators. 2 | 3 | The file manager module allows you to access editing and saving files not only on the CLD server, but also on instances under its control. Access to files is completely safe, reliably protected and extremely convenient. Files are edited through the user's browser; for the convenience of work, a simple and convenient editor with syntax highlighting is used. After editing, you can save the changes made also through the web interface. 4 | In addition, the functionality of the file manager module includes: 5 | - Ability to create new files with the necessary content directly from the user's browser. 6 | - A useful functionality is also the ability to access the file systems of instances managed by the CLD. You can edit files on any of the instances that are controlled by the CLD, the logic of work allows you to make edits on all instances, create files and view the content. 7 | - Also, the functionality of the file manager module allows you to delete not only files created by the user, but also to delete existing files on the server. 8 | 9 | Initial variables are not required for the file manager module. 10 | -------------------------------------------------------------------------------- /modules/infraconfig/README.md: -------------------------------------------------------------------------------- 1 | The **infraconfig** module collects basic configuration information from remote instances. 2 | 3 | ### Usage 4 | ``` 5 | cld-infraconfig [PATTERN1] [PATTERN2] [PATTERN3] [options] 6 | ``` 7 | Options: 8 | - `--groups=GROUP1,GROUP2` – filter instances by groups. 9 | - `--dirs=/etc,/path` – comma separated list of directories to copy from each instance (default `/etc`). 10 | - `--commit` – after collecting data commit changes to the CLD git repository. The commit message is generated by OpenAI GPT‑4.1‑mini using the diff. 11 | - `--all` – admin option to search instances across all groups. 12 | 13 | Collected files are stored under `/var/cld/modules/infraconfig/data/instances/INSTANCE/`. 14 | 15 | ### Custom commands and directories 16 | The module looks for optional files under `modules/infraconfig/data` to adjust what 17 | is collected: 18 | 19 | - `data/instances//dirs` – newline separated directories to copy 20 | - `data/instances//commands` – shell commands executed on the instance 21 | - `data/groups//dirs` and `data/groups//commands` work the same for groups. 22 | 23 | If no custom files are found the script copies `/etc` and runs a default command 24 | set (`netstat -plunt`, `nproc`, `free -h`, `df -h`). 25 | 26 | ### OpenAI integration 27 | Run `modules/infraconfig/init` once to store your OpenAI API key in the 28 | `/var/cld/creds/creds` file as `OPENAI_API_KEY`. When `--commit` is 29 | used, `cld-infraconfig` will call the OpenAI API to create a concise 30 | commit message from the staged diff. 31 | -------------------------------------------------------------------------------- /modules/infraconfig/data/groups/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/modules/infraconfig/data/groups/.gitkeep -------------------------------------------------------------------------------- /modules/infraconfig/data/instances/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/modules/infraconfig/data/instances/.gitkeep -------------------------------------------------------------------------------- /modules/infraconfig/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /var/cld/bin/include/cldfuncs 3 | init-load-constants OPENAI_API_KEY\|sk-your-openai-api-key 4 | mkdir -p /var/cld/modules/infraconfig/data/groups /var/cld/modules/infraconfig/data/instances 5 | -------------------------------------------------------------------------------- /modules/infraconfig/web.py: -------------------------------------------------------------------------------- 1 | webmodule["infraconfig"] = {} 2 | webmodule["infraconfig"]["homename"] = "Infra config" 3 | webmodule["infraconfig"]["desc"] = "Collect instance configuration" 4 | 5 | @app.route("/infraconfig") 6 | def infraconfig_index(): 7 | if 'username' in session: 8 | if userisadmin(session['username']) != True: 9 | session.pop('username', None) 10 | return redirect('/', code=302) 11 | user = session['username'] 12 | checkresult = checkpermswhiteip(cldmodule, 'NOTOOL', user, remoteaddr()) 13 | if checkresult[0] != "granted": return Response("403", status=403, mimetype='application/json') 14 | os.makedirs('/var/cld/modules/infraconfig/data', mode = 0o700, exist_ok=True) 15 | bash('''[ -d /var/cld/modules/infraconfig/data/groups ] || mkdir -p /var/cld/modules/infraconfig/data/groups ; [ -d /var/cld/modules/infraconfig/data/instances ] || mkdir -p /var/cld/modules/infraconfig/data/instances''') 16 | instances_files = path_to_dict('/var/cld/modules/infraconfig/data/instances') 17 | groups_files = path_to_dict('/var/cld/modules/infraconfig/data/groups') 18 | configs = {"instances": instances_files, "groups": groups_files} 19 | cld_instances = bash('sudo -u '+vld(user)+' sudo FROM=CLI /var/cld/bin/cld --list --all').split('\n') 20 | cld_groups = [os.path.basename(name) for name in os.listdir('/var/cld/access/groups/') if os.path.isdir('/var/cld/access/groups/'+name)] 21 | return render_template('modules/infraconfig/infraconfig.html', username=user, cld_instances=cld_instances, cld_groups=cld_groups, configs=configs) 22 | 23 | 24 | -------------------------------------------------------------------------------- /modules/kubernetes/README.md: -------------------------------------------------------------------------------- 1 | CLD integration with Kubernetes for convenient management of multiple clusters and deploy accesslist to ingress Nginx config map 2 | 3 | Additional functionality of the module is under development 4 | 5 | Below is a list of the Kubernetes module initial variables. 6 | 7 | | Variable | Description | 8 | | :------- | :----------- | 9 | | KUBERNETES | variable responsible for initializing the Kubernetes module. | 10 | | MASTER_INSTANCE | CLD instance string of kubernetes cluster master instance | 11 | | CLUSTER_NAME | Kubernetes cluster custom name as cluster id in CLD | -------------------------------------------------------------------------------- /modules/kubernetes/bin/cld-kubeaccesslistdeploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | CLD kubernetes access list deploy to ingress config map 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | --cluster=kubeprod Kubernetes cluster name - default is current 8 | --map=nginx-ingress Config map name - default is "nginx-ingress-ingress-nginx-controller" 9 | --namespace=default Kubernetes namespace - default is "default" 10 | --key=whitelist-source-range Name of the key in config map - default is "whitelist-source-range" 11 | --groups=group1,group2 Filtering access list by instance groups default is all allowed to user 12 | --all Admin user option - setting up for one time run with all groups existing at CLD server regardless to access matrix 13 | EOL 14 | ) 15 | HELP_EXAMPLES=$(cat << 'EOL' 16 | cld-kubeaccesslistdeploy 17 | cld-kubeaccesslistdeploy --cluster=kubeprod --configmap=nginx-ingress --namespace=cld --groups=default,kubeprod,kubedev 18 | EOL 19 | ) 20 | 21 | source /var/cld/bin/include/cldfuncs 22 | 23 | for i in ${CLDOPTS} 24 | do 25 | case $i in 26 | -c=*|-cluster=*|--cluster=*) CLUSTER_NAME="${i#*=}" ;; 27 | -m=*|-map=*|--map=*) CONFIG_MAP="${i#*=}" ;; 28 | -n=*|-namespace=*|--namespace=*) NAMESPACE="${i#*=}" ;; 29 | -k=*|-key=*|--key=*) KEY_NAME="${i#*=}" ;; 30 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 31 | -a|-all|--all) CLD_ALL_GROUPS_ARG="--all" ;; 32 | -*) ;; 33 | *) let ii++; declare ARG$ii=${i} ;; 34 | esac 35 | done 36 | 37 | if [ "${CLUSTER_NAME}" ]; then 38 | CLUSTER_EXIST=$(grep -q -s ",${CLUSTER_NAME}$" /var/cld/modules/kubernetes/data/clustersets && echo 1 || echo 0) 39 | [ "${CLUSTER_EXIST}" = "1" ] && CLUSTER_CONFIG="/var/cld/modules/kubernetes/data/kubectlconfig/${CLUSTER_NAME}" 40 | else 41 | CLUSTER_CONFIG="$(readlink -e /root/.kube/config)" 42 | CLUSTER_NAME=$(basename ${CLUSTER_CONFIG}) 43 | fi 44 | 45 | CLUSTER_CONFIG_CHECK=$(grep -s -q "apiVersion" /var/cld/modules/kubernetes/data/kubectlconfig/${CLUSTER_NAME} && echo 1 || echo 0) 46 | 47 | [ "${CLUSTER_CONFIG}" != "" -a "${CLUSTER_CONFIG_CHECK}" = "1" ] || { echo Cluster not exist - use cld-kubecluster to check cluster set and try again - exit ; exit 1 ; } 48 | 49 | CONFIG_MAP=${CONFIG_MAP:-nginx-ingress-ingress-nginx-controller} 50 | NAMESPACE=${NAMESPACE:-default} 51 | KEY_NAME=${KEY_NAME:-whitelist-source-range} 52 | ACCESS_LIST="$(/var/cld/modules/access/bin/cld-accesslist --groups=${CLD_GROUPS} ${CLD_ALL_GROUPS_ARG} --cidr --noinfo | head -c -1 | tr -d ' ' | tr '\n' ',')" 53 | 54 | [ "$ACCESS_LIST" ] || { echo access list is not defined - use cld-accesslist to check it - exit ; exit 1 ; } 55 | 56 | kubectl patch configmap/${CONFIG_MAP} -n ${NAMESPACE} --kubeconfig=${CLUSTER_CONFIG} --type merge -p "$(cat << EOL | sort -u 57 | {"data":{"${KEY_NAME}":"${ACCESS_LIST}"}} 58 | EOL 59 | )" -------------------------------------------------------------------------------- /modules/kubernetes/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /var/cld/bin/include/cldfuncs 3 | 4 | if ! grep -q "^KUBERNETES=" /var/cld/creds/creds 5 | then 6 | echo "Are you using KUBERNETES ?" 7 | select ANSWER in yes no 8 | do 9 | if [ "${ANSWER}" == "yes" ] 10 | then 11 | /var/cld/modules/kubernetes/bin/cld-kubecluster --new && echo KUBERNETES=1 >> /var/cld/creds/creds || echo skipped - you can try again cld-kubecluster tool to add exist cluster or cld-initmain to run this question again 12 | break 13 | elif [ "${ANSWER}" == "no" ] 14 | then 15 | echo KUBERNETES=0 >> /var/cld/creds/creds 16 | break 17 | fi 18 | done 19 | fi -------------------------------------------------------------------------------- /modules/note/README.md: -------------------------------------------------------------------------------- 1 | Secure script storage 2 | Module based on Web and API interfaces 3 | Provides the following functionality: 4 | - Create quick notes 5 | - Editing with syntax highlighting right in the browser 6 | - Secure access to files by generated link using a hash 7 | - Recursive filtering search by keywords -------------------------------------------------------------------------------- /modules/note/api.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | @app.route("/all/note//") 3 | def note_get_file(note, file): 4 | apihash = request.args['hash'] 5 | for line in open('/var/cld/creds/passwd').read().strip().split('\n'): 6 | token = line.split(':')[2] 7 | checkhash = hashlib.md5(str(note+file+token).encode('utf-8')).hexdigest() 8 | if checkhash == apihash: 9 | user = line.split(':')[0] 10 | break 11 | try: user 12 | except: return Response("404", status=403, mimetype='text/plain') 13 | checkresult = checkperms(cldmodule, "NONE", token) 14 | if checkresult[0] != "granted": return Response("403", status=403, mimetype='text/plain') 15 | user = userbytoken(checkresult[1]) 16 | if os.path.isfile('/var/cld/modules/note/data/'+note+'/'+file): 17 | return Response(open('/var/cld/modules/note/data/'+note+'/'+file).read(), status=200, mimetype='text/plain') 18 | else: 19 | return Response(note.capitalize()+" not found", status=404, mimetype='text/plain') -------------------------------------------------------------------------------- /modules/note/bin/cld-note: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Recursive filtering search around files in notes 4 | Output is list of matched files 5 | EOL 6 | ) 7 | HELP_ARGS=$(cat << 'EOL' 8 | $1-$20 Patterns for recursive filtering 9 | --json JSON output 10 | --beauty Using together with --json option to beautify json output 11 | EOL 12 | ) 13 | HELP_EXAMPLES=$(cat << 'EOL' 14 | cld-note watch mysql process 15 | EOL 16 | ) 17 | source /var/cld/bin/include/cldfuncs 18 | 19 | for i in ${CLDOPTS} 20 | do 21 | case $i in 22 | -j|-json|--json) JSON=1 ;; 23 | -b|-beauty|--beauty) JSON_BEAUTY=1 ;; 24 | *) ;; 25 | esac 26 | done 27 | 28 | CUT_ARG=' | cut -d / -f7' 29 | 30 | [ "$JSON" == "1" ] && JSON_ARG=$(cat << 'EOL' 31 | | jq -R -s -c 'split("\n")[:-1]' 32 | EOL 33 | ) 34 | [ "$JSON_BEAUTY" == "1" -a "$FROM" == "API" ] && JSON_BEAUTY_ARG=' | jq . -C' 35 | [ "$JSON_BEAUTY" == "1" -a "$FROM" != "API" ] && JSON_BEAUTY_ARG=' | jq .' 36 | 37 | ARG_LIST=$(echo ${@:1} | tr ' ' '\n' | grep -v '^\-') 38 | [ "$ARG_LIST" ] || ARG_LIST='.' 39 | 40 | itter=1 41 | source <(for ARG in ${ARG_LIST} 42 | do 43 | if [ "$itter" = "1" ] 44 | then 45 | echo -n grep -Rlim 1 "$ARG" /var/cld/modules/note/data/ 46 | else 47 | echo -n ' |' xargs -I ^ grep -lim 1 "$ARG" ^ 48 | fi 49 | let itter++ 50 | done 51 | echo -n ${CUT_ARG} ${JSON_ARG} ${JSON_BEAUTY_ARG} 52 | ) -------------------------------------------------------------------------------- /modules/note/web/content/note.css: -------------------------------------------------------------------------------- 1 | #searchInput { 2 | background-position: 10px 12px; 3 | background-repeat: no-repeat; 4 | width: 95%; 5 | font-size: 14px; 6 | padding: 5px 5px 5px 8px; 7 | border: 1px solid #1e88e5; 8 | margin-bottom: 12px; 9 | } 10 | 11 | #ServerListUl li a { 12 | border: 1px solid #1e88e5; 13 | margin: 0px; 14 | background-color: white; 15 | padding: 0px; 16 | padding-left: 4px; 17 | text-decoration: none; 18 | display: block; 19 | font-size: 14; 20 | color: lightslategray; 21 | border-right-width: 0; 22 | border-left-width: 0; 23 | border-bottom-width: 0; 24 | } -------------------------------------------------------------------------------- /modules/spamcheck/README.md: -------------------------------------------------------------------------------- 1 | Allows you to check the presence of IP addresses in more than 100 spam lists -------------------------------------------------------------------------------- /modules/spamcheck/bin/cld-spamchecker: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Utility to check all instances addresses if there is in spam lists 4 | EOL 5 | ) 6 | HELP_EXAMPLES=$(cat << 'EOL' 7 | cld-spamchecker 8 | EOL 9 | ) 10 | 11 | ARG1=$(echo "${@:1}" | tr ' ' '\n' | grep -v '\--' | head -1) 12 | ARG2=$(echo "${@:1}" | tr ' ' '\n' | grep -v '\--' | head -2 | tail -1) 13 | ARG3=$(echo "${@:1}" | tr ' ' '\n' | grep -v '\--' | head -3 | tail -1) 14 | 15 | for i in ${CLDOPTS} 16 | do 17 | case $i in 18 | -g=*|-groups=*|--groups=*) CLD_GROUPS="${i#*=}" ;; 19 | *) ;; 20 | esac 21 | done 22 | 23 | source /var/cld/bin/include/cldfuncs 24 | [ "$SUDO_USER" ] || SUDO_USER=admin 25 | [ "$CLD_GROUPS" ] || CLD_GROUPS=default 26 | truncate -s 0 /tmp/spamlisted 27 | for VM in $(CLOUDS_USER_ALLOWED --group=${CLD_GROUPS} | grep -i "$ARG1" | grep -i "$ARG2" | grep -i "$ARG3") 28 | do 29 | CLD_LOGS 30 | if [ "$VM" = "" ] ; then 31 | echo "you choosed incorrect VM, please try again and type numbers only" 32 | else 33 | GROUP=$(grep -l $VM /var/cld/access/groups/*/clouds | cut -d '/' -f 6) 34 | if [ "$GROUP" = "" ] ; then sleep 1s; GROUP=$(grep -l $VM /var/cld/access/groups/*/clouds | cut -d '/' -f 6) ; fi 35 | if [ "$GROUP" = "" ] ; then echo "$VM have incorrect GROUP" ; continue ; fi 36 | if grep -qs "1" /var/cld/access/groups/${GROUP}/funcs 37 | then 38 | source <(for GROUPFUNC in funcvars 39 | do 40 | echo "${GROUP}_${GROUPFUNC}(){" 41 | cat /var/cld/access/groups/${GROUP}/${GROUPFUNC} 42 | echo '}' 43 | done) 44 | CLD_VARS=${GROUP}_funcvars 45 | else 46 | CLD_VARS=EXTERNAL_VARS 47 | fi 48 | $CLD_VARS 49 | cld-spamcheck ${SRV} | grep spamlisted | xargs -I ^ echo $VMN - $SRV - ^ | cut -d '(' -f 1 50 | fi 51 | done | tee -a /tmp/spamlisted -------------------------------------------------------------------------------- /modules/telegramcloud/README.md: -------------------------------------------------------------------------------- 1 | The module provides utilities for interacting with Telegram using the `CLI` and `Bot` interfaces, functions are available: 2 | - Uploading files to the telegram cloud, used through the telegram bot interface, in response to any sent file, a link is provided to download the file, the file is saved on telegram servers and is available by `id` in the link body, CLD only proxies requests: 3 | - Sending files from the server to the chat 4 | - Sending text messages to chat -------------------------------------------------------------------------------- /modules/telegramcloud/api.py: -------------------------------------------------------------------------------- 1 | @app.route('/tcloud//') 2 | @app.route('/all/tcloud//') 3 | def telegramclouddownload(telegram_file_id, file_name): 4 | try: 5 | tg_file_path = json.loads(requests.get("https://api.telegram.org/bot"+telegram_bot_token+"/getFile?file_id="+telegram_file_id).content)['result']['file_path'] 6 | except: 7 | return requests.get("https://api.telegram.org/bot"+telegram_bot_token+"/getFile?file_id="+telegram_file_id).content 8 | return requests.get("https://api.telegram.org/file/bot"+telegram_bot_token+"/"+tg_file_path).content, {'Content-Type': 'application/octet-stream'} 9 | 10 | @app.route('/cldcloud/') 11 | @app.route('/all/cldcloud/') 12 | def cldclouddownload(filename): 13 | if os.path.exists('/var/cld/modules/telegramcloud/data/all/'+str(filename)) != True: 14 | return Response('404', status=404, mimetype='text/plain') 15 | return Response(stream_file('/var/cld/modules/telegramcloud/data/all/'+str(filename)), status=200, mimetype='application/octet-stream') 16 | -------------------------------------------------------------------------------- /modules/telegramcloud/bin/cld-tcloud-message: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Send message to telegram chat 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | --chatid=-1234567891011|123456789 Telegram chat or user id 8 | Any text what here will send as is Text from $2 will pass to a message - have prority before Here documement and stdin 9 | [Here documents|stdin] Any text passed into stdin or Here documents will send as is 10 | EOL 11 | ) 12 | HELP_EXAMPLES=$(cat << 'EOL' 13 | cld-tcloud-message --chatid=-1234567891011 Any text what here will send as is 14 | echo "Any message" cld-tcloud-message --chatid=-1234567891011 15 | cld-tcloud-message --chatid=-1234567891011 << EOCLD 16 | Any 17 | Here documents 18 | Text 19 | EOCLD 20 | EOL 21 | ) 22 | HELP_ONLY="CLI" 23 | 24 | source /var/cld/bin/include/cldfuncs 25 | init-load-constants TELEGRAM_BOT_TOKEN\|1234567890:AAEzBFqFii-uirfyG3PnygA0DAvJvRH7UzB CLD_DOMAIN\|cld.example.com 26 | 27 | for i in ${CLDOPTS} 28 | do 29 | case $i in 30 | -c=*|-chatid=*|--chatid=*) TG_GROUP="${i#*=}" ;; 31 | *) ;; 32 | esac 33 | done 34 | 35 | TEXT=$(echo "${@:2}") 36 | 37 | [ "$TEXT" ] || TEXT="$( 38 | while IFS= read line; do 39 | echo ${line} 40 | done 41 | )" 42 | 43 | [ "$TEXT" ] && TEXT=$(echo "$TEXT") 44 | 45 | [ "$TG_GROUP" ] || echoexit1 Telegram user or chat id is not defined - use --help argument for details 46 | [ "$TEXT" ] || echoexit1 Text is not defined - use --help argument for details 47 | 48 | curl "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" -d "chat_id=${TG_GROUP}&parse_mode=markdown&text=\`\`\`%0A$(urlencode "${TEXT}")\`\`\`" 49 | -------------------------------------------------------------------------------- /modules/telegramcloud/bin/cld-tcloud-split: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Upload directory or big file as parts to telegram cloud 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | --chatid=-1234567891011|123456789 Telegram chat or user id 8 | --filepath=/tmp/file_for_upload Absolute file/dir path at cld/mounted server 9 | EOL 10 | ) 11 | HELP_EXAMPLES=$(cat << 'EOL' 12 | cld-tcloud-split --chatid=-1234567891011 --filepath=/tmp/big_file_or_dir_for_upload 13 | EOL 14 | ) 15 | HELP_ONLY="CLI" 16 | 17 | source /var/cld/bin/include/cldfuncs 18 | init-load-constants TELEGRAM_BOT_TOKEN\|1234567890:AAEzBFqFii-uirfyG3PnygA0DAvJvRH7UzB CLD_DOMAIN\|cld.example.com 19 | 20 | for i in ${CLDOPTS} 21 | do 22 | case $i in 23 | -c=*|-chatid=*|--chatid=*) TG_GROUP="${i#*=}" ;; 24 | -f=*|-filepath=*|--filepath=*) FILE_PATH="${i#*=}" ;; 25 | *) ;; 26 | esac 27 | done 28 | 29 | [ "$TG_GROUP" ] || echoexit1 Telegram user or chat id is not defined - use --help argument for details 30 | [ "$FILE_PATH" ] || echoexit1 File path is not defined - use --help argument for details 31 | 32 | CURRENT_TIMESTAMP=$(date +%s) 33 | FILE_NAME=$(basename ${FILE_PATH}) 34 | 35 | rm -f ./${FILE_NAME}.part* 36 | tar zcvf - ${FILE_PATH} | split -b 20M - "${FILE_NAME}.part" 37 | for FILE_PART in $(ls ./${FILE_NAME}.part* | xargs readlink -e) 38 | do 39 | /var/cld/modules/telegramcloud/bin/cld-tcloud-upload --chatid=${TG_GROUP} --file=${FILE_PART} 40 | done | tee -a /var/cld/tmp/${FILE_NAME}.links 41 | cat << EOL | tee /var/cld/tmp/${FILE_NAME}.commands 42 | # Commands to download and collect file: 43 | rm -f ./${FILE_NAME}.part* 44 | $(awk '{print "wget "$1}' /var/cld/tmp/${FILE_NAME}.links) 45 | 46 | # Collect file 47 | cat ${FILE_NAME}.part* > ${FILE_NAME}.tar.gz 48 | 49 | # Extract content 50 | tar zxvf ${FILE_NAME}.tar.gz 51 | 52 | # Delete downloaded parts 53 | rm -f ./${FILE_NAME}.part* 54 | EOL 55 | /var/cld/modules/telegramcloud/bin/cld-tcloud-upload --chatid=${TG_GROUP} --file=/var/cld/tmp/${FILE_NAME}.commands -------------------------------------------------------------------------------- /modules/telegramcloud/bin/cld-tcloud-upload: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Upload file to telegram cloud 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | --chatid=-1234567891011|123456789 Telegram chat or user id 8 | --file=/tmp/file_for_upload Absolute file path at cld server 9 | EOL 10 | ) 11 | HELP_EXAMPLES=$(cat << 'EOL' 12 | cld-tcloud-upload --chatid=-1234567891011 --file=/tmp/file_for_upload 13 | EOL 14 | ) 15 | HELP_ONLY="CLI" 16 | 17 | source /var/cld/bin/include/cldfuncs 18 | init-load-constants TELEGRAM_BOT_TOKEN\|1234567890:AAEzBFqFii-uirfyG3PnygA0DAvJvRH7UzB CLD_DOMAIN\|cld.example.com 19 | 20 | for i in ${CLDOPTS} 21 | do 22 | case $i in 23 | -c=*|-chatid=*|--chatid=*) TG_GROUP="${i#*=}" ;; 24 | -f=*|-file=*|--file=*) FILE_PATH="${i#*=}" ;; 25 | *) ;; 26 | esac 27 | done 28 | 29 | [ "$TG_GROUP" ] || echoexit1 Telegram user or chat id is not defined - use --help argument for details 30 | [ "$FILE_PATH" ] || echoexit1 File path is not defined - use --help argument for details 31 | 32 | FILE_NAME=$(rev <<< ${FILE_PATH} | cut -d / -f 1 | rev) 33 | OUTPUT_JSON=$(curl -sF chat_id="${TG_GROUP}" -F document=@"${FILE_PATH}" https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument) 34 | FILE_ID=$(jq -r .result.document.file_id <<< "$OUTPUT_JSON") 35 | MESSAGE_ID=$(jq -r .result.message_id <<< "$OUTPUT_JSON") 36 | DOWNLOAD_LINK=https://${CLD_DOMAIN}/api/all/tcloud/${FILE_ID}/${FILE_NAME} 37 | echo $DOWNLOAD_LINK 38 | sleep 0.5s 39 | curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/editMessageCaption?chat_id=${TG_GROUP}&message_id=${MESSAGE_ID}&parse_mode=markdown&caption=\`Download link:%0A${DOWNLOAD_LINK}\`" &>/dev/null -------------------------------------------------------------------------------- /modules/telegramcloud/bot.py: -------------------------------------------------------------------------------- 1 | @bot.message_handler(func=lambda message: message.caption == '/upload', content_types=['document']) 2 | def tcloud_get_file(message): 3 | checkresult = checkperms(cldmodule, "tcloud_get_file", message.from_user.id, message.chat.id, message.from_user.username) 4 | if checkresult[0] != "granted": return 5 | user = bash('grep ":'+checkresult[1]+':" /var/cld/creds/passwd | cut -d : -f 1 | head -1 | tr -d "\\n"') 6 | answer = "downloadlink:\n`https://"+api_domain+"/api/all/tcloud/"+message.document.file_id+"/"+message.document.file_name+"`" 7 | return bot.send_message(message.chat.id, answer, parse_mode='Markdown') -------------------------------------------------------------------------------- /modules/zabbix/README.md: -------------------------------------------------------------------------------- 1 | Module for managing hosts checking the availability of web sites by url (periodic access to a remote server by domain), as well as monitoring and checking the validity of SSL certificates, domain expiration dates. 2 | - Templates and scripts for Zabbix server are in `/var/cld/modules/zabbix/zbx/` 3 | 4 | The functional of the zabbix module implements functions that allow you to quickly and conveniently add URLs to monitoring and automatically check its availability, the correctness of the response code and much more, if the CLD was initialized with Zabbix support. The zabbix module allows you to significantly speed up the process of adding domain names to the monitoring system through popular corporate messengers, since CLD is deeply integrated into Slack, Mattermost, Discord, Telegram and others. 5 | The main functionality that the zabbix module provides: 6 | - Adding a URL to the monitoring system using a command for the bot. When adding, it is possible to specify a pattern that will be checked when responding to the page. A pattern can include a piece of content, a search word, or a combination. If the pattern is not specified when adding, only the page response code will be checked, which is 200 by default. 7 | - Removing the URL from the monitoring system. You can always remove one or more hosts from monitoring if their further monitoring is not required. Removal is also performed using a command via a bot in a corporate messenger. 8 | - It is also possible to get a complete list of hosts that are being monitored at the moment. 9 | 10 | Below is a list of the Zabbix-module initial variables. 11 | 12 | | Variable | Description | 13 | | ------ | ----------- | 14 | | ZABBIX | variable responsible for initializing the Zabbix module. | 15 | | ZABBIX_USER | Zabbix username through which hosts will be added to monitoring. | 16 | | ZABBIX_PASS | Zabbix user password. | 17 | | ZABBIX_SERVER | the address of the Zabbix server with which the checks will be performed. | 18 | | ZABBIX_API | Zabbix API key for CLD interaction of Zabbix module. | 19 | -------------------------------------------------------------------------------- /modules/zabbix/bin/cld-webcheckdel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Delete web monitoring instance at Zabbix 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 FQDN 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-webcheckdel example.com 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | ARG1=$(echo "${@:1}" | tr ' ' '\n' | grep -v '^\-' | head -1) 16 | 17 | for i in ${CLDOPTS} 18 | do 19 | case $i in 20 | -p=*|-pattern=*|--pattern=*) PATTERN="${i#*=}" ;; 21 | -u=*|-url=*|--url=*) URL="${i#*=}" ;; 22 | *) ;; 23 | esac 24 | done 25 | 26 | IP=127.0.0.1 27 | HOST_NAME="check $ARG1" 28 | HOST_DNS="$ARG1" 29 | # CONSTANT VARIABLES 30 | ERROR='0' 31 | 32 | init-load-constants ZABBIX_USER\|zabbix ZABBIX_PASS\|pAs5w0Rd ZABBIX_API\|https://zbx.example.com/api_jsonrpc.php ZABBIX_HOSTGROUPID\|10 ZABBIX_TEMPLATEIDS\|10362,10364,10365 33 | 34 | export ZABBIX_TEMPLATEIDS="$(tr ',' '\n' <<< ${ZABBIX_TEMPLATEIDS})" 35 | # Authenticate with Zabbix API 36 | authenticate() { 37 | echo $(curl -k -s -H 'Content-Type: application/json-rpc' -d "{ 38 | \"jsonrpc\": \"2.0\", 39 | \"method\": \"user.login\", 40 | \"params\": { 41 | \"user\": \"${ZABBIX_USER}\", 42 | \"password\": \"${ZABBIX_PASS}\" 43 | }, 44 | \"auth\": null, 45 | \"id\": 0 46 | }" "$ZABBIX_API" | cut -d ':' -f 3 | cut -d ',' -f 1) | tr -d '"' 47 | } 48 | 49 | AUTH_TOKEN=$(authenticate) 50 | 51 | JSON_ID_REQUEST=$(cat << EOL | jq . 52 | { 53 | "jsonrpc": "2.0", 54 | "method": "host.get", 55 | "params": { 56 | "filter": { 57 | "host": [ 58 | "${HOST_NAME}" 59 | ] 60 | } 61 | }, 62 | "auth": "${AUTH_TOKEN}", 63 | "id": 1 64 | } 65 | EOL 66 | ) 67 | 68 | HOST_ID=$(curl -k -s -H 'Content-Type: application/json-rpc' -d "${JSON_ID_REQUEST}" "$ZABBIX_API" | jq -r '.result[].hostid') 69 | 70 | AUTH_TOKEN=$(authenticate) 71 | 72 | JSON_REQUEST=$(cat << EOL | jq . 73 | { 74 | "jsonrpc": "2.0", 75 | "method": "host.delete", 76 | "params": [ 77 | "${HOST_ID}" 78 | ], 79 | "auth": "${AUTH_TOKEN}", 80 | "id": 1 81 | } 82 | EOL 83 | ) 84 | 85 | RESULT=$(curl -k -s -H 'Content-Type: application/json-rpc' -d "${JSON_REQUEST}" "$ZABBIX_API" | jq .) 86 | 87 | ( 88 | echo "$RESULT" | grep -q result && echo Web checker for $ARG1 deleted successfully || echo "$RESULT" | grep "data" | cut -d : -f 2- | cut -d ' ' -f 2- | tr -d '"''\\' 89 | ) #| awk -v f="$F" -v b="$B" '{print f$0f}' -------------------------------------------------------------------------------- /modules/zabbix/bin/cld-webchecklist: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | List of your web monitoring instances at Zabbix filtering by pattern 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | $1 Some pattern - if exist will search the word by all your web monitoring instances - emplty will show everything 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-webchecklist 12 | cld-webchecklist example.com 13 | cld-webchecklist copyright 14 | cld-webchecklist /page/addr 15 | EOL 16 | ) 17 | source /var/cld/bin/include/cldfuncs 18 | 19 | for i in ${CLDOPTS} 20 | do 21 | case $i in 22 | -*) ;; 23 | *) let ii++; declare ARG$ii=${i} ;; 24 | esac 25 | done 26 | 27 | init-load-constants ZABBIX_USER\|zabbix ZABBIX_PASS\|pAs5w0Rd ZABBIX_API\|https://zbx.example.com/api_jsonrpc.php ZABBIX_HOSTGROUPID\|10 ZABBIX_TEMPLATEIDS\|10362,10364,10365 28 | 29 | export ZABBIX_TEMPLATEIDS="$(tr ',' '\n' <<< ${ZABBIX_TEMPLATEIDS})" 30 | # Authenticate with Zabbix API 31 | authenticate() { 32 | echo $(curl -k -s -H 'Content-Type: application/json-rpc' -d "{ 33 | \"jsonrpc\": \"2.0\", 34 | \"method\": \"user.login\", 35 | \"params\": { 36 | \"user\": \"${ZABBIX_USER}\", 37 | \"password\": \"${ZABBIX_PASS}\" 38 | }, 39 | \"auth\": null, 40 | \"id\": 0 41 | }" "$ZABBIX_API" | cut -d ':' -f 3 | cut -d ',' -f 1) | tr -d '"' 42 | } 43 | 44 | AUTH_TOKEN=$(authenticate) 45 | 46 | JSON_ID_REQUEST=$(cat << EOL | jq . 47 | { 48 | "jsonrpc": "2.0", 49 | "method": "host.get", 50 | "params": { 51 | "selectMacros": "extend" 52 | }, 53 | "auth": "${AUTH_TOKEN}", 54 | "id": 1 55 | } 56 | EOL 57 | ) 58 | 59 | # curl -k -s -H 'Content-Type: application/json-rpc' -d "${JSON_ID_REQUEST}" "$ZABBIX_API" | jq '.result[] | select(.name|test("^check.")) | [.name,.macros[].value]' | tr -d '\n' | sed 's#\]\[#\n#g' | tr -d '['']''"'',' | awk '{print "`"$2" "$3" "$4"`"}' 60 | curl -k -s -H 'Content-Type: application/json-rpc' -d "${JSON_ID_REQUEST}" "$ZABBIX_API" | jq '.result[] | select(.name|test("^check.")) | {"host":.name,"pattern":.macros[0].value,"url":.macros[1].value}' | jq -c "select(.host,.pattern,.url|test(\"$ARG1\"))" | sort -u | jq . | tr -d '\n' | sed -e 's#^{ ##g' -e 's#}$##g' -e 's#}{ #\n---------------------------------------------\n#g' -e 's#, #\n#g' -e 's#"##g' -e 's#host: #& #g' -e 's#url: #& #g' #| awk -v f="$F" -v b="$B" '{print f$0f}' -------------------------------------------------------------------------------- /modules/zabbix/bin/cld-zbxuploadxml: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HELP_DESC=$(cat << 'EOL' 3 | Zabbix XML configuration import tool 4 | EOL 5 | ) 6 | HELP_ARGS=$(cat << 'EOL' 7 | --file=/tmp/zabbix.xml Configuration XML zabbix file 8 | EOL 9 | ) 10 | HELP_EXAMPLES=$(cat << 'EOL' 11 | cld-zbxuploadxml --file=/tmp/zabbix.xml 12 | EOL 13 | ) 14 | source /var/cld/bin/include/cldfuncs 15 | 16 | for i in ${CLDOPTS} 17 | do 18 | case $i in 19 | -f=*|-file=*|--file=*) FILE="${i#*=}" ;; 20 | *) ;; 21 | esac 22 | done 23 | 24 | init-load-constants ZABBIX_USER\|zabbix ZABBIX_PASS\|pAs5w0Rd ZABBIX_API\|https://zbx.example.com/api_jsonrpc.php ZABBIX_HOSTGROUPID\|10 25 | 26 | # Authenticate with Zabbix API 27 | authenticate() { 28 | echo $(curl -k -s -H 'Content-Type: application/json-rpc' -d "{ 29 | \"jsonrpc\": \"2.0\", 30 | \"method\": \"user.login\", 31 | \"params\": { 32 | \"user\": \"${ZABBIX_USER}\", 33 | \"password\": \"${ZABBIX_PASS}\" 34 | }, 35 | \"auth\": null, 36 | \"id\": 0 37 | }" "$ZABBIX_API" | cut -d ':' -f 3 | cut -d ',' -f 1) | tr -d '"' 38 | } 39 | 40 | AUTH_TOKEN=$(authenticate) 41 | 42 | JSON_REQUEST=$(cat << EOL | jq . 43 | { 44 | "jsonrpc": "2.0", 45 | "method": "configuration.import", 46 | "params": { 47 | "format": "xml", 48 | "rules": { 49 | "applications": { 50 | "createMissing": true, 51 | "deleteMissing": false 52 | }, 53 | "valueMaps": { 54 | "createMissing": true, 55 | "updateExisting": true 56 | }, 57 | "hosts": { 58 | "createMissing": true, 59 | "updateExisting": true 60 | }, 61 | "items": { 62 | "createMissing": true, 63 | "updateExisting": true, 64 | "deleteMissing": false 65 | }, 66 | "screens": { 67 | "createMissing": true, 68 | "updateExisting": true 69 | } 70 | }, 71 | "source": "$(cat $FILE | sed 's#"#\\"#g' | tr -d '\n' | tr -s ' ')" 72 | }, 73 | "auth": "${AUTH_TOKEN}", 74 | "id": 1 75 | } 76 | EOL 77 | ) 78 | 79 | # RESULT=$( 80 | curl -k -s -H 'Content-Type: application/json-rpc' -d "${JSON_REQUEST}" "$ZABBIX_API" | jq . 81 | # ) 82 | # ( 83 | # echo "$RESULT" | grep -q result && echo Web checker for $ARG1 configured successfully || echo "$RESULT" | grep "data" | cut -d : -f 2- | cut -d ' ' -f 2- | tr -d '"''\\' 84 | # ) #| awk -v f="$F" -v b="$B" '{print f$0f}' -------------------------------------------------------------------------------- /modules/zabbix/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /var/cld/bin/include/cldfuncs 3 | 4 | if grep -q "^ZABBIXCONTROL=" /var/cld/creds/creds 5 | then 6 | echo -n "" 7 | else 8 | echo "Will you using Zabbix control module ?" 9 | select ANSWER in yes no 10 | do 11 | if [ "${ANSWER}" == "yes" ] 12 | then 13 | init-load-constants ZABBIX_USER\|zabbix ZABBIX_PASS\|pAs5w0Rd ZABBIX_SERVER\|zbx.example.com ZABBIX_API\|https://zbx.example.com/api_jsonrpc.php ZABBIX_HOSTGROUPID\|10 ZABBIX_TEMPLATEIDS\|10362,10364,10365 14 | echo ZABBIXCONTROL=1 >> /var/cld/creds/creds 15 | break 16 | elif [ "${ANSWER}" == "no" ] 17 | then 18 | echo ZABBIXCONTROL=0 >> /var/cld/creds/creds 19 | break 20 | fi 21 | done 22 | fi -------------------------------------------------------------------------------- /modules/zabbix/zbx/scripts/checkssl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DOMAIN=$1 3 | expr \( `echo|openssl s_client -connect ${DOMAIN}:443 -servername ${DOMAIN} 2>/dev/null|openssl x509 -noout -enddate|cut -d'=' -f2|xargs -I ^ date +%s -d "^"` - `date +%s` \) / 24 / 3600 4 | -------------------------------------------------------------------------------- /modules/zabbix/zbx/templates/web_url_check.yaml: -------------------------------------------------------------------------------- 1 | zabbix_export: 2 | version: '5.4' 3 | date: '2022-02-03T18:26:22Z' 4 | groups: 5 | - 6 | uuid: df69cb4c179f4c92acbe0b11f081d7c5 7 | name: adsdoctor 8 | - 9 | uuid: 7df96b18c230490a9a0a9e2307226338 10 | name: Templates 11 | templates: 12 | - 13 | uuid: 597d1db97b2e44329baeb64e0e6be139 14 | template: 'Check web' 15 | name: 'Check web' 16 | groups: 17 | - 18 | name: adsdoctor 19 | - 20 | name: Templates 21 | httptests: 22 | - 23 | uuid: f5d78a1b65134adf827cdddd684ba1ea 24 | name: '{HOSTNAME}' 25 | agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.78.2 (KHTML, like Gecko) Version/7.0.6 Safari/537.78.2' 26 | authentication: BASIC 27 | http_user: admin@mail.com 28 | http_password: '123' 29 | steps: 30 | - 31 | name: 'Open site' 32 | url: '{$URL}' 33 | timeout: 30s 34 | required: '{$PATTERN}' 35 | status_codes: '200' 36 | triggers: 37 | - 38 | uuid: 916571579a8841818ad6e2261c41c585 39 | expression: 'find(/Check web/web.test.error[{HOSTNAME}],,"iregexp",".*")<>0 and last(/Check web/web.test.fail[{HOSTNAME}])<>0 and last(/Check web/web.test.fail[{HOSTNAME}],#2)<>0' 40 | name: 'check {$URL} was completed with error: {ITEM.VALUE1}' 41 | priority: DISASTER 42 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cryptography==36.0.1 2 | Flask==1.1.2 3 | Flask-Session==0.3.2 4 | Flask-SocketIO==5.0.1 5 | itsdangerous==1.1.0 6 | Jinja2==2.10.1 7 | lxml==4.6.5 8 | MarkupSafe==0.23 9 | PySocks==1.7.1 10 | pyTelegramBotAPI==4.14.0 11 | python-dateutil==2.8.1 12 | python-engineio==4.11.2 13 | python-linux-procfs==0.7.3 14 | python-pam==2.0.2 15 | python-socketio==5.2.1 16 | urllib3==1.26.5 17 | Werkzeug==1.0.1 18 | wsproto==1.2.0 19 | -------------------------------------------------------------------------------- /setup/access/groups/aws/parsingscript: -------------------------------------------------------------------------------- 1 | aws ec2 describe-instances --filters "Name=tag:Name,Values=CLUSTER-NODEGROUPNAME-Node" --query Reservations[*].Instances[*].[PrivateDnsName,PublicIpAddress] | egrep -o ".*\t.*" --color=never| awk '{print "eks-"$1"_"$2"_22_root" }' | sed 's#.compute.internal##g' > /var/cld/access/groups/${GROUP}/clouds_tmp 2 | unalias mv &>/dev/null 3 | INSTANCE_LIST=$(cat /var/cld/access/groups/${GROUP}/clouds_tmp) 4 | [ "${INSTANCE_LIST}" ] && { 5 | echo "${INSTANCE_LIST}" > /var/cld/access/groups/${GROUP}/clouds_tmp 6 | 7 | for awsinstance in $(grep -v -f /var/cld/access/groups/${GROUP}/clouds /var/cld/access/groups/${GROUP}/clouds_tmp) 8 | do 9 | timeout 10s ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ec2-user@$(echo $awsinstance | cut -d _ -f 2) "sudo sed -i -r 's#.*(ssh-rsa.*)#\1#g' /root/.ssh/authorized_keys" & &>/dev/null 10 | done 11 | 12 | mv /var/cld/access/groups/${GROUP}/clouds_tmp /var/cld/access/groups/${GROUP}/clouds 13 | } -------------------------------------------------------------------------------- /setup/access/groups/aws/type: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /setup/access/groups/default/clouds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/setup/access/groups/default/clouds -------------------------------------------------------------------------------- /setup/access/groups/digitalocean/clouds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/setup/access/groups/digitalocean/clouds -------------------------------------------------------------------------------- /setup/access/groups/digitalocean/funcmount: -------------------------------------------------------------------------------- 1 | LOCALMOUNTPATH="/home/${SUDO_USER}/mnt/${VM}" 2 | if [ ! -d "$DIR" ]; then mkdir -p $LOCALMOUNTPATH ;fi 3 | fusermount -uzq $LOCALMOUNTPATH >> /dev/null 4 | mkdir -p $LOCALMOUNTPATH 2>&1 >/dev/null 5 | echo $USR | grep -q clouds && SFTP_PATH=$(ssh -q -p 55567 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o "RequestTTY force" $USR@$SRV "grep sftp /etc/ssh/sshd_config" | awk '{print $3}' | tr -d '\r' | tr -d '\n') 6 | echo $USR | grep -q clouds && SUDO_PATH=$(ssh -q -p 55567 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o "RequestTTY force" $USR@$SRV "which sudo" | tr -d '\r' | tr -d '\n') 7 | mkdir -p $LOCALMOUNTPATH 2>&1 >/dev/null 8 | echo $USR | grep -q clouds && sshfs -p $PRT -o password_stdin -o sftp_server="${SUDO_PATH} ${SFTP_PATH}" -o allow_other,UserKnownHostsFile=/dev/null,StrictHostKeyChecking=no $USR@$SRV:/ $LOCALMOUNTPATH 2>&1 >/dev/null 9 | echo $USR | grep -q clouds || sshfs -p $PRT -o password_stdin -o allow_other,UserKnownHostsFile=/dev/null,StrictHostKeyChecking=no $USR@$SRV:/ $LOCALMOUNTPATH <<< "$PWD" 2>&1 >/dev/null 10 | -------------------------------------------------------------------------------- /setup/access/groups/digitalocean/funcs: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /setup/access/groups/digitalocean/functerm: -------------------------------------------------------------------------------- 1 | echo $USR | grep -q root && sshpass -p "$PWD" ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o "RequestTTY force" -p $PRT $USR@$SRV | tee -a $CLD_LOG 2 | echo $USR | grep -q root || sshpass -p "$PWD" ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o "RequestTTY force" -p $PRT $USR@$SRV "sudo -i" | tee -a $CLD_LOG 3 | -------------------------------------------------------------------------------- /setup/access/groups/digitalocean/funcumount: -------------------------------------------------------------------------------- 1 | LOCALMOUNTPATH=`echo "/home/$SUDO_USER/mnt/$VM"` >> /dev/null ; fusermount -uzq $LOCALMOUNTPATH >> /dev/null ; rmdir $LOCALMOUNTPATH 2 | -------------------------------------------------------------------------------- /setup/access/groups/digitalocean/funcvars: -------------------------------------------------------------------------------- 1 | SRV=`echo $VM | cut -d "_" -f 2` 2 | PRT=`echo $VM | cut -d "_" -f 3` 3 | USR=`echo $VM | cut -d "_" -f 4` 4 | -------------------------------------------------------------------------------- /setup/access/groups/digitalocean/parsingscript: -------------------------------------------------------------------------------- 1 | ( 2 | for cycle in $(seq 1 3) 3 | do 4 | curl -s -X GET "https://api.digitalocean.com/v2/droplets/$(echo $cycle | grep -q '^1$' || echo \?page=${cycle})" -H "Authorization: Bearer ${DIGITALOCEAN_TOKEN}" 5 | done 6 | ) | tr ',' '\n' | grep -v "x64" | grep -v GrubLoader | egrep -v "\ [0-9]" | grep -Po "\"name\"\:\".*?\""\|"\"ip_address\":\"[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\"" | sed -e 's#"name":"##g' -e 's#"ip_address":"##g' -e 's#"##g' | tr '\n' ' ' | grep -Po ".*?\ \d+\.\d+\.\d+\.\d+" | awk '{print "DO-"$1"_"$2"_22_root"}' >> /var/cld/tmp/tmp_do_list 7 | rm -f /var/cld/creds/do_list ; mv /var/cld/tmp/tmp_do_list /var/cld/access/groups/digitalocean/clouds 8 | 9 | -------------------------------------------------------------------------------- /setup/access/groups/digitalocean/type: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /setup/access/groups/openvz/clouds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/setup/access/groups/openvz/clouds -------------------------------------------------------------------------------- /setup/access/groups/openvz/funcmount: -------------------------------------------------------------------------------- 1 | LOCALMOUNTPATH="/home/${SUDO_USER}/mnt/${VM}" >> /dev/null 2 | if [ ! -d "$DIR" ]; then mkdir -p $LOCALMOUNTPATH ;fi 3 | fusermount -uzq $LOCALMOUNTPATH &>/dev/null 4 | mkdir -p $LOCALMOUNTPATH &>/dev/null 5 | DEVICE=$(ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "sudo pct exec $CT -- df -P" | tr '\r' '\n' | egrep "/$" | awk '{print $1}' | tr -d '\n') &>/dev/null 6 | if echo $DEVICE | egrep --quiet "^[/].*" ; then 7 | ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "sudo mkdir /mnt/$CT" &>/dev/null ; ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "sudo mount $DEVICE /mnt/$CT" &>/dev/null 8 | SFTP_PATH=$(ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "grep sftp /etc/ssh/sshd_config" | awk '{print $3}' | tr -d '\r' | tr -d '\n') &>/dev/null 9 | SUDO_PATH=$(ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "which sudo" | tr -d '\r' | tr -d '\n') &>/dev/null 10 | sshfs -p 55567 -o sftp_server="$SUDO_PATH $SFTP_PATH" -o allow_other,UserKnownHostsFile=/dev/null,StrictHostKeyChecking=no clouds@$HPR:/mnt/$CT $LOCALMOUNTPATH &>/dev/null 11 | else 12 | SFTP_PATH=$(ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "grep sftp /etc/ssh/sshd_config" | awk '{print $3}' | tr -d '\r' | tr -d '\n') &>/dev/null 13 | SUDO_PATH=$(ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "which sudo" | tr -d '\r' | tr -d '\n') &>/dev/null 14 | sshfs -p 55567 -o sftp_server="$SUDO_PATH $SFTP_PATH" -o allow_other,UserKnownHostsFile=/dev/null,StrictHostKeyChecking=no clouds@$HPR:/$DEVICE $LOCALMOUNTPATH &>/dev/null 15 | fi 16 | -------------------------------------------------------------------------------- /setup/access/groups/openvz/funcs: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /setup/access/groups/openvz/functerm: -------------------------------------------------------------------------------- 1 | ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o "RequestTTY force" -p 55567 clouds@$HPR "sudo vzctl enter $CT" | tee -a $CLD_LOG 2 | -------------------------------------------------------------------------------- /setup/access/groups/openvz/funcumount: -------------------------------------------------------------------------------- 1 | LOCALMOUNTPATH=`echo "/home/$SUDO_USER/mnt/$VM"` &>/dev/null ; fusermount -uzq $LOCALMOUNTPATH &>/dev/null ; rmdir $LOCALMOUNTPATH 2 | -------------------------------------------------------------------------------- /setup/access/groups/openvz/funcvars: -------------------------------------------------------------------------------- 1 | CTNAME="`echo "$VM" | cut -d "_" -f 1`_`echo "$VM" | cut -d "_" -f 3`" 2 | HPR=`echo "$VM" | cut -d "_" -f 2` 3 | CT=`echo "$VM" | cut -d "_" -f 3` 4 | -------------------------------------------------------------------------------- /setup/access/groups/openvz/parsingscript: -------------------------------------------------------------------------------- 1 | temp_vz_ct_hyper_list="/var/cld/tmp/temp_vz_ct_hyper_list" 2 | ct_vz_hyper_list="/var/cld/setup/access/groups/openvz/clouds" 3 | for vz_hyper in $(cat /var/cld/setup/access/groups/openvz/hpr_list) 4 | do 5 | timeout 20 ssh -o "StrictHostKeyChecking no" -p 55567 clouds@$vz_hyper "sudo /usr/sbin/vzlist" | grep -v HOSTNAME | tr -d '\r' | awk '{print $5"_HYPER_"$1"_"$4}' | sed "s#HYPER#$vz_hyper#g" >> $temp_vz_ct_hyper_list & 6 | done 7 | wait 8 | rm -f ct_vz_hyper_list ; mv $temp_vz_ct_hyper_list $ct_vz_hyper_list 9 | 10 | touch /var/cld/setup/access/groups/openvz/clouds 11 | -------------------------------------------------------------------------------- /setup/access/groups/openvz/type: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /setup/access/groups/proxmox/clouds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/setup/access/groups/proxmox/clouds -------------------------------------------------------------------------------- /setup/access/groups/proxmox/funcmount: -------------------------------------------------------------------------------- 1 | LOCALMOUNTPATH="/home/${SUDO_USER}/mnt/${VM}" 2 | if [ ! -d "$DIR" ]; then mkdir -p $LOCALMOUNTPATH ;fi 3 | fusermount -uzq $LOCALMOUNTPATH >> /dev/null 4 | mkdir -p $LOCALMOUNTPATH >> /dev/null 5 | DEVICE=$(ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "sudo pct exec $CT -- df -P" | tr '\r' '\n' | egrep "/$" | awk '{print $1}' | tr -d '\n') >> /dev/null 6 | if echo $DEVICE | egrep --quiet "^[/].*" ; then 7 | ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "sudo mkdir /mnt/$CT" >> /dev/null ; ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "sudo mount $DEVICE /mnt/$CT" >> /dev/null 8 | SFTP_PATH=$(ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "grep sftp /etc/ssh/sshd_config" | awk '{print $3}' | tr -d '\r' | tr -d '\n') >> /dev/null 9 | SUDO_PATH=$(ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "which sudo" | tr -d '\r' | tr -d '\n') >> /dev/null 10 | sshfs -p 55567 -o sftp_server="$SUDO_PATH $SFTP_PATH" -o allow_other,UserKnownHostsFile=/dev/null,StrictHostKeyChecking=no clouds@$HPR:/mnt/$CT $LOCALMOUNTPATH >> /dev/null 11 | else 12 | SFTP_PATH=$(ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "grep sftp /etc/ssh/sshd_config" | awk '{print $3}' | tr -d '\r' | tr -d '\n') >> /dev/null 13 | SUDO_PATH=$(ssh -q -p 55567 -o "RequestTTY force" clouds@$HPR "which sudo" | tr -d '\r' | tr -d '\n') >> /dev/null 14 | sshfs -p 55567 -o sftp_server="$SUDO_PATH $SFTP_PATH" -o allow_other,UserKnownHostsFile=/dev/null,StrictHostKeyChecking=no clouds@$HPR:/$DEVICE $LOCALMOUNTPATH >> /dev/null 15 | fi 16 | 17 | -------------------------------------------------------------------------------- /setup/access/groups/proxmox/funcs: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /setup/access/groups/proxmox/functerm: -------------------------------------------------------------------------------- 1 | ssh -q -p 55567 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o "RequestTTY force" clouds@$HPR "sudo pct enter $CT" | tee -a $CLD_LOG 2 | -------------------------------------------------------------------------------- /setup/access/groups/proxmox/funcumount: -------------------------------------------------------------------------------- 1 | LOCALMOUNTPATH=`echo "/home/$SUDO_USER/mnt/$VM"` >> /dev/null ; fusermount -uzq $LOCALMOUNTPATH >> /dev/null ; rmdir $LOCALMOUNTPATH 2 | -------------------------------------------------------------------------------- /setup/access/groups/proxmox/funcvars: -------------------------------------------------------------------------------- 1 | CTNAME="`echo "$VM" | cut -d "_" -f 1`_`echo "$VM" | cut -d "_" -f 3`" 2 | HPR=$(echo "$VM" | cut -d "_" -f 2) 3 | CT=`echo "$VM" | cut -d "_" -f 3` 4 | -------------------------------------------------------------------------------- /setup/access/groups/proxmox/type: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /setup/access/groups/scaleway/parsingscript: -------------------------------------------------------------------------------- 1 | curl -s -H "X-Auth-Token: $SCALEWAYTOKEN" https://api.scaleway.com/instance/v1/zones/fr-par-1/servers | jq -r '.servers[] | .hostname+"_"+.public_ip.address+"_22_root"' > /var/cld/access/groups/${GROUP}/clouds_tmp 2 | unalias mv &>/dev/null 3 | INSTANCE_LIST=$(cat /var/cld/access/groups/${GROUP}/clouds_tmp) 4 | [ "${INSTANCE_LIST}" ] && { 5 | echo "${INSTANCE_LIST}" > /var/cld/access/groups/${GROUP}/clouds_tmp 6 | 7 | mv /var/cld/access/groups/${GROUP}/clouds_tmp /var/cld/access/groups/${GROUP}/clouds 8 | } -------------------------------------------------------------------------------- /setup/access/groups/scaleway/type: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /setup/access/groups/virtuozzo/clouds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/setup/access/groups/virtuozzo/clouds -------------------------------------------------------------------------------- /setup/access/groups/virtuozzo/funcmount: -------------------------------------------------------------------------------- 1 | LOCALMOUNTPATH="/home/${SUDO_USER}/mnt/${VM}" >> /dev/null 2 | if [ ! -d "$DIR" ]; then mkdir -p $LOCALMOUNTPATH ;fi 3 | fusermount -uzq $LOCALMOUNTPATH >> /dev/null 4 | mkdir -p $LOCALMOUNTPATH >> /dev/null 5 | DEVICE=$(ssh -q -o "RequestTTY force" clouds@$HPR "sudo prlctl exec $CT df -P" | tr '\r' '\n' | egrep "/$" | awk '{print $1}' | tr -d '\r' | tr -d '\n') >> /dev/null 6 | VZPOINT=$(ssh -q -o "RequestTTY force" root@$HPR "df -P" | tr '\r' '\n' | grep "$DEVICE" | awk '{print $6}' | tr -d '\r' | tr -d '\n') >> /dev/null 7 | SFTP_PATH=$(ssh -q -o "RequestTTY force" clouds@$HPR "grep sftp /etc/ssh/sshd_config" | awk '{print $3}' | tr -d '\r' | tr -d '\n') >> /dev/null 8 | SUDO_PATH=$(ssh -q -o "RequestTTY force" clouds@$HPR "which sudo" | tr -d '\r' | tr -d '\n') >> /dev/null 9 | sshfs -o sftp_server="$SUDO_PATH S$FTP_PATH" -o allow_other,UserKnownHostsFile=/dev/null,StrictHostKeyChecking=no clouds@$HPR:$VZPOINT $LOCALMOUNTPATH >> /dev/null 10 | -------------------------------------------------------------------------------- /setup/access/groups/virtuozzo/funcs: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /setup/access/groups/virtuozzo/functerm: -------------------------------------------------------------------------------- 1 | ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o "RequestTTY force" clouds@$HPR "sudo prlctl enter $CT" | tee -a $CLD_LOG 2 | -------------------------------------------------------------------------------- /setup/access/groups/virtuozzo/funcumount: -------------------------------------------------------------------------------- 1 | LOCALMOUNTPATH=`echo "/home/$SUDO_USER/mnt/$VM"` >> /dev/null ; fusermount -uzq $LOCALMOUNTPATH >> /dev/null ; rmdir $LOCALMOUNTPATH 2 | -------------------------------------------------------------------------------- /setup/access/groups/virtuozzo/funcvars: -------------------------------------------------------------------------------- 1 | HPR=`echo "$VM" | cut -d "_" -f 2` 2 | CT=`echo "$VM" | cut -d "_" -f 1` 3 | -------------------------------------------------------------------------------- /setup/access/groups/virtuozzo/parsingscript: -------------------------------------------------------------------------------- 1 | truncate -s 0 /var/cld/tmp/temp_ct_vz_hyper_list 2 | temp_ct_vz_hyper_list="/var/cld/tmp/temp_ct_vz_hyper_list" 3 | ct_hyper_list="/var/cld/access/groups/virtuozzo/clouds" 4 | for hyper in $(cat /var/cld/setup/access/groups/virtuozzo/hpr_list) 5 | do timeout 5 ssh clouds@$hyper "sudo prlctl list | grep -v 'UUID\|stopped'" | awk '{print $5"_HYPER"}' | sed "s#HYPER#$hyper#g" >> $temp_ct_vz_hyper_list 6 | done 7 | rm -f $ct_hyper_list ; mv $temp_ct_vz_hyper_list $ct_hyper_list 8 | 9 | touch /var/cld/access/groups/virtuozzo/clouds 10 | -------------------------------------------------------------------------------- /setup/access/groups/virtuozzo/type: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /setup/access/users/admin/clouds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/setup/access/users/admin/clouds -------------------------------------------------------------------------------- /setup/access/users/admin/groups: -------------------------------------------------------------------------------- 1 | proxmox 2 | virtuozzo 3 | openvz 4 | digitalocean 5 | 6 | default 7 | -------------------------------------------------------------------------------- /setup/access/users/admin/role: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /setup/creds/creds: -------------------------------------------------------------------------------- 1 | FLASKSECRETKEY=YourFlaskSecret 2 | -------------------------------------------------------------------------------- /setup/creds/protected_ports: -------------------------------------------------------------------------------- 1 | 3306 2 | 5432 3 | 6379 4 | 8006 5 | 11211 6 | 15672 7 | 27017 -------------------------------------------------------------------------------- /setup/etc/cron.d/cld: -------------------------------------------------------------------------------- 1 | MAILTO="" 2 | */5 * * * * root bash -lc "/var/cld/bin/cld-groupparser" 3 | #* * * * * root bash -lc "/var/cld/modules/access/bin/cld-accesslistdeploy --groups=default" &>/dev/null 4 | #0 12 * * * root bash -lc "/var/cld/modules/etcbackup/bin/cld-etcbackup" -------------------------------------------------------------------------------- /supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=false 3 | 4 | [program:sshd] 5 | command=/usr/sbin/sshd -D 6 | autorestart=true 7 | stdout_logfile=/dev/stdout 8 | stderr_logfile=/dev/stderr 9 | 10 | [program:nginx] 11 | command=/usr/sbin/nginx -g 'daemon off;' 12 | autorestart=true 13 | stdout_logfile=/dev/stdout 14 | stderr_logfile=/dev/stderr 15 | 16 | [program:cld_web] 17 | command=python3 /var/cld/web/dashboard.py 18 | directory=/var/cld/web 19 | autorestart=true 20 | stdout_logfile=/dev/stdout 21 | stderr_logfile=/dev/stderr 22 | environment=PYTHONUNBUFFERED=1 23 | 24 | [program:cld_api] 25 | command=python3 /var/cld/api/api.py 26 | directory=/var/cld/api 27 | autorestart=true 28 | stdout_logfile=/dev/stdout 29 | stderr_logfile=/dev/stderr 30 | environment=PYTHONUNBUFFERED=1 31 | 32 | [program:cld_auditor] 33 | command=/var/cld/bin/cld-auditor 34 | autorestart=true 35 | stdout_logfile=/dev/stdout 36 | stderr_logfile=/dev/stderr 37 | environment=PYTHONUNBUFFERED=1 38 | 39 | [program:tgbot] 40 | command=python3 /var/cld/bot/telegram/tgbot.py 41 | directory=/var/cld/bot/telegram 42 | autorestart=true 43 | stdout_logfile=/dev/stdout 44 | stderr_logfile=/dev/stderr 45 | environment=PYTHONUNBUFFERED=1 46 | 47 | [program:dcbot] 48 | command=python3 /var/cld/bot/discord/dcbot.py 49 | directory=/var/cld/bot/discord 50 | autorestart=true 51 | stdout_logfile=/dev/stdout 52 | stderr_logfile=/dev/stderr 53 | environment=PYTHONUNBUFFERED=1 54 | 55 | [program:cron] 56 | command=/usr/sbin/crond -n 57 | autorestart=true 58 | stdout_logfile=/dev/stdout 59 | stderr_logfile=/dev/stderr 60 | 61 | -------------------------------------------------------------------------------- /web/css/toolkit.css: -------------------------------------------------------------------------------- 1 | #ServerListUl li a { 2 | border: 1px solid #1e88e5; 3 | margin: 0px; 4 | background-color: white; 5 | padding: 0px; 6 | padding-left: 4px; 7 | text-decoration: none; 8 | display: block; 9 | font-size: 14; 10 | color: lightslategray; 11 | border-right-width: 0; 12 | border-left-width: 0; 13 | border-bottom-width: 0; 14 | } -------------------------------------------------------------------------------- /web/font/D3Euronism.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/web/font/D3Euronism.woff -------------------------------------------------------------------------------- /web/html/include/footer.html: -------------------------------------------------------------------------------- 1 | {% import 'html/include/cld_tier.html' as cldtier %} 2 | {% set cldtier = cldtier| replace(" ","") | replace("\n","") %} 3 | {% if cldtier in ["basic", "business", "premium", "enterprise"] %} 4 | {% set copyright = "CLD "+cldtier|capitalize+" License" %} 5 | {% else %} 6 | {% set copyright = "GNU General Public License v2.0" %} 7 | {% endif %} 8 |
9 | 10 | ClassicDevOps © {{ copyright }}
11 |
-------------------------------------------------------------------------------- /web/html/include/navbar-term.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/html/include/navbar.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/html/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CLD Web - Login 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 |
17 | User Icon 18 |
19 | 20 | 21 |
22 | 23 | 24 | 25 |
26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /web/html/terminal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CLD Web - Terminal 4 | {% include 'html/include/head.html' %} 5 | 6 | 7 | 8 |
9 | 10 | {% include 'html/include/navbar-term.html' %} 11 |
12 |
13 | 14 | 26 | 27 |
28 | 33 |
34 |
ClassicDevOps access system terminal
35 |
36 |
37 | 38 |
39 | 40 |
41 | 42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /web/html/toolkit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CLD Web - Toolkit 4 | {% include 'html/include/head.html' %} 5 | 6 | 7 | 8 | 9 |
10 | 11 | {% include 'html/include/navbar-term.html' %} 12 |
13 |
14 | 15 | 27 | 28 |
29 | 34 |
35 |
ClassicDevOps toolkit
36 |
37 |
38 | 39 |
40 | 41 |
42 | 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /web/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/web/img/favicon.ico -------------------------------------------------------------------------------- /web/img/favicon_term.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/classicdevops/cld/6b843534ac580f65fa14b087b22a8ca8b7cd475e/web/img/favicon_term.ico -------------------------------------------------------------------------------- /web/img/module.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/img/shell.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/js/terminal.js: -------------------------------------------------------------------------------- 1 | function newtab(util, hostname) { 2 | var id = idgen(); 3 | $('#hostTab').append(''); 4 | $('#hostTabContent').append('
'); 5 | document.getElementById(id + "-tab").click(); 6 | sleep(250).then(() => { 7 | $('#'+id).html(''); 8 | }); 9 | }; 10 | 11 | $(document).ready(function() { 12 | $('[data-toggle=offcanvas]').click(function() { 13 | $('.row-offcanvas').toggleClass('active'); 14 | }); 15 | }); -------------------------------------------------------------------------------- /web/js/toolkit.js: -------------------------------------------------------------------------------- 1 | function appendtab(id, util) { 2 | $('#hostTab').append('' 3 | ); 4 | } 5 | function appendform(id, util) { 6 | $('#'+id).append('
') 7 | } 8 | function appendcontent(id, util) { 9 | $('#hostTabContent').append('
'); 10 | document.getElementById(id + "-tab").click(); 11 | appendform(id, util); 12 | $.ajax({type : 'GET', url: "/help/"+util, dataType : 'text', 13 | success: function (data) { 14 | $('#'+id).append('
'+data+'
') 15 | } 16 | }); 17 | } 18 | function appendframe(id, util) { 19 | $('#hostTabContent').append('
'); 20 | document.getElementById(id + "-tab").click(); 21 | sleep(250).then(() => { 22 | $('#'+id).html(''); 23 | }); 24 | } 25 | function openutil(id, util) { 26 | var args = document.getElementById(id+'-arg').value; 27 | $('#'+id).html(''); 28 | sleep(250).then(() => { 29 | console.log("document.getElementById('frame-"+id+"').contentWindow.document.getElementsByClassName('xterm-cursor-layer')[0].click();") 30 | document.getElementById('frame-' + id).contentDocument.querySelector('.xterm-helper-textarea').focus(); 31 | }); 32 | }; 33 | function newtab(util) { 34 | var id = idgen(); 35 | appendtab(id, util); 36 | appendcontent(id, util); 37 | }; 38 | function newdirecttab(util) { 39 | var id = idgen(); 40 | appendtab(id, util); 41 | appendframe(id, util); 42 | }; 43 | function updatetab(id, util) { 44 | $('#'+id).html('') 45 | appendcontent(id, util); 46 | }; 47 | 48 | $(document).ready(function() { 49 | $('[data-toggle=offcanvas]').click(function() { 50 | $('.row-offcanvas').toggleClass('active'); 51 | }); 52 | }); --------------------------------------------------------------------------------