/* This library help generates the configuration for the various components of a site. It also program the blackhole system tying all the components together. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "manager.h" using namespace std; static const char *sbin_path="/usr/sbin"; static const char *sock_dir = "/var/run/blackhole"; static const char *blackhole_path = "/usr/sbin"; static const char *horizon_ip = "192.168.4.1"; static const char *lxcsock_dir = "/var/run/blackhole"; static const char *manager_user = "manager"; static int manager_userid = -1; static const char *varlxc = "/var/lib/lxc"; #define IP_PREFIX "192.168.122." #define IP_PREPROD_PREFIX "192.168.124." static const char *ip_lxc_gateway = IP_PREFIX "1"; static const char *ip_preprod_lxc_gateway = IP_PREPROD_PREFIX "1"; static bool preprodmode=false; static int trli_chmod (const PARAM_STRING name, int mode) { int ret = chmod (name.ptr,mode); if (ret == -1) tlmp_error ("Can't chmod %s (%s)\n",name.ptr,strerror(errno)); return ret; } void manager_set_sock_dir (const char *path) { // Leak normal sock_dir = strdup(path); } void manager_set_manager_user (const char *name, int id) { manager_user = strdup(name); manager_userid = id; } void manager_setpreprodmode() { preprodmode = true; ip_lxc_gateway = ip_preprod_lxc_gateway; } static bool lxc3 = false; void lxc_config (const char *name, const char *utsname, const char *ip, bool internet_access) { glocal const char *name = name; glocal const char *utsname = utsname; glocal const char *ip = ip; glocal bool internet_access = internet_access; (string_f("/var/lib/lxc/%s/config",name),false); static bool is_init = false; if (!is_init){ is_init = false; ("rpm -q lxc",10); // We check for lxc3 but the changes were made in 2.1 if (strncmp(line,"lxc-3",5)>=0) lxc3 = true; return 0; } const char *keyw = lxc3 ? "net.0" : "network"; fprintf (fout,"lxc.include = /usr/share/lxc/config/common.conf\n"); fprintf (fout,"lxc.%s.type = veth\n",keyw); fprintf (fout,"lxc.%s.link = virbr0\n",keyw); unsigned long ipu = ipnum_aip2l (glocal.ip); fprintf (fout,"lxc.%s.hwaddr = fe:dc:%02x:%02x:%02x:%02x\n",keyw ,(unsigned)(ipu>>24),(unsigned)((ipu>>16)&0xff),(unsigned)((ipu>>8)&0xff),(unsigned)(ipu&0xff)); fprintf (fout,"lxc.%s.flags = up\n",keyw); if (glocal.internet_access) fprintf (fout,"lxc.%s.ipv4.gateway=%s\n",keyw,ip_lxc_gateway); if (lxc3){ fprintf (fout,"lxc.%s.ipv4.address=%s/24\n",keyw,glocal.ip); fprintf (fout,"lxc.rootfs.path = /var/lib/lxc/%s/rootfs\n",glocal.name); fprintf (fout,"lxc.uts.name = %s\n",glocal.utsname); if (preprodmode) fprintf (fout,"lxc.seccomp.profile=\n"); }else{ fprintf (fout,"lxc.network.ipv4=%s/24\n",glocal.ip); fprintf (fout,"lxc.rootfs = /var/lib/lxc/%s/rootfs\n",glocal.name); fprintf (fout,"lxc.rootfs.backend = dir\n"); fprintf (fout,"lxc.utsname = %s\n",glocal.utsname); if (preprodmode) fprintf (fout,"lxc.seccomp=\n"); } fprintf (fout,"lxc.arch = x86_64\n"); fprintf (fout,"lxc.autodev=0\n"); fprintf (fout,"lxc.cap.drop = sys_admin\n"); fprintf (fout,"lxc.cap.drop = mknod\n"); fprintf (fout,"lxc.cap.drop = net_raw\n"); fprintf (fout,"lxc.mount.auto =\n"); return 0; } void lxc_config (const char *name, const char *ip, bool internet_access) { lxc_config (name,name,ip,internet_access); } void lxc_config (const char *name, const char *ip) { lxc_config (name,ip,false); } void _F_lxc_stop::pre_insert (FILE *fout, const char *name, const char *command, const char *command_path, int workers) { } void _F_lxc_stop::post_insert (FILE *fout, const char *name, const char *command, const char *command_path, int workers) { } void _F_lxc_stop::insert (FILE *fout, const char *name, const char *command, const char *command_path, int workers) { if (command != NULL){ if (workers == -1){ fprintf (fout,"%s/%s-control -p /var/lib/lxc/%s/rootfs%s/%s.sock quit\n" ,command_path,command,name,lxcsock_dir,command); }else{ for (int i=0; i void lxc_stop (_F_lxc_stop &c, const char *name, const char *command, const char *command_path, int workers, string &stopfile) { glocal _F_lxc_stop *c = &c; glocal const char *name = name; glocal const char *command = command; glocal const char *command_path = command_path; glocal int workers = workers; glocal string horizonfile = string_f ("/var/lib/lxc/%s/horizon-stop.sh",name); (glocal.horizonfile,false); fprintf (fout,"#!/usr/bin/sh\n"); glocal.c->horizon(fout,glocal.name); fprintf (fout,"%s/horizon-control -p %s/horizon.sock vserver %s -\n" ,blackhole_path,sock_dir,glocal.name); fprintf (fout,"%s/horizon-control -p %s/horizon.sock vserverdir %s -\n" ,blackhole_path,sock_dir,glocal.name); fprintf (fout,"%s/horizon-control -p %s/horizon.sock unbindfd unix /dev/log %s\n" ,blackhole_path,sock_dir,glocal.name); return 0; trli_chmod (glocal.horizonfile,0755); stopfile = string_f ("/var/lib/lxc/%s/%s.stop",name,name); (stopfile,false); fprintf (fout,"#!/bin/sh\n"); glocal.c->pre_insert (fout,glocal.name,glocal.command,glocal.command_path,glocal.workers); glocal.c->insert (fout,glocal.name,glocal.command,glocal.command_path,glocal.workers); glocal.c->post_insert (fout,glocal.name,glocal.command,glocal.command_path,glocal.workers); fprintf (fout,"%s\n",glocal.horizonfile.c_str()); fprintf (fout,"/var/lib/lxc/%s/%s.save\n",glocal.name,glocal.name); return 0; trli_chmod (stopfile,0755); } void lxc_stop (const char *name, const char *command, const char *command_path, int workers, string &stopfile) { (name,command,command_path,workers,stopfile); } void _F_lxc_start::prestart (FILE *fout, const char *name) { } void _F_lxc_start::pre_insert(FILE *fout, const char *name, const char *command, int workers) { } void _F_lxc_start::post_insert(FILE *fout, const char *name, const char *command, int workers) { } void _F_lxc_start::delayed(FILE *fout, const char *name, const char *command, int workers) { delayed_notused = true; } void _F_lxc_start::horizon (FILE *fout, const char *name) { } void _F_lxc_stop::horizon (FILE *fout, const char *name) { } void lxc_start (_F_lxc_start &c, const char *name, const char *ip, string &startfile, string &delayfile, const char *user, int userid) { glocal _F_lxc_start *c = &c; glocal const char *name = name; glocal const char *ip = ip; glocal const char *user = user; glocal int userid = userid; glocal string horizonfile = string_f ("/var/lib/lxc/%s/horizon-start.sh",name); c.delayed_notused = false; (glocal.horizonfile,false); fprintf (fout,"#!/bin/sh\n"); fprintf (fout,"%s/horizon-control -p %s/horizon.sock vserver %s %s\n" ,blackhole_path,sock_dir,glocal.name,glocal.ip); fprintf (fout,"%s/horizon-control -p %s/horizon.sock vserverdir %s /var/lib/lxc/%s/rootfs\n" ,blackhole_path,sock_dir,glocal.name,glocal.name); fprintf (fout,"%s/horizon-control -p %s/horizon.sock --bind unix,/dev/log:/var/lib/lxc/%s/rootfs/dev/log,%s\n" ,blackhole_path,sock_dir,glocal.name,glocal.name); fprintf (fout,"chmod 666 /var/lib/lxc/%s/rootfs/dev/log\n",glocal.name); glocal.c->horizon(fout,glocal.name); return 0; trli_chmod (glocal.horizonfile,0755); startfile = string_f ("/var/lib/lxc/%s/%s.start",name,name); (startfile,false); string lxcdir_s = string_f ("%s/%s",varlxc,glocal.name); const char *lxcdir = lxcdir_s.c_str(); fprintf (fout,"#!/usr/bin/sh\n"); fprintf (fout,"execif(){\n"); fprintf (fout,"\tif [ -x $1 ] ; then\n"); fprintf (fout,"\t\t$1\n"); fprintf (fout,"\telse\n"); fprintf (fout,"\t\treturn 0\n"); fprintf (fout,"\tfi\n"); fprintf (fout,"}\n"); fprintf (fout,"if lxc-info -s -n %s | grep -q RUNNING\n",glocal.name); fprintf (fout,"then\n"); fprintf (fout,"\techo %s already running\n\texit 1\n",glocal.name); fprintf (fout,"fi\n"); glocal.c->prestart (fout,glocal.name); fprintf (fout,"rm -fr /var/lib/lxc/%s/rootfs\n",glocal.name); fprintf (fout,"/var/lib/lxc/%s/%s-lxc0.sh\n",glocal.name,glocal.name); // lxc0 might have linked /etc/passwd and /etc/hosts fprintf (fout,"rm -f /var/lib/lxc/%s/rootfs/etc/passwd\n",glocal.name); fprintf (fout,"rm -f /var/lib/lxc/%s/rootfs/etc/hosts\n",glocal.name); fprintf (fout,"rm -f /var/lib/lxc/%s/rootfs/etc/group\n",glocal.name); // Creates a generic /etc/passwd fprintf (fout,"echo \"root:x:0:0:root:/root:/sbin/nologin\" >/var/lib/lxc/%s/rootfs/etc/passwd\n" ,glocal.name); fprintf (fout,"echo \"%s:x:%d:%d:trli user:/home/trli:/sbin/nologin\" >>/var/lib/lxc/%s/rootfs/etc/passwd\n" ,glocal.user,glocal.userid,glocal.userid,glocal.name); // Creates a generic /etc/group fprintf (fout,"echo \"root:x:0:\" >/var/lib/lxc/%s/rootfs/etc/group\n",glocal.name); fprintf (fout,"echo \"apache:x:48:\" >>/var/lib/lxc/%s/rootfs/etc/group\n",glocal.name); fprintf (fout,"echo \"mysql:x:27:\" >>/var/lib/lxc/%s/rootfs/etc/group\n",glocal.name); fprintf (fout,"echo \"exim:x:93:\" >>/var/lib/lxc/%s/rootfs/etc/group\n",glocal.name); fprintf (fout,"echo \"mail:x:12:exim\" >>/var/lib/lxc/%s/rootfs/etc/group\n",glocal.name); fprintf (fout,"echo 127.0.0.1 localhost >/var/lib/lxc/%s/rootfs/etc/hosts\n",glocal.name); fprintf (fout,"echo %s %s >>/var/lib/lxc/%s/rootfs/etc/hosts\n",glocal.ip,glocal.name,glocal.name); fprintf (fout,"cp /var/lib/lxc/%s/%s.init /var/lib/lxc/%s/rootfs/tmp/config\n",glocal.name,glocal.name,glocal.name); fprintf (fout,"%s/%s.restore\n",lxcdir,glocal.name); glocal.c->pre_insert (fout,glocal.name,"",0); glocal.c->insert (fout,glocal.name,"",0); fprintf (fout,"%s\n",glocal.horizonfile.c_str()); fprintf (fout,"execif %s/%s.prestart\n",lxcdir,glocal.name); fprintf (fout,"lxc-start -n %s\n",glocal.name); glocal.c->post_insert (fout,glocal.name,"",0); fprintf (fout,"execif %s/%s.poststart\n",lxcdir,glocal.name); return 0; trli_chmod (startfile,0755); // Optional delayed processing (generally performed after all services have been started) delayfile = string_f ("/var/lib/lxc/%s/%s.start-delayed",name,name); (delayfile,false); fprintf (fout,"#!/usr/bin/sh\n"); glocal.c->delayed (fout,glocal.name,"",0); return 0; if (c.delayed_notused){ unlink (delayfile.c_str()); delayfile.clear(); }else{ trli_chmod (delayfile,0755); } } void lxc_start (_F_lxc_start &c, const char *name, const char *ip, string &startfile, const char *user, int userid) { string delayfile; lxc_start (c,name,ip,startfile,delayfile,user,userid); if (delayfile.size() > 0){ tlmp_error ("startup delay file for service %s was generated, but not used\n",name); } } void lxc_start (const char *name, const char *ip, string &startfile, const char *user, int userid) { (name,ip,startfile,user,userid); } void lxc_start (const char *name, const char *ip, string &startfile) { lxc_start (name,ip,startfile,manager_user,manager_userid); } void lxc_status (const char *binpath, const char *name, const char *command, int workers) { glocal const char *name = name; glocal const char *command = command; glocal int workers = workers; glocal const char *binpath = binpath; string tmp = string_f ("/var/lib/lxc/%s/status.sh",name); (tmp,false); if (glocal.workers == -1){ fprintf (fout,"%s/%s-control -p /var/lib/lxc/%s/rootfs%s/%s.sock status\n" ,glocal.binpath,glocal.command,glocal.name,lxcsock_dir,glocal.command); }else{ for (int i=0; i trli_chmod (tmp,0755); } void lxc_status (const char *name, const char *command, int workers) { lxc_status (sbin_path,name,command,workers); } static void lxc_debug_one (FILE *fout, const char *hc) { fprintf (fout,"if [ \"$1\" = off ]; then\n"); fprintf (fout,"\t%s debug 0\n",hc); fprintf (fout,"elif [ \"$1\" = on ]; then\n"); fprintf (fout,"\t%s debug 1\n",hc); fprintf (fout,"else\n"); fprintf (fout,"\techo on or off\n"); fprintf (fout,"fi\n"); } void lxc_debug (const char *binpath, const char *name, const char *command, int workers) { glocal const char *name = name; glocal const char *command = command; glocal int workers = workers; glocal const char *binpath = binpath; string tmp = string_f ("/var/lib/lxc/%s/debug.sh",name); (tmp,false); if (glocal.workers == -1){ string hc_str = string_f ("%s/%s-control -p /var/lib/lxc/%s/rootfs%s/%s.sock" ,glocal.binpath,glocal.command,glocal.name,lxcsock_dir,glocal.command); const char *hc = hc_str.c_str(); fprintf (fout,"%s debugfile /tmp/%s-debug.log\n",hc,glocal.name); lxc_debug_one (fout,hc); }else{ fprintf (fout,"#!/bin/sh\n"); for (int i=0; i trli_chmod (tmp,0755); } void lxc_debug (const char *name, const char *command, int workers) { lxc_debug (sbin_path,name,command,workers); } void config_sql (const char *name, const char *ip, string &startfile, string &stopfile) { glocal string sock = string_f("/var/lib/lxc/%s/rootfs/var/lib/mysql/mysql.sock",name); string rootdir = string_f("/var/lib/lxc/%s",name); mkdir (rootdir.c_str(),0755); (string_f ("%s/%s.init",rootdir.c_str(),name),false); fprintf (fout,"/usr/libexec/mysqld --basedir=/usr --user=mysql --character-set-server=utf8mb4\n"); return 0; (name,ip,startfile,"mysql",27); fprintf (fout,"if [ -d /var/lib/lxc/%s/rootfs/var/lib/mysql ] ; then\n",name); fprintf (fout,"\techo \"Directory /var/lib/mysql exist in container %s\"\n",name); fprintf (fout,"\techo Abort\n"); fprintf (fout,"\texit 1\n"); fprintf (fout,"elif [ ! -d /var/lib/lxc/%s/data/mysql ]; then\n",name); fprintf (fout,"\techo \"No directory mysql found in /var/lib/lxc/%s/data, creating one\"\n",name); fprintf (fout,"\tmkdir -p /var/lib/lxc/%s/data\n",name); fprintf (fout,"\tmysql_install_db --user=mysql --datadir=/var/lib/lxc/%s/data/mysql" " >/var/lib/lxc/%s/mysql_install_db.log\n" ,name,name); fprintf (fout,"fi\n"); fprintf (fout,"cat <<-EOF >/var/lib/lxc/%s/rootfs/etc/my.cnf.d/notcp.cnf\n",name); fprintf (fout,"[mysqld]\n"); fprintf (fout,"skip-networking\n"); fprintf (fout,"EOF\n"); // We are not using rocksdb and it just grow logs ... fprintf (fout,"rm -f /var/lib/lxc/%s/rootfs/etc/my.cnf.d/rocksdb.cnf\n",name); (name,NULL,NULL,-1,stopfile); fprintf (fout,"/usr/sbin/vkillall -n %s /usr/libexec/mysqld\n",name); fprintf (fout,"echo -n \"Stopping %s \"\n",name); fprintf (fout,"for ((i=0; i<5; i++))\n"); fprintf (fout,"do\n"); fprintf (fout,"\techo -n .\n"); fprintf (fout,"\tsleep 1\n"); fprintf (fout,"\tRUNNING=`lxc-info -s -n %s | grep -q RUNNING && echo running`\n",name); fprintf (fout,"\tif [ \"$RUNNING\" = \"\" ] ; then\n"); fprintf (fout,"\t\tbreak\n"); fprintf (fout,"\tfi\n"); fprintf (fout,"done\n"); fprintf (fout,"echo\n"); fprintf (fout,"lxc-info -s -n %s | grep -q RUNNING && (echo Force stop %s; lxc-stop -n %s)\n" ,name,name,name); lxc_config (name,ip); string runsql = string_f ("%s/%s.runsql",rootdir.c_str(),name); (runsql,false); fprintf (fout,"#!/bin/sh\n"); fprintf (fout,"if [ $# = 0 ] ; then\n"); fprintf (fout,"\techo table\n"); fprintf (fout,"\texit 1\n"); fprintf (fout,"fi\n"); fprintf (fout,"mysql -S %s $*\n",glocal.sock.c_str()); return 0; trli_chmod (runsql,0755); string admsql = string_f ("%s/%s.admsql",rootdir.c_str(),name); (admsql,false); fprintf (fout,"#!/bin/sh\n"); fprintf (fout,"if [ $# = 0 ] ; then\n"); fprintf (fout,"\techo command\n"); fprintf (fout,"\texit 1\n"); fprintf (fout,"fi\n"); fprintf (fout,"mysqladmin -S %s $*\n",glocal.sock.c_str()); return 0; trli_chmod (admsql,0755); } void _F_config_web::insertconf (FILE *, const char *){} void config_web (_F_config_web &c, const char *name, const char *ip, string &startfile, string &stopfile) { glocal _F_config_web *c = &c; mkdir (string_f("/var/lib/lxc/%s",name).c_str(),0755); (string_f("/var/lib/lxc/%s/%s.init",name,name),false); fprintf (fout,"/usr/sbin/httpd --daemon\n"); return 0; (name,ip,startfile,"apache",48); fprintf (fout,"#!/bin/sh\n"); fprintf (fout,"echo nameserver %s >/var/lib/lxc/%s/rootfs/etc/resolv.conf\n" ,horizon_ip,name); fprintf (fout,"echo \"RequestHeader edit Destination ^https: http: early\" >/var/lib/lxc/webssl/rootfs/etc/httpd/conf.d/a_svncopy.conf\n"); glocal.c->insertconf (fout,name); fprintf (fout,"ROOT=/var/lib/lxc/%s/rootfs\n",name); fprintf (fout,"for FILE in /etc/httpd/conf.d/add.conf /etc/httpd/conf.d/le_http_01_challenge_pre.conf /etc/httpd/conf.d/le_http_01_challenge_post.conf\n"); fprintf (fout,"do\n"); fprintf (fout," if [ -f $FILE ] ; then\n"); fprintf (fout," cp -a $FILE $ROOT/etc/httpd/conf.d/.\n"); fprintf (fout," cp -a $FILE /tmp/.\n"); fprintf (fout," fi\n"); fprintf (fout,"done\n"); fprintf (fout,"if [ -d /var/lib/letsencrypt ] ; then\n"); fprintf (fout," mkdir -p $ROOT/var/lib/letsencrypt\n"); fprintf (fout," cp -a /var/lib/letsencrypt/. $ROOT/var/lib/letsencrypt/.\n"); fprintf (fout,"fi\n"); lxc_stop (name,NULL,NULL,-1,stopfile); lxc_config (name,"solucorp.solutions",ip,true); } void tlmpweb_conf (FILE *fout, const char *name) { fprintf (fout,"cat <<-EOF >/var/lib/lxc/%s/rootfs/etc/httpd/conf.d/tlmpweb.conf\n",name); fprintf (fout,"AddType application/x-httpd-hc .hc\n"); fprintf (fout,"Action application/x-httpd-hc /cgi-bin/tlmpweb\n"); fprintf (fout,"DirectoryIndex index.hc\n"); fprintf (fout,"EOF\n"); } void config_syslog(string &startfile, string &stopfile, const char *devlog, const char *devlog_user, const char *run_as_user) { glocal const char *devlog = devlog; glocal const char *run_as_user = run_as_user; glocal const char *devlog_user = devlog_user; startfile = "/var/lib/lxc/trli-syslog-start.sh"; (startfile,false); fprintf (fout,"#!/bin/sh\n"); fprintf (fout,"/usr/sbin/trli-syslog --daemon --logport %s --user %s\n" ,glocal.devlog,glocal.run_as_user); fprintf (fout,"chown %s %s\n",glocal.devlog_user,glocal.devlog); fprintf (fout,"chown %s /var/run/blackhole/trli-syslog.sock\n",glocal.devlog_user); return 0; trli_chmod (startfile,0755); stopfile = "/var/lib/lxc/trli-syslog-stop.sh"; (stopfile,false); fprintf (fout,"#!/bin/sh\n"); fprintf (fout,"/usr/sbin/trli-syslog-control quit\n"); return 0; trli_chmod (stopfile,0755); }