root/trunk/jobqueue.c

Revision 1928, 154.2 KB (checked in by Dylan, 3 weeks ago)

unxsVZ ExecuteCommands? and support for cHostname lists have been added to the search set tContainer page and alpha tested.

  • Property svn:keywords set to id
Line 
1/*
2FILE
3        jobqueue.c
4        $Id$
5PURPOSE
6        Command line processing of jobs in the tJob queue.
7AUTHOR/LEGAL
8        (C) 2008-2011 Gary Wallis for Unxiservice, LLC.
9        GPLv2 license applies. See LICENSE file included.
10NOTES
11        We still use KISS code, var naming conventions, and Allman (ANSI) style C
12        indentation to make our software readable and writable by any programmer.
13        At the same time this approach (although with some redundant code) has kept these
14        programs lean and faster than anything available in any other language.
15TODO
16        Create more #define based "macros," to help the compiler optimize the
17        many simple, fast but redundant code blocks.
18        Get rid of any goto statements that do not add too many layers of nested
19        logic that makes the code hard to maintain by non-authors.
20        Use uNotValidSystemCallArg() before all system() calls where any args
21        come from db and are not formatted (sprintf) as numbers.
22FILE CONTENTS
23        1-. Top redundant protos as the appear in file for a simple TOC.
24        2-. More protos: Major external functions used.
25        3-. File scoped vars.
26        4-. Top level functions.
27        5-. Rest of functions.
28*/
29
30#include "mysqlrad.h"
31#include <openisp/template.h>
32#include <sys/sysinfo.h>
33
34//
35//The following prototype declarations should provide a
36//      table of contents
37
38//local protos, order=ret type, in file
39void ProcessJobQueue(unsigned uDebug);
40void ProcessJob(unsigned uJob,unsigned uDatacenter,unsigned uNode,
41                unsigned uContainer,char *cJobName,char *cJobData);
42void tJobErrorUpdate(unsigned uJob, const char *cErrorMsg);
43void tJobDoneUpdate(unsigned uJob);
44void tJobWaitingUpdate(unsigned uJob);
45void NewContainer(unsigned uJob,unsigned uContainer);
46void DestroyContainer(unsigned uJob,unsigned uContainer);
47void ChangeIPContainer(unsigned uJob,unsigned uContainer,char *cJobData);
48void SwapIPContainer(unsigned uJob,unsigned uContainer,char *cJobData);
49void ChangeHostnameContainer(unsigned uJob,unsigned uContainer,char *cJobData);
50void ExecuteCommands(unsigned uJob,unsigned uContainer,char *cJobData);
51void StopContainer(unsigned uJob,unsigned uContainer);
52void StartContainer(unsigned uJob,unsigned uContainer);
53void MigrateContainer(unsigned uJob,unsigned uContainer,char *cJobData);
54void GetGroupProp(const unsigned uGroup,const char *cName,char *cValue);
55void GetContainerProp(const unsigned uContainer,const char *cName,char *cValue);
56void UpdateContainerUBC(unsigned uJob,unsigned uContainer,const char *cJobData);
57void SetContainerUBC(unsigned uJob,unsigned uContainer,const char *cJobData);
58void TemplateContainer(unsigned uJob,unsigned uContainer,const char *cJobData);
59void ActionScripts(unsigned uJob,unsigned uContainer);
60void AllowAccess(unsigned uJob,const char *cJobData);
61void DenyAccess(unsigned uJob,const char *cJobData);
62void CloneContainer(unsigned uJob,unsigned uContainer,char *cJobData);
63void CloneRemoteContainer(unsigned uJob,unsigned uContainer,char *cJobData,unsigned uNewVeid);
64void AppFunctions(FILE *fp,char *cFunction);
65void LocalImportTemplate(unsigned uJob,unsigned uDatacenter,const char *cJobData);
66void LocalImportConfig(unsigned uJob,unsigned uDatacenter,const char *cJobData);
67void FailoverTo(unsigned uJob,unsigned uContainer,const char *cJobData);
68void FailoverFrom(unsigned uJob,unsigned uContainer,const char *cJobData);
69void GetIPFromtIP(const unsigned uIPv4,char *cIP);
70void GetNodeProp(const unsigned uNode,const char *cName,char *cValue);
71void GetDatacenterProp(const unsigned uDatacenter,const char *cName,char *cValue);
72void logfileLine(const char *cFunction,const char *cLogline);
73void LogError(char *cErrorMsg,unsigned uKey);
74void RecurringJob(unsigned uJob,unsigned uDatacenter,unsigned uNode,unsigned uContainer,const char *cJobData);
75void SetJobStatus(unsigned uJob,unsigned uJobStatus);
76
77unsigned uNotValidSystemCallArg(char *cSSHOptions);
78unsigned GetContainerStatus(const unsigned uContainer, unsigned *uStatus);
79unsigned GetContainerMainIP(const unsigned uContainer,char *cIP);
80unsigned GetContainerSource(const unsigned uContainer, unsigned *uSource);
81unsigned SetContainerIP(const unsigned uContainer,char *cIP);
82unsigned SetContainerSource(const unsigned uContainer,const unsigned uSource);
83unsigned SetContainerHostname(const unsigned uContainer,
84                        const char *cHostname,const char *cLabel);
85unsigned GetContainerNames(const unsigned uContainer,char *cHostname,char *cLabel);
86unsigned GetContainerNodeStatus(const unsigned uContainer, unsigned *uStatus);
87unsigned SetContainerProperty(const unsigned uContainer,const char *cPropertyName,const  char *cPropertyValue);
88unsigned FailToJobDone(unsigned uJob);
89unsigned ProcessCloneSyncJob(unsigned uNode,unsigned uContainer,unsigned uCloneContainer);
90unsigned ProcessOSDeltaSyncJob(unsigned uNode,unsigned uContainer,unsigned uCloneContainer);
91
92int CreateActionScripts(unsigned uContainer, unsigned uOverwrite);
93
94//extern protos
95unsigned TextConnectDb(void); //mysqlconnect.c
96void SetContainerStatus(unsigned uContainer,unsigned uStatus);
97void SetContainerNode(unsigned uContainer,unsigned uNode);
98void SetContainerDatacenter(unsigned uContainer,unsigned uDatacenter);
99void GetConfiguration(const char *cName,char *cValue,
100                unsigned uDatacenter,
101                unsigned uNode,
102                unsigned uContainer,
103                unsigned uHtml);
104
105//file scoped vars.
106static unsigned gfuNode=0;
107static unsigned gfuDatacenter=0;
108static unsigned guDebug=0;
109static char cHostname[100]={""};//file scope
110static FILE *gLfp=NULL;//log file
111
112
113//Using the local server hostname get max 32 jobs for this node from the tJob queue.
114//Then dispatch jobs via ProcessJob() this function in turn calls specific functions for
115//each known cJobName.
116void ProcessJobQueue(unsigned uDebug)
117{
118        MYSQL_RES *res;
119        MYSQL_ROW field;
120        unsigned uDatacenter=0;
121        unsigned uNode=0;
122        unsigned uContainer=0;
123        unsigned uCloneContainer=0;
124        unsigned uJob=0;
125        unsigned uError=0;
126        struct sysinfo structSysinfo;
127
128        if(uDebug) guDebug=1;
129
130        if((gLfp=fopen(cLOGFILE,"a"))==NULL)
131        {
132                fprintf(stderr,"Could not open logfile: %s\n",cLOGFILE);
133                exit(300);
134        }
135
136        if(gethostname(cHostname,99)!=0)
137        {
138                logfileLine("ProcessJobQueue","gethostname() failed");
139                exit(1);
140        }
141
142        if(sysinfo(&structSysinfo))
143        {
144                logfileLine("ProcessJobQueue","sysinfo() failed");
145                exit(1);
146        }
147#define LINUX_SYSINFO_LOADS_SCALE 65536
148#define JOBQUEUE_MAXLOAD 10 //This is equivalent to uptime 10.00 last 5 min avg load
149        if(structSysinfo.loads[1]/LINUX_SYSINFO_LOADS_SCALE>JOBQUEUE_MAXLOAD)
150        {
151                sprintf(gcQuery,"structSysinfo.loads[1]=%lu larger than JOBQUEUE_MAXLOAD=%u",
152                                structSysinfo.loads[1]/LINUX_SYSINFO_LOADS_SCALE,JOBQUEUE_MAXLOAD);
153                logfileLine("ProcessJobQueue",gcQuery);
154                exit(1);
155        }
156        //debug only
157        //sprintf(gcQuery,"%2.2f",(float)structSysinfo.loads[1]/(float)LINUX_SYSINFO_LOADS_SCALE);
158        //logfileLine("structSysinfo.loads",gcQuery);
159        //exit(0);
160
161        //Uses login data from local.h
162        if(TextConnectDb())
163                exit(1);
164
165        guLoginClient=1;//Root user
166
167        //Get node and datacenter via hostname
168        sprintf(gcQuery,"SELECT uNode,uDatacenter FROM tNode WHERE cLabel='%.99s'",cHostname);
169        mysql_query(&gMysql,gcQuery);
170        if(mysql_errno(&gMysql))
171        {
172                logfileLine("ProcessJobQueue",mysql_error(&gMysql));
173                mysql_close(&gMysql);
174                exit(2);
175        }
176        res=mysql_store_result(&gMysql);
177        if((field=mysql_fetch_row(res)))
178        {
179                sscanf(field[0],"%u",&uNode);
180                sscanf(field[1],"%u",&uDatacenter);
181        }
182        mysql_free_result(res);
183
184        //FQDN vs short name of 2nd NIC mess
185        if(!uNode)
186        {
187                char *cp;
188
189                if((cp=strchr(cHostname,'.')))
190                        *cp=0;
191                sprintf(gcQuery,"SELECT uNode,uDatacenter FROM tNode WHERE cLabel='%.99s'",cHostname);
192                mysql_query(&gMysql,gcQuery);
193                if(mysql_errno(&gMysql))
194                {
195                        logfileLine("ProcessJobQueue",mysql_error(&gMysql));
196                        mysql_close(&gMysql);
197                        exit(2);
198                }
199                res=mysql_store_result(&gMysql);
200                if((field=mysql_fetch_row(res)))
201                {
202                        sscanf(field[0],"%u",&uNode);
203                        sscanf(field[1],"%u",&uDatacenter);
204                }
205                mysql_free_result(res);
206        }
207
208        if(!uNode)
209        {
210                logfileLine("ProcessJobQueue","could not determine uNode: aborted");
211                mysql_close(&gMysql);
212                exit(1);
213        }
214
215        //Some file scoped globals we need to cleanout someday
216        gfuNode=uNode;
217        gfuDatacenter=uDatacenter;
218
219        //Special recurring jobs based on special containers
220        //Main loop normal jobs
221        //1-. Maintain clone containers
222        //We need to rsync from running container to clone container
223        //where the source container is running on this node
224        //and the target node is a remote node.
225        //1 uACTIVE
226        //31 uSTOPPED
227        //logfileLine("ProcessCloneSyncJob","Start");
228        //Select clone containers of active or stopped source containers
229        //running on this node
230        sprintf(gcQuery,"SELECT t1.uContainer,t2.uContainer,t1.uStatus FROM tContainer AS t1,tContainer AS t2"
231                        " WHERE (t2.uStatus=1 OR t2.uStatus=31)"
232                        " AND t1.uSource=t2.uContainer AND t2.uNode=%u",uNode);
233        mysql_query(&gMysql,gcQuery);
234        if(mysql_errno(&gMysql))
235        {
236                logfileLine("CloneSync",mysql_error(&gMysql));
237                mysql_close(&gMysql);
238                exit(2);
239        }
240        res=mysql_store_result(&gMysql);
241        while((field=mysql_fetch_row(res)))
242        {
243                unsigned uCloneStatus=0;
244
245                if(sysinfo(&structSysinfo))
246                {
247                        logfileLine("CloneSync","sysinfo() failed");
248                        mysql_free_result(res);
249                        fclose(gLfp);
250                        mysql_close(&gMysql);
251                        exit(0);
252                }
253                if(structSysinfo.loads[1]/LINUX_SYSINFO_LOADS_SCALE>(JOBQUEUE_MAXLOAD/2))
254                {
255                        logfileLine("CloneSync","structSysinfo.loads[1] too high");
256                        mysql_free_result(res);
257                        fclose(gLfp);
258                        mysql_close(&gMysql);
259                        exit(0);
260                }
261                sscanf(field[0],"%u",&uCloneContainer);
262                sscanf(field[1],"%u",&uContainer);
263                sscanf(field[2],"%u",&uCloneStatus);
264                if(guDebug)
265                {
266                        sprintf(gcQuery,"uCloneStatus=%u",uCloneStatus);
267                        logfileLine("CloneSync",gcQuery);
268                }
269
270                switch(uCloneStatus)
271                {
272                        //We only move the delta files to the
273                        //remote node for backup (cold spare) and possible remote failover BC/DR.
274                        //Provided sample script osdeltasync.sh handles the details.
275                        case uINITSETUP:
276                                if((uError=ProcessOSDeltaSyncJob(uNode,uContainer,uCloneContainer)))
277                                {
278                                        logfileLine("ProcessOSDeltaCloneSyncJob uError",field[1]);
279                                        //error return(6) when clone script fails.
280                                        if(uError!=6)
281                                                LogError("ProcessOSDeltaCloneSyncJob()",uError);
282                                }
283                        break;
284
285                        //Here provided sample script clonesync.sh does an rsync
286                        //and keeps the clone container as warm spare.
287                        case uSTOPPED:
288                        case uACTIVE:
289                                if((uError=ProcessCloneSyncJob(uNode,uContainer,uCloneContainer)))
290                                {
291                                        logfileLine("ProcessCloneSyncJob uError",field[1]);
292                                        //error return(6) when clone script fails.
293                                        if(uError!=6)
294                                                LogError("ProcessCloneSyncJob()",uError);
295                                }
296                }
297        }
298        mysql_free_result(res);
299
300        if(guDebug)
301        {
302                sprintf(gcQuery,"Start %s(uNode=%u,uDatacenter=%u)",cHostname,uNode,uDatacenter);
303                logfileLine("ProcessJobQueue",gcQuery);
304        }
305
306        //
307        //Main loop normal jobs
308        //uWAITING==1
309        //TODO can the LIMIT partition related jobs that need to run close together?
310        //Testing allow only one to run at the same time.
311        if(mkdir("/var/run/unxsvz.lock",S_IRWXU))
312        {
313                logfileLine("ProcessJobQueue","/var/run/unxsvz.lock");
314                exit(127);
315        }
316
317        sprintf(gcQuery,"SELECT uJob,uContainer,cJobName,cJobData FROM tJob WHERE uJobStatus=1"
318                                " AND (uDatacenter=%u OR uDatacenter=0) AND (uNode=%u OR uNode=0)" //uDatacenter,uNode=0 all type jobs
319                                " AND uJobDate<=UNIX_TIMESTAMP(NOW()) ORDER BY uJob LIMIT 128",
320                                                uDatacenter,uNode);
321        mysql_query(&gMysql,gcQuery);
322        if(mysql_errno(&gMysql))
323        {
324                logfileLine("ProcessJobQueue",mysql_error(&gMysql));
325                mysql_close(&gMysql);
326                if(rmdir("/var/run/unxsvz.lock"))
327                        logfileLine("ProcessJobQueue","/var/run/unxsvz.lock rmdir error");
328                exit(2);
329        }
330        res=mysql_store_result(&gMysql);
331        while((field=mysql_fetch_row(res)))
332        {
333                if(sysinfo(&structSysinfo))
334                {
335                        logfileLine("ProcessJobQueue","sysinfo() failed");
336                        exit(1);
337                }
338                if(structSysinfo.loads[1]/LINUX_SYSINFO_LOADS_SCALE>JOBQUEUE_MAXLOAD)
339                {
340                        logfileLine("ProcessJobQueue-mainloop","structSysinfo.loads[1] too high");
341                        mysql_free_result(res);
342                        if(rmdir("/var/run/unxsvz.lock"))
343                                logfileLine("ProcessJobQueue-mainloop","/var/run/unxsvz.lock rmdir error");
344                        fclose(gLfp);
345                        mysql_close(&gMysql);
346                        exit(0);
347                }
348                sscanf(field[0],"%u",&uJob);
349                sscanf(field[1],"%u",&uContainer);
350                //Job dispatcher based on cJobName
351                //These log entries combined with the output of system calls will provide framing
352                sprintf(gcQuery,"Start %s",field[2]);
353                logfileLine("ProcessJobQueue",gcQuery);
354                ProcessJob(uJob,uDatacenter,uNode,uContainer,field[2],field[3]);
355                logfileLine("ProcessJobQueue","End");
356        }
357        mysql_free_result(res);
358
359        if(rmdir("/var/run/unxsvz.lock"))
360                logfileLine("ProcessJobQueue","/var/run/unxsvz.lock rmdir error");
361        if(guDebug) logfileLine("ProcessJobQueue","End");
362        fclose(gLfp);
363        mysql_close(&gMysql);
364        exit(0);
365
366}//void ProcessJobQueue()
367
368
369
370void ProcessJob(unsigned uJob,unsigned uDatacenter,unsigned uNode,
371                unsigned uContainer,char *cJobName,char *cJobData)
372{
373        //Some jobs may take quite some time, we need to make sure we don't run again!
374        sprintf(gcQuery,"UPDATE tJob SET uJobStatus=2,cRemoteMsg='Running',uModBy=1,"
375                                "uModDate=UNIX_TIMESTAMP(NOW()) WHERE uJob=%u",uJob);
376        mysql_query(&gMysql,gcQuery);
377        if(mysql_errno(&gMysql))
378                logfileLine("ProcessJob()",mysql_error(&gMysql));
379
380
381        //if debug
382        //printf("%3.3u uJob=%u uContainer=%u cJobName=%s; cJobData=%s;\n",
383        //              uCount++,uJob,uContainer,cJobName,cJobData);
384
385        //Is priority order needed in some cases?
386        if(!strcmp(cJobName,"FailoverTo"))
387        {
388                FailoverTo(uJob,uContainer,cJobData);
389        }
390        else if(!strcmp(cJobName,"FailoverFrom"))
391        {
392                FailoverFrom(uJob,uContainer,cJobData);
393        }
394        else if(!strcmp(cJobName,"MigrateContainer"))
395        {
396                MigrateContainer(uJob,uContainer,cJobData);
397        }
398        else if(!strcmp(cJobName,"CloneContainer"))
399        {
400                CloneContainer(uJob,uContainer,cJobData);
401        }
402        else if(!strcmp(cJobName,"NewContainer"))
403        {
404                NewContainer(uJob,uContainer);
405        }
406        else if(!strcmp(cJobName,"AllowAccess") && uNode)
407        {
408                AllowAccess(uJob,cJobData);
409        }
410        else if(!strcmp(cJobName,"DenyAccess") && uNode)
411        {
412                DenyAccess(uJob,cJobData);
413        }
414        else if(!strcmp(cJobName,"ActionScripts"))
415        {
416                //OpenVZ action scripts
417                ActionScripts(uJob,uContainer);
418        }
419        else if(!strcmp(cJobName,"StartContainer"))
420        {
421                StartContainer(uJob,uContainer);
422        }
423        else if(!strcmp(cJobName,"ChangeHostnameContainer"))
424        {
425                ChangeHostnameContainer(uJob,uContainer,cJobData);
426        }
427        else if(!strcmp(cJobName,"ExecuteCommands"))
428        {
429                ExecuteCommands(uJob,uContainer,cJobData);
430        }
431        else if(!strcmp(cJobName,"ChangeIPContainer"))
432        {
433                ChangeIPContainer(uJob,uContainer,cJobData);
434        }
435        else if(!strcmp(cJobName,"SwapIPContainer"))
436        {
437                SwapIPContainer(uJob,uContainer,cJobData);
438        }
439        else if(!strcmp(cJobName,"StopContainer"))
440        {
441                StopContainer(uJob,uContainer);
442        }
443        else if(!strcmp(cJobName,"DestroyContainer"))
444        {
445                DestroyContainer(uJob,uContainer);
446        }
447        else if(!strcmp(cJobName,"UpdateContainerUBCJob"))
448        {
449                UpdateContainerUBC(uJob,uContainer,cJobData);
450        }
451        else if(!strcmp(cJobName,"SetUBCJob"))
452        {
453                SetContainerUBC(uJob,uContainer,cJobData);
454        }
455        else if(!strcmp(cJobName,"TemplateContainer"))
456        {
457                TemplateContainer(uJob,uContainer,cJobData);
458        }
459        else if(!strcmp(cJobName,"LocalImportTemplateJob"))
460        {
461                LocalImportTemplate(uJob,uDatacenter,cJobData);
462        }
463        else if(!strcmp(cJobName,"LocalImportConfigJob"))
464        {
465                LocalImportConfig(uJob,uDatacenter,cJobData);
466        }
467        else if(!strcmp(cJobName,"RecurringJob"))
468        {
469                RecurringJob(uJob,uDatacenter,uNode,uContainer,cJobData);
470        }
471        else if(1)
472        {
473                logfileLine("ProcessJob()",cJobName);
474                tJobErrorUpdate(uJob,cJobName);
475        }
476
477}//ProcessJob(...)
478
479
480//Shared functions
481
482
483void tJobErrorUpdate(unsigned uJob, const char *cErrorMsg)
484{
485        sprintf(gcQuery,"UPDATE tJob SET uJobStatus=14,cRemoteMsg='%.31s',uModBy=1,"
486                                "uModDate=UNIX_TIMESTAMP(NOW()) WHERE uJob=%u",
487                                                                        cErrorMsg,uJob);
488        mysql_query(&gMysql,gcQuery);
489        if(mysql_errno(&gMysql))
490        {
491                logfileLine("tJobErrorUpdate",mysql_error(&gMysql));
492                exit(2);
493        }
494
495        sprintf(gcQuery,"INSERT INTO tLog SET"
496                " cLabel='unxsVZ.cgi ProcessJobQueue Error',"
497                "uLogType=4,uLoginClient=1,"
498                "cLogin='unxsVZ.cgi',cMessage=\"%s uJob=%u\","
499                "cServer='%s',uOwner=1,uCreatedBy=1,"
500                "uCreatedDate=UNIX_TIMESTAMP(NOW())",
501                                        cErrorMsg,uJob,cHostname);
502        mysql_query(&gMysql,gcQuery);
503        if(mysql_errno(&gMysql))
504        {
505                logfileLine("tJobErrorUpdate",mysql_error(&gMysql));
506                exit(2);
507        }
508
509}//void tJobErrorUpdate()
510
511
512void tJobDoneUpdate(unsigned uJob)
513{
514        sprintf(gcQuery,"UPDATE tJob SET uJobStatus=3,uModBy=1,cRemoteMsg='tJobDoneUpdate() ok',"
515                                "uModDate=UNIX_TIMESTAMP(NOW()) WHERE uJob=%u",uJob);
516        mysql_query(&gMysql,gcQuery);
517        if(mysql_errno(&gMysql))
518        {
519                logfileLine("tJobDoneUpdate",mysql_error(&gMysql));
520                exit(2);
521        }
522
523}//void tJobDoneUpdate(unsigned uJob, char *cErrorMsg)
524
525
526void tJobWaitingUpdate(unsigned uJob)
527{
528        sprintf(gcQuery,"UPDATE tJob SET uJobStatus=1,uModBy=1,cRemoteMsg='tJobWaitingUpdate()',"
529                                "uModDate=UNIX_TIMESTAMP(NOW()) WHERE uJob=%u",uJob);
530        mysql_query(&gMysql,gcQuery);
531        if(mysql_errno(&gMysql))
532        {
533                logfileLine("tJobWaitingUpdate",mysql_error(&gMysql));
534                exit(2);
535        }
536
537}//void tJobWaitingUpdate(unsigned uJob, char *cErrorMsg)
538
539
540//Specific job handlers
541
542
543void NewContainer(unsigned uJob,unsigned uContainer)
544{
545        MYSQL_RES *res;
546        MYSQL_ROW field;
547        unsigned uVeth=0;
548        unsigned uDeployStopped=0;
549        char cDeployOptions[256]={""};
550
551        //Must wait for clone or template operations to finish.
552        if(access("/var/run/vzdump.lock",R_OK)==0)
553        {
554                logfileLine("NewContainer","/var/run/vzdump.lock exists");
555                tJobWaitingUpdate(uJob);
556                return;
557        }
558
559        sprintf(gcQuery,"SELECT tContainer.cLabel,tContainer.cHostname,tIP.cLabel"
560                        ",tOSTemplate.cLabel,tNameserver.cLabel,tSearchdomain.cLabel,tConfig.cLabel,tContainer.uVeth"
561                        " FROM tContainer,tOSTemplate,tNameserver,tSearchdomain,tConfig,tIP WHERE uContainer=%u"
562                        " AND tContainer.uOSTemplate=tOSTemplate.uOSTemplate"
563                        " AND tContainer.uNameserver=tNameserver.uNameserver"
564                        " AND tContainer.uConfig=tConfig.uConfig"
565                        " AND tContainer.uIPv4=tIP.uIP"
566                        " AND tContainer.uSearchdomain=tSearchdomain.uSearchdomain",uContainer);
567        mysql_query(&gMysql,gcQuery);
568        if(mysql_errno(&gMysql))
569        {
570                logfileLine("NewContainer",mysql_error(&gMysql));
571                exit(2);
572        }
573        res=mysql_store_result(&gMysql);
574        if((field=mysql_fetch_row(res)))
575        {
576
577
578                sscanf(field[7],"%u",&uVeth);
579
580                //0-. Create vz conf action script files if applicable. 1 is for overwriting existing files
581                //OpenVZ action scripts
582                if(CreateActionScripts(uContainer,1))
583                {
584                        logfileLine("NewContainer","CreateActionScripts(x,1) failed");
585                        tJobErrorUpdate(uJob,"CreateActionScripts(x,1) failed");
586                        goto CommonExit;
587                }
588
589                //vzctl [flags] create veid --ostemplate name] [--config name] [--private path]
590                //[--root path] [--ipadd addr] [--hostname name]
591                //1-.
592               
593                if(     uNotValidSystemCallArg(field[0]) ||
594                        uNotValidSystemCallArg(field[1]) ||
595                        uNotValidSystemCallArg(field[2]) ||
596                        uNotValidSystemCallArg(field[3]) ||
597                        uNotValidSystemCallArg(field[4]) ||
598                        uNotValidSystemCallArg(field[5]) ||
599                        uNotValidSystemCallArg(field[6])        )
600                {
601                        logfileLine("NewContainer","security alert");
602                        tJobErrorUpdate(uJob,"failed sec alert!");
603                        goto CommonExit;
604                }
605
606
607                if(uVeth)
608                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose create %u --ostemplate %s --hostname %s"
609                                " --name %s --config %s",
610                                uContainer,field[3],field[1],field[0],field[6]);
611                else
612                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose create %u --ostemplate %s --hostname %s"
613                                " --ipadd %s --name %s --config %s",
614                                uContainer,field[3],field[1],field[2],field[0],field[6]);
615                if(system(gcQuery))
616                {
617                        logfileLine("NewContainer",gcQuery);
618                        tJobErrorUpdate(uJob,"vzctl create failed");
619                }
620
621                //2-.
622                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --nameserver \"%.99s\" --searchdomain \"%.32s\" --save",
623                                uContainer,field[4],field[5]);
624                if(system(gcQuery))
625                {
626                        logfileLine("NewContainer",gcQuery);
627                        tJobErrorUpdate(uJob,"vzctl set failed");
628                        //Roll back step 1-.
629                        sprintf(gcQuery,"/usr/sbin/vzctl destroy %u",uContainer);
630                        if(system(gcQuery))
631                        {
632                                logfileLine("NewContainer",gcQuery);
633                                tJobErrorUpdate(uJob,"rb0: vzctl destroy failed");
634                        }
635                        goto CommonExit;
636                }
637
638                //3-.
639                //TODO hardcoded eth0 problem. Solution is easy get from node properties.
640                //problem remains if datacenter nodes have diff eth device!
641                GetContainerProp(uContainer,"cDeployOptions",cDeployOptions);
642                if(strstr(cDeployOptions,"uDeployStopped=1;"))
643                        uDeployStopped=1;
644                if(uVeth)
645                {
646                        char cIPv4[32]={""};
647
648                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
649                        if(system(gcQuery))
650                        {
651                                logfileLine("NewContainer",gcQuery);
652                                tJobErrorUpdate(uJob,"vzctl start1 failed");
653                                //Roll back step 1-.
654                                sprintf(gcQuery,"/usr/sbin/vzctl destroy %u",uContainer);
655                                if(system(gcQuery))
656                                {
657                                        logfileLine("NewContainer",gcQuery);
658                                        tJobErrorUpdate(uJob,"rb1: vzctl destroy failed");
659                                }
660                                goto CommonExit;
661                        }
662
663                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --netif_add eth0,,,,vmbr0 --save",uContainer);
664                        if(system(gcQuery))
665                        {
666                                logfileLine("NewContainer",gcQuery);
667                                tJobErrorUpdate(uJob,"vzctl --netif_add failed");
668                                //Roll back step 2-.
669                                sprintf(gcQuery,"/usr/sbin/vzctl stop %u",uContainer);
670                                if(system(gcQuery))
671                                {
672                                        logfileLine("NewContainer",gcQuery);
673                                        tJobErrorUpdate(uJob,"rb2: vzctl stop failed");
674                                }
675                                //Roll back step 1-.
676                                sprintf(gcQuery,"/usr/sbin/vzctl destroy %u",uContainer);
677                                if(system(gcQuery))
678                                {
679                                        logfileLine("NewContainer",gcQuery);
680                                        tJobErrorUpdate(uJob,"rb2: vzctl destroy failed");
681                                }
682                                goto CommonExit;
683                        }
684
685                        if(GetContainerMainIP(uContainer,cIPv4))
686                                logfileLine("NewContainer","Empty cIPv4");
687
688                        sprintf(gcQuery,"/usr/sbin/vzctl exec %u \"/sbin/ifconfig eth0 0\"",uContainer);
689                        if(system(gcQuery))
690                                logfileLine("NewContainer",gcQuery);
691
692                        sprintf(gcQuery,"/usr/sbin/vzctl exec %u \"/sbin/ip addr add %s dev eth0\"",
693                                                uContainer,cIPv4);
694                        if(system(gcQuery))
695                                logfileLine("NewContainer",gcQuery);
696
697                        sprintf(gcQuery,"/usr/sbin/vzctl exec %u \"/sbin/ip route add default dev eth0\"",uContainer);
698                        if(system(gcQuery))
699                                logfileLine("NewContainer",gcQuery);
700
701                        if(uDeployStopped)
702                        {
703                                sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u",uContainer);
704                                if(system(gcQuery))
705                                        logfileLine("NewContainer",gcQuery);
706                        }
707                }
708                else
709                {
710                        if(!uDeployStopped)
711                        {
712                                sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
713                                if(system(gcQuery))
714                                {
715                                        logfileLine("NewContainer",gcQuery);
716                                        tJobErrorUpdate(uJob,"vzctl start failed");
717                                        //Roll back step 1-.
718                                        sprintf(gcQuery,"/usr/sbin/vzctl destroy %u",uContainer);
719                                        if(system(gcQuery))
720                                        {
721                                                logfileLine("NewContainer",gcQuery);
722                                                tJobErrorUpdate(uJob,"rb3: vzctl destroy failed");
723                                        }
724                                        goto CommonExit;
725                                }
726                        }
727                }
728        }
729        else
730        {
731                sprintf(gcQuery,"Select for %u failed",uContainer);
732                logfileLine("NewContainer",gcQuery);
733                tJobErrorUpdate(uJob,"Select failed");
734                goto CommonExit;
735        }
736
737        //4-. Optional container password set
738        //This option requires MySQL SSL replication and
739        //much more security measures in place to avoid a db penetration leading
740        //to multiple container breaches.
741        char cPasswd[256]={""};
742        GetContainerProp(uContainer,"cPasswd",cPasswd);
743        if(cPasswd[0] && !uNotValidSystemCallArg(cPasswd) )
744        {
745                //sprintf(gcQuery,"/usr/sbin/vzctl --userpasswd \"root:%s\" %u",cPasswd,uContainer);
746                //This works on older vzctl also
747                sprintf(gcQuery,"/usr/sbin/vzctl set %u --userpasswd \"root:%s\"",uContainer,cPasswd);
748                if(system(gcQuery))
749                        logfileLine("NewContainer","Container passwd not changed!");
750        }
751
752        //5-. Optional container CentOS linux timezone set
753        //Example (cOrg_TimeZone) cTimezone "Europe/Zurich"
754        //For /usr/share/zoneinfo/Europe/Zurich
755        char cTimezone[256]={""};
756        GetContainerProp(uContainer,"cOrg_TimeZone",cTimezone);
757        if(cTimezone[0] && !uNotValidSystemCallArg(cTimezone) )
758        {
759                sprintf(gcQuery,"rm -f /vz/private/%u/etc/localtime",uContainer);
760                if(system(gcQuery))
761                {
762                        logfileLine("NewContainer",gcQuery);
763                }
764                else
765                {
766                        sprintf(gcQuery,"ln -s /usr/share/zoneinfo/%s /vz/private/%u/etc/localtime",
767                                                        cTimezone,uContainer);
768                        if(system(gcQuery))
769                                logfileLine("NewContainer",gcQuery);
770                        else
771                                logfileLine("NewContainer","Container timezone changed");
772                }
773        }
774
775        //6-.
776        //Optional group based script may exist to be executed.
777        //
778        sprintf(gcQuery,"SELECT tProperty.cValue FROM tProperty,tGroupGlue WHERE tProperty.uType=%u"
779                        " AND tProperty.uKey=tGroupGlue.uGroup"
780                        " AND tGroupGlue.uContainer=%u"
781                        " AND tProperty.cName='cJob_OnNewScript' LIMIT 1",uPROP_GROUP,uContainer);
782        mysql_query(&gMysql,gcQuery);
783        if(mysql_errno(&gMysql))
784        {
785                logfileLine("NewContainer",mysql_error(&gMysql));
786                exit(2);
787        }
788        res=mysql_store_result(&gMysql);
789        if((field=mysql_fetch_row(res)))
790        {
791                char cOnScriptCall[386];
792                struct stat statInfo;
793                char cCommand[256];
794                char *cp;
795
796                sprintf(cCommand,"%.255s",field[0]);
797
798                //Remove trailing junk
799                if((cp=strchr(cCommand,'\n')) || (cp=strchr(cCommand,'\r'))) *cp=0;
800
801                if(uNotValidSystemCallArg(cCommand))
802                {
803                        logfileLine("NewContainer","cJob_OnNewScript security alert");
804                        goto CommonExit2;
805                }
806
807                //Only run if command is chmod 500 and owned by root for extra security reasons.
808                if(stat(cCommand,&statInfo))
809                {
810                        logfileLine("NewContainer","stat failed for cJob_OnNewScript");
811                        logfileLine("NewContainer",cCommand);
812                        goto CommonExit2;
813                }
814                if(statInfo.st_uid!=0)
815                {
816                        logfileLine("NewContainer","cJob_OnNewScript is not owned by root");
817                        goto CommonExit2;
818                }
819                if(statInfo.st_mode & ( S_IWOTH | S_IWGRP | S_IWUSR | S_IXOTH | S_IROTH | S_IXGRP | S_IRGRP ) )
820                {
821                        logfileLine("NewContainer","cJob_OnNewScript is not chmod 500");
822                        goto CommonExit2;
823                }
824
825                char cHostname[100]={""};
826                sprintf(gcQuery,"SELECT tContainer.cHostname"
827                                " FROM tContainer WHERE uContainer=%u",uContainer);
828                mysql_query(&gMysql,gcQuery);
829                if(mysql_errno(&gMysql))
830                {
831                        logfileLine("",mysql_error(&gMysql));
832                        exit(2);
833                }
834                res=mysql_store_result(&gMysql);
835                if((field=mysql_fetch_row(res)))
836                {
837                        sprintf(cHostname,"%.99s",field[0]);
838
839                        sprintf(cOnScriptCall,"%.255s %.64s %u",cCommand,cHostname,uContainer);
840                        if(system(cOnScriptCall))
841                        {
842                                logfileLine("NewContainer",cOnScriptCall);
843                        }
844                }
845        }
846
847//In this case the goto MIGHT be justified
848CommonExit2:
849
850        //Everything went ok;
851        if(uDeployStopped)
852                SetContainerStatus(uContainer,31);//Stopped
853        else
854                SetContainerStatus(uContainer,1);//Active
855        tJobDoneUpdate(uJob);
856
857//In this case the goto MIGHT be justified
858CommonExit:
859        mysql_free_result(res);
860
861}//void NewContainer(...)
862
863
864void DestroyContainer(unsigned uJob,unsigned uContainer)
865{
866
867        //1-.
868        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u",uContainer);
869        if(system(gcQuery))
870        {
871                logfileLine("DestroyContainer",gcQuery);
872                tJobErrorUpdate(uJob,"vzctl stop failed");
873                return;
874        }
875
876        //2-.
877        sprintf(gcQuery,"/usr/sbin/vzctl --verbose destroy %u",uContainer);
878        if(system(gcQuery))
879        {
880                logfileLine("DestroyContainer",gcQuery);
881                tJobErrorUpdate(uJob,"vzctl destroy failed");
882
883                //Attempt roll back
884                sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
885                if(system(gcQuery))
886                {
887                        logfileLine("DestroyContainer",gcQuery);
888                        tJobErrorUpdate(uJob,"vzctl start rollback failed");
889                }
890                return;
891        }
892
893        //Optional group based script may exist to be executed.
894        //
895        MYSQL_RES *res;
896        MYSQL_ROW field;
897        sprintf(gcQuery,"SELECT tProperty.cValue FROM tProperty,tGroupGlue WHERE tProperty.uType=%u"
898                        " AND tProperty.uKey=tGroupGlue.uGroup"
899                        " AND tGroupGlue.uContainer=%u"
900                        " AND tProperty.cName='cJob_OnDestroyScript' LIMIT 1",uPROP_GROUP,uContainer);
901        mysql_query(&gMysql,gcQuery);
902        if(mysql_errno(&gMysql))
903        {
904                logfileLine("DestroyContainer",mysql_error(&gMysql));
905                exit(2);
906        }
907        res=mysql_store_result(&gMysql);
908        if((field=mysql_fetch_row(res)))
909        {
910                struct stat statInfo;
911                char cOnScriptCall[512];
912                char cCommand[256];
913                char *cp;
914
915                sprintf(cCommand,"%.255s",field[0]);
916
917                //Remove trailing junk
918                if((cp=strchr(cCommand,'\n')) || (cp=strchr(cCommand,'\r'))) *cp=0;
919
920                if(uNotValidSystemCallArg(cCommand))
921                {
922                        logfileLine("DestroyContainer","cJob_OnDestroyScript security alert");
923                        goto CommonExit2;
924                }
925
926                //Only run if command is chmod 500 and owned by root for extra security reasons.
927                if(stat(cCommand,&statInfo))
928                {
929                        logfileLine("DestroyContainer","stat failed for cJob_OnDestroyScript");
930                        logfileLine("DestroyContainer",cCommand);
931                        goto CommonExit2;
932                }
933                if(statInfo.st_uid!=0)
934                {
935                        logfileLine("DestroyContainer","cJob_OnDestroyScript is not owned by root");
936                        goto CommonExit2;
937                }
938                if(statInfo.st_mode & ( S_IWOTH | S_IWGRP | S_IWUSR | S_IXOTH | S_IROTH | S_IXGRP | S_IRGRP ) )
939                {
940                        logfileLine("DestroyContainer","cJob_OnDestroyScript is not chmod 500");
941                        goto CommonExit2;
942                }
943
944                char cHostname[100]={""};
945                sprintf(gcQuery,"SELECT tContainer.cHostname"
946                                " FROM tContainer WHERE uContainer=%u",uContainer);
947                mysql_query(&gMysql,gcQuery);
948                if(mysql_errno(&gMysql))
949                {
950                        logfileLine("",mysql_error(&gMysql));
951                        exit(2);
952                }
953                res=mysql_store_result(&gMysql);
954                if((field=mysql_fetch_row(res)))
955                {
956                        sprintf(cHostname,"%.99s",field[0]);
957
958                        sprintf(cOnScriptCall,"%.255s %.64s %u",cCommand,cHostname,uContainer);
959                        if(system(cOnScriptCall))
960                        {
961                                logfileLine("DestroyContainer",cOnScriptCall);
962                        }
963                }
964        }
965CommonExit2:
966        mysql_free_result(res);
967
968        //Everything ok
969        SetContainerStatus(uContainer,uINITSETUP);//Initial
970        tJobDoneUpdate(uJob);
971
972
973}//void DestroyContainer(...)
974
975
976void ChangeIPContainer(unsigned uJob,unsigned uContainer,char *cJobData)
977{
978
979        char cIPOld[256]={""};
980        char cIPNew[31]={""};
981        char *cp;
982        MYSQL_RES *res;
983        MYSQL_ROW field;
984        unsigned uVeth=0;
985
986        //Check 1-. Check to make sure container is on this node, if not
987        //      give job back to queue
988        sprintf(gcQuery,"/usr/sbin/vzlist %u > /dev/null 2>&1",uContainer);
989        if(system(gcQuery))
990        {
991                logfileLine("ChangeIPContainer","Job returned to queue no such container");
992                tJobWaitingUpdate(uJob);
993                return;
994        }
995
996        //Check 2-. Wait till any other jobs currently in the job queue for this
997        //      container are done.
998        sprintf(gcQuery,"SELECT uJob FROM tJob"
999                        " WHERE uContainer=%u AND (uJobStatus=%u OR uJobStatus=%u) AND uJob!=%u"
1000                        " AND cJobName!='ChangeHostnameContainer'",
1001                                        uContainer,uWAITING,uRUNNING,uJob);
1002        mysql_query(&gMysql,gcQuery);
1003        if(mysql_errno(&gMysql))
1004        {
1005                logfileLine("ChangeIPContainer",mysql_error(&gMysql));
1006                exit(2);
1007        }
1008        res=mysql_store_result(&gMysql);
1009        if((field=mysql_fetch_row(res)))
1010        {
1011                logfileLine("ChangeIPContainer","Job returned to queue other jobs pending");
1012                tJobWaitingUpdate(uJob);
1013                mysql_free_result(res);
1014                return;
1015        }
1016        mysql_free_result(res);
1017
1018
1019        //0-. Get required data
1020        sprintf(gcQuery,"SELECT tIP.cLabel,tContainer.uVeth"
1021                        " FROM tContainer,tIP WHERE uContainer=%u"
1022                        " AND tContainer.uIPv4=tIP.uIP",uContainer);
1023        mysql_query(&gMysql,gcQuery);
1024        if(mysql_errno(&gMysql))
1025        {
1026                logfileLine("ChangeIPContainer",mysql_error(&gMysql));
1027                exit(2);
1028        }
1029        res=mysql_store_result(&gMysql);
1030        if((field=mysql_fetch_row(res)))
1031        {
1032                sscanf(field[1],"%u",&uVeth);
1033
1034                sprintf(cIPNew,"%.31s",field[0]);
1035                if(!cIPNew[0]) 
1036                {
1037                        logfileLine("ChangeIPContainer cIPNew",gcQuery);
1038                        tJobErrorUpdate(uJob,"Get cIPNew failed");
1039                        goto CommonExit;
1040                }
1041                sscanf(cJobData,"cIPOld=%31s;",cIPOld);
1042                if((cp=strchr(cIPOld,';')))
1043                        *cp=0;
1044                if(!cIPOld[0]) 
1045                {
1046                        logfileLine("ChangeIPContainer cIPOld from cJobData=",cJobData);
1047                        tJobErrorUpdate(uJob,"Get cIPOld failed");
1048                        goto CommonExit;
1049                }
1050
1051                if(uNotValidSystemCallArg(cIPNew)||uNotValidSystemCallArg(cIPOld))
1052                {
1053                        logfileLine("ChangeIPContainer","security alert");
1054                        tJobErrorUpdate(uJob,"failed sec alert!");
1055                        goto CommonExit;
1056                }
1057
1058
1059                if(!uVeth)
1060                {
1061                        //0-.
1062                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u",uContainer);
1063                        if(system(gcQuery))
1064                        {
1065                                logfileLine("ChangeIPContainer",gcQuery);
1066                                tJobErrorUpdate(uJob,"vzctl stop failed");
1067                                goto CommonExit;
1068                        }
1069
1070                        //1-.
1071                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cIPNew);
1072                        if(system(gcQuery))
1073                        {
1074                                logfileLine("ChangeIPContainer",gcQuery);
1075                                tJobErrorUpdate(uJob,"vzctl set ipadd failed");
1076                                goto CommonExit;
1077                        }
1078       
1079       
1080                        //2-.
1081                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel %s --save",uContainer,cIPOld);
1082                        if(system(gcQuery))
1083                        {
1084                                logfileLine("ChangeIPContainer",gcQuery);
1085                                tJobErrorUpdate(uJob,"vzctl set ipdel failed");
1086                                goto CommonExit;
1087                        }
1088                }
1089                else
1090                {
1091                        //VETH based container
1092                        sprintf(gcQuery,"/usr/sbin/vzctl exec %u \"/sbin/ifconfig eth0 0\"",uContainer);
1093                        if(system(gcQuery))
1094                        {
1095                                logfileLine("ChangeIPContainer",gcQuery);
1096                                tJobErrorUpdate(uJob,"vzctl exec 1");
1097                                goto CommonExit;
1098                        }
1099
1100                        sprintf(gcQuery,"/usr/sbin/vzctl exec %u \"/sbin/ip addr add %s dev eth0\"",
1101                                                uContainer,cIPNew);
1102                        if(system(gcQuery))
1103                        {
1104                                logfileLine("ChangeIPContainer",gcQuery);
1105                                tJobErrorUpdate(uJob,"vzctl exec 2");
1106                                goto CommonExit;
1107                        }
1108
1109                        sprintf(gcQuery,"/usr/sbin/vzctl exec %u \"/sbin/ip route add default dev eth0\"",uContainer);
1110                        if(system(gcQuery))
1111                        {
1112                                logfileLine("ChangeIPContainer",gcQuery);
1113                                tJobErrorUpdate(uJob,"vzctl exec 3");
1114                                goto CommonExit;
1115                        }
1116
1117                        sprintf(gcQuery,"/sbin/ip route del %.31s dev veth%u.0",cIPOld,uContainer);
1118                        if(system(gcQuery))
1119                        {
1120                                logfileLine("ChangeIPContainer",gcQuery);
1121                                tJobErrorUpdate(uJob,"vzctl exec 4");
1122                                goto CommonExit;
1123                        }
1124
1125                        sprintf(gcQuery,"/sbin/ip route add %.31s dev veth%u.0",cIPNew,uContainer);
1126                        if(system(gcQuery))
1127                        {
1128                                logfileLine("ChangeIPContainer",gcQuery);
1129                                tJobErrorUpdate(uJob,"vzctl exec 4");
1130                                goto CommonExit;
1131                        }
1132                }
1133
1134                //3-.
1135                sprintf(gcQuery,"UPDATE tIP SET uAvailable=1 WHERE cLabel='%.31s'",cIPOld);
1136                mysql_query(&gMysql,gcQuery);
1137                if(mysql_errno(&gMysql))
1138                {
1139                        logfileLine("ChangeIPContainer",mysql_error(&gMysql));
1140                        tJobErrorUpdate(uJob,"Release old IP from tIP failed");
1141                        goto CommonExit;
1142                }
1143
1144                if(!uVeth)
1145                {
1146                        //4-.
1147                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
1148                        if(system(gcQuery))
1149                        {
1150                                logfileLine("ChangeIPContainer",gcQuery);
1151                                tJobErrorUpdate(uJob,"vzctl start failed");
1152                                goto CommonExit;
1153                        }
1154                }
1155
1156                //Everything ok
1157                sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot yes --save",uContainer);
1158                if(system(gcQuery))
1159                        logfileLine("ChangeIPContainer",gcQuery);
1160                SetContainerStatus(uContainer,1);//Active
1161                tJobDoneUpdate(uJob);
1162
1163        }
1164        else
1165        {
1166                logfileLine("ChangeIPContainer",gcQuery);
1167                tJobErrorUpdate(uJob,"No line from query");
1168        }
1169
1170//This goto MIGHT be ok
1171CommonExit:
1172        mysql_free_result(res);
1173        return;
1174
1175}//void ChangeIPContainer()
1176
1177
1178void ChangeHostnameContainer(unsigned uJob,unsigned uContainer,char *cJobData)
1179{
1180        char cHostname[100]={""};
1181        char cName[100]={""};
1182        char cTimezone[256]={""};
1183        MYSQL_RES *res;
1184        MYSQL_ROW field;
1185
1186        //Check 1-. Check to make sure container is on this node, if not
1187        //      give job back to queue
1188        sprintf(gcQuery,"/usr/sbin/vzlist %u > /dev/null 2>&1",uContainer);
1189        if(system(gcQuery))
1190        {
1191                logfileLine("ChangeHostnameContainer","Job returned to queue no such container");
1192                tJobWaitingUpdate(uJob);
1193                return;
1194        }
1195
1196        //Check 2-. Wait till any other jobs currently in the job queue for this
1197        //      container are done.
1198        sprintf(gcQuery,"SELECT uJob FROM tJob"
1199                        " WHERE uContainer=%u AND (uJobStatus=%u OR uJobStatus=%u) AND uJob!=%u"
1200                        " AND cJobName!='ChangeIPContainer'",
1201                                        uContainer,uWAITING,uRUNNING,uJob);
1202        mysql_query(&gMysql,gcQuery);
1203        if(mysql_errno(&gMysql))
1204        {
1205                logfileLine("ChangeHostnameContainer",mysql_error(&gMysql));
1206                exit(2);
1207        }
1208        res=mysql_store_result(&gMysql);
1209        if((field=mysql_fetch_row(res)))
1210        {
1211                logfileLine("ChangeHostnameContainer","Job returned to queue other jobs pending");
1212                tJobWaitingUpdate(uJob);
1213                mysql_free_result(res);
1214                return;
1215        }
1216        mysql_free_result(res);
1217
1218
1219        //New for external script
1220        char cPrevHostname[100]={""};
1221        char *cp;
1222        sscanf(cJobData,"cPrevHostname=%99s;",cPrevHostname);
1223        if((cp=strchr(cPrevHostname,';')))
1224                *cp=0;
1225
1226        sprintf(gcQuery,"SELECT tContainer.cLabel,tContainer.cHostname"
1227                        " FROM tContainer WHERE uContainer=%u",uContainer);
1228        mysql_query(&gMysql,gcQuery);
1229        if(mysql_errno(&gMysql))
1230        {
1231                logfileLine("ChangeHostnameContainer",mysql_error(&gMysql));
1232                exit(2);
1233        }
1234        res=mysql_store_result(&gMysql);
1235        if((field=mysql_fetch_row(res)))
1236        {
1237                sprintf(cName,"%.99s",field[0]);
1238                sprintf(cHostname,"%.99s",field[1]);
1239
1240                if(!cHostname[0] || !cName[0]) 
1241                {
1242                        logfileLine("ChangeHostnameContainer",gcQuery);
1243                        tJobErrorUpdate(uJob,"Get cHostname failed");
1244                        goto CommonExit;
1245                }
1246
1247                if(uNotValidSystemCallArg(cHostname)||uNotValidSystemCallArg(cName))
1248                {
1249                        logfileLine("ChangeHostnameContainer","security alert");
1250                        tJobErrorUpdate(uJob,"failed sec alert!");
1251                        goto CommonExit;
1252                }
1253
1254                //1-.
1255                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --hostname %s --name %s --save",
1256                                        uContainer,cHostname,cName);
1257                if(system(gcQuery))
1258                {
1259                        logfileLine("ChangeHostnameContainer",gcQuery);
1260                        tJobErrorUpdate(uJob,"vzctl set hostname failed");
1261                        goto CommonExit;
1262                }
1263
1264                //Everything ok
1265                SetContainerStatus(uContainer,1);//Active
1266                tJobDoneUpdate(uJob);
1267        }
1268        else
1269        {
1270                logfileLine("ChangeHostnameContainer",gcQuery);
1271                tJobErrorUpdate(uJob,"No line from query");
1272        }
1273
1274
1275        //Optional group based script may exist to be executed.
1276        //
1277        sprintf(gcQuery,"SELECT tProperty.cValue FROM tProperty,tGroupGlue WHERE tProperty.uType=%u"
1278                        " AND tProperty.uKey=tGroupGlue.uGroup"
1279                        " AND tGroupGlue.uContainer=%u"
1280                        " AND tProperty.cName='cJob_OnChangeHostnameScript' LIMIT 1",uPROP_GROUP,uContainer);
1281        mysql_query(&gMysql,gcQuery);
1282        if(mysql_errno(&gMysql))
1283        {
1284                logfileLine("ChangeHostnameContainer",mysql_error(&gMysql));
1285                exit(2);
1286        }
1287        res=mysql_store_result(&gMysql);
1288        if((field=mysql_fetch_row(res)))
1289        {
1290                struct stat statInfo;
1291                char cOnScriptCall[512];
1292                char cCommand[256];
1293                char *cp;
1294
1295                sprintf(cCommand,"%.255s",field[0]);
1296
1297                //Remove trailing junk
1298                if((cp=strchr(cCommand,'\n')) || (cp=strchr(cCommand,'\r'))) *cp=0;
1299
1300                if(uNotValidSystemCallArg(cCommand))
1301                {
1302                        logfileLine("ChangeHostnameContainer","cJob_OnChangeHostnameScript security alert");
1303                        goto CommonExit2;
1304                }
1305
1306                //Only run if command is chmod 500 and owned by root for extra security reasons.
1307                if(stat(cCommand,&statInfo))
1308                {
1309                        logfileLine("ChangeHostnameContainer","stat failed for cJob_OnChangeHostnameScript");
1310                        logfileLine("ChangeHostnameContainer",cCommand);
1311                        goto CommonExit2;
1312                }
1313                if(statInfo.st_uid!=0)
1314                {
1315                        logfileLine("ChangeHostnameContainer","cJob_OnChangeHostnameScript is not owned by root");
1316                        goto CommonExit2;
1317                }
1318                if(statInfo.st_mode & ( S_IWOTH | S_IWGRP | S_IWUSR | S_IXOTH | S_IROTH | S_IXGRP | S_IRGRP ) )
1319                {
1320                        logfileLine("ChangeHostnameContainer","cJob_OnChangeHostnameScript is not chmod 500");
1321                        goto CommonExit2;
1322                }
1323
1324                sprintf(cOnScriptCall,"%.255s %.64s %u %.99s",cCommand,cHostname,uContainer,cPrevHostname);
1325                if(system(cOnScriptCall))
1326                {
1327                        logfileLine("ChangeHostnameContainer",cOnScriptCall);
1328                }
1329        }
1330
1331CommonExit2:
1332
1333        //Please note that some container programs may need to also have time based info
1334        //set or maybe restarted. This should be done by the above script.
1335        //Since it is beyond the scope of unxsVZ to handle all the diff types of container
1336        //Good example is a complex service container like a FreePBX/Asterisk virtual server.
1337
1338        //Optional container CentOS linux timezone set. See New also.
1339        //Example (cOrg_TimeZone) cTimezone "Europe/Zurich"
1340        //For /usr/share/zoneinfo/Europe/Zurich
1341        GetContainerProp(uContainer,"cOrg_TimeZone",cTimezone);
1342        if(cTimezone[0] && !uNotValidSystemCallArg(cTimezone) )
1343        {
1344                sprintf(gcQuery,"rm -f /vz/private/%u/etc/localtime",uContainer);
1345                if(system(gcQuery))
1346                {
1347                        logfileLine("ChangeHostnameContainer",gcQuery);
1348                }
1349                else
1350                {
1351                        //The link target is internal to container
1352                        sprintf(gcQuery,"ln -s /usr/share/zoneinfo/%s /vz/private/%u/etc/localtime",
1353                                                        cTimezone,uContainer);
1354                        if(system(gcQuery))
1355                                logfileLine("ChangeHostnameContainer",gcQuery);
1356                        else
1357                                logfileLine("ChangeHostnameContainer","Container timezone changed");
1358                }
1359        }
1360
1361CommonExit:
1362        mysql_free_result(res);
1363        return;
1364
1365}//void ChangeHostnameContainer()
1366
1367
1368void StopContainer(unsigned uJob,unsigned uContainer)
1369{
1370
1371        //1-.
1372        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u",uContainer);
1373        if(system(gcQuery))
1374        {
1375                logfileLine("StopContainer",gcQuery);
1376                tJobErrorUpdate(uJob,"vzctl stop failed");
1377                return;
1378        }
1379
1380        //2-.
1381        sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot no --save",uContainer);
1382        if(system(gcQuery))
1383        {
1384                logfileLine("StopContainer",gcQuery);
1385                tJobErrorUpdate(uJob,"vzctl set failed");
1386                return;
1387        }
1388
1389        //Optional group based script may exist to be executed.
1390        //
1391        MYSQL_RES *res;
1392        MYSQL_ROW field;
1393        sprintf(gcQuery,"SELECT tProperty.cValue FROM tProperty,tGroupGlue WHERE tProperty.uType=%u"
1394                        " AND tProperty.uKey=tGroupGlue.uGroup"
1395                        " AND tGroupGlue.uContainer=%u"
1396                        " AND tProperty.cName='cJob_OnStopScript' LIMIT 1",uPROP_GROUP,uContainer);
1397        mysql_query(&gMysql,gcQuery);
1398        if(mysql_errno(&gMysql))
1399        {
1400                logfileLine("StopContainer",mysql_error(&gMysql));
1401                exit(2);
1402        }
1403        res=mysql_store_result(&gMysql);
1404        if((field=mysql_fetch_row(res)))
1405        {
1406                struct stat statInfo;
1407                char cOnScriptCall[512];
1408                char cCommand[256];
1409                char *cp;
1410
1411                sprintf(cCommand,"%.255s",field[0]);
1412
1413                //Remove trailing junk
1414                if((cp=strchr(cCommand,'\n')) || (cp=strchr(cCommand,'\r'))) *cp=0;
1415
1416                if(uNotValidSystemCallArg(cCommand))
1417                {
1418                        logfileLine("StopContainer","cJob_OnStopScript security alert");
1419                        goto CommonExit2;
1420                }
1421
1422                //Only run if command is chmod 500 and owned by root for extra security reasons.
1423                if(stat(cCommand,&statInfo))
1424                {
1425                        logfileLine("StopContainer","stat failed for cJob_OnStopScript");
1426                        logfileLine("StopContainer",cCommand);
1427                        goto CommonExit2;
1428                }
1429                if(statInfo.st_uid!=0)
1430                {
1431                        logfileLine("StopContainer","cJob_OnStopScript is not owned by root");
1432                        goto CommonExit2;
1433                }
1434                if(statInfo.st_mode & ( S_IWOTH | S_IWGRP | S_IWUSR | S_IXOTH | S_IROTH | S_IXGRP | S_IRGRP ) )
1435                {
1436                        logfileLine("StopContainer","cJob_OnStopScript is not chmod 500");
1437                        goto CommonExit2;
1438                }
1439
1440                char cHostname[100]={""};
1441                sprintf(gcQuery,"SELECT tContainer.cHostname"
1442                                " FROM tContainer WHERE uContainer=%u",uContainer);
1443                mysql_query(&gMysql,gcQuery);
1444                if(mysql_errno(&gMysql))
1445                {
1446                        logfileLine("",mysql_error(&gMysql));
1447                        exit(2);
1448                }
1449                res=mysql_store_result(&gMysql);
1450                if((field=mysql_fetch_row(res)))
1451                {
1452                        sprintf(cHostname,"%.99s",field[0]);
1453
1454                        sprintf(cOnScriptCall,"%.255s %.64s %u",cCommand,cHostname,uContainer);
1455                        if(system(cOnScriptCall))
1456                        {
1457                                logfileLine("StopContainer",cOnScriptCall);
1458                        }
1459                }
1460        }
1461CommonExit2:
1462        mysql_free_result(res);
1463
1464        //Everything ok
1465        SetContainerStatus(uContainer,uSTOPPED);
1466        tJobDoneUpdate(uJob);
1467
1468}//void StopContainer()
1469
1470
1471void StartContainer(unsigned uJob,unsigned uContainer)
1472{
1473        //1-.
1474        sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
1475        if(system(gcQuery))
1476        {
1477                logfileLine("StartContainer",gcQuery);
1478                sprintf(gcQuery,"/usr/sbin/vzctl --verbose restart %u",uContainer);
1479                if(system(gcQuery))
1480                {
1481                        logfileLine("StartContainer",gcQuery);
1482                        tJobErrorUpdate(uJob,"vzctl start/restart failed");
1483                        return;
1484                }
1485        }
1486
1487        //2-.
1488        sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot yes --save",uContainer);
1489        if(system(gcQuery))
1490        {
1491                logfileLine("StartContainer",gcQuery);
1492                tJobErrorUpdate(uJob,"vzctl set failed");
1493                return;
1494        }
1495
1496        //Optional group based script may exist to be executed.
1497        //
1498        MYSQL_RES *res;
1499        MYSQL_ROW field;
1500        sprintf(gcQuery,"SELECT tProperty.cValue FROM tProperty,tGroupGlue WHERE tProperty.uType=%u"
1501                        " AND tProperty.uKey=tGroupGlue.uGroup"
1502                        " AND tGroupGlue.uContainer=%u"
1503                        " AND tProperty.cName='cJob_OnStartScript' LIMIT 1",uPROP_GROUP,uContainer);
1504        mysql_query(&gMysql,gcQuery);
1505        if(mysql_errno(&gMysql))
1506        {
1507                logfileLine("StartContainer",mysql_error(&gMysql));
1508                exit(2);
1509        }
1510        res=mysql_store_result(&gMysql);
1511        if((field=mysql_fetch_row(res)))
1512        {
1513                struct stat statInfo;
1514                char cOnScriptCall[512];
1515                char cCommand[256];
1516                char *cp;
1517
1518                sprintf(cCommand,"%.255s",field[0]);
1519
1520                //Remove trailing junk
1521                if((cp=strchr(cCommand,'\n')) || (cp=strchr(cCommand,'\r'))) *cp=0;
1522
1523                if(uNotValidSystemCallArg(cCommand))
1524                {
1525                        logfileLine("StartContainer","cJob_OnStartScript security alert");
1526                        goto CommonExit2;
1527                }
1528
1529                //Only run if command is chmod 500 and owned by root for extra security reasons.
1530                if(stat(cCommand,&statInfo))
1531                {
1532                        logfileLine("StartContainer","stat failed for cJob_OnStartScript");
1533                        logfileLine("StartContainer",cCommand);
1534                        goto CommonExit2;
1535                }
1536                if(statInfo.st_uid!=0)
1537                {
1538                        logfileLine("StartContainer","cJob_OnStartScript is not owned by root");
1539                        goto CommonExit2;
1540                }
1541                if(statInfo.st_mode & ( S_IWOTH | S_IWGRP | S_IWUSR | S_IXOTH | S_IROTH | S_IXGRP | S_IRGRP ) )
1542                {
1543                        logfileLine("StartContainer","cJob_OnStartScript is not chmod 500");
1544                        goto CommonExit2;
1545                }
1546
1547                char cHostname[100]={""};
1548                sprintf(gcQuery,"SELECT tContainer.cHostname"
1549                                " FROM tContainer WHERE uContainer=%u",uContainer);
1550                mysql_query(&gMysql,gcQuery);
1551                if(mysql_errno(&gMysql))
1552                {
1553                        logfileLine("",mysql_error(&gMysql));
1554                        exit(2);
1555                }
1556                res=mysql_store_result(&gMysql);
1557                if((field=mysql_fetch_row(res)))
1558                {
1559                        sprintf(cHostname,"%.99s",field[0]);
1560
1561                        sprintf(cOnScriptCall,"%.255s %.64s %u",cCommand,cHostname,uContainer);
1562                        if(system(cOnScriptCall))
1563                        {
1564                                logfileLine("StartContainer",cOnScriptCall);
1565                        }
1566                }
1567        }
1568CommonExit2:
1569        mysql_free_result(res);
1570
1571        //Everything ok
1572        SetContainerStatus(uContainer,uACTIVE);
1573        tJobDoneUpdate(uJob);
1574
1575}//void StartContainer(...)
1576
1577
1578//Covers Migration Wizard and Remote Migration
1579//Remote Migration must setup ChangeIP and DNS jobs
1580void MigrateContainer(unsigned uJob,unsigned uContainer,char *cJobData)
1581{
1582        char cTargetNodeIPv4[256]={""};
1583        char cIPv4[32]={""};
1584        unsigned uTargetNode=0;
1585        unsigned uTargetDatacenter=0;
1586        unsigned uIPv4=0;
1587        unsigned uPrevStatus=0;
1588
1589        sscanf(cJobData,"uTargetNode=%u;",&uTargetNode);
1590        if(!uTargetNode)
1591        {
1592                logfileLine("MigrateContainer","Could not determine uTargetNode");
1593                tJobErrorUpdate(uJob,"uTargetNode==0");
1594                return;
1595        }
1596
1597        //New...Now we always get the target datacenter
1598        sscanf(ForeignKey("tNode","uDatacenter",uTargetNode),"%u",&uTargetDatacenter);
1599        if(!uTargetDatacenter)
1600        {
1601                logfileLine("MigrateContainer","Could not determine uTargetDatacenter");
1602                tJobErrorUpdate(uJob,"uTargetDatacenter==0");
1603                return;
1604        }
1605
1606        sscanf(cJobData,"uTargetNode=%*u;\nuIPv4=%u;",&uIPv4);
1607        if(uIPv4)
1608        {
1609                logfileLine("MigrateContainer","Migration with new IP");
1610                sprintf(cIPv4,"%.31s",ForeignKey("tIP","cLabel",uIPv4));
1611                logfileLine("MigrateContainer",cIPv4);
1612
1613                //Remote migration uses node name for ssh
1614                sprintf(cTargetNodeIPv4,"%.255s",ForeignKey("tNode","cLabel",uTargetNode));
1615        }
1616        else
1617        {
1618                //Local cluster migration use private LAN IP
1619                GetNodeProp(uTargetNode,"cIPv4",cTargetNodeIPv4);
1620        }
1621
1622        if(!cTargetNodeIPv4[0])
1623        {
1624                logfileLine("MigrateContainer","Could not determine cTargetNodeIPv4");
1625                tJobErrorUpdate(uJob,"cTargetNodeIPv4");
1626                return;
1627        }
1628
1629        sscanf(cJobData,"uTargetNode=%*u;\nuIPv4=%*u;\nuPrevStatus=%u;",&uPrevStatus);
1630        if(uPrevStatus!=uACTIVE && uPrevStatus!=uSTOPPED)
1631        {
1632                sprintf(gcQuery,"cJobData uPrevStatus not active or stopped. uPrevStatus=%u",uPrevStatus);
1633                logfileLine("MigrateContainer",gcQuery);
1634                tJobErrorUpdate(uJob,"uPrevStatus problem");
1635                return;
1636        }
1637
1638        //vzmigrate --online -v <destination_address> <veid>
1639        //Most specific tConfiguration is used. This allows for some nodes to be set global
1640        //and others specific. But is slower than the other option with what maybe
1641        //very large numbers of per node tConfiguration entries.
1642        char cSSHOptions[256]={""};
1643        GetConfiguration("cSSHOptions",cSSHOptions,gfuDatacenter,gfuNode,0,0);//First try node specific
1644        if(!cSSHOptions[0])
1645        {
1646                GetConfiguration("cSSHOptions",cSSHOptions,gfuDatacenter,0,0,0);//Second try datacenter wide
1647                if(!cSSHOptions[0])
1648                        GetConfiguration("cSSHOptions",cSSHOptions,0,0,0,0);//Last try global
1649        }
1650        if(uNotValidSystemCallArg(cSSHOptions))
1651        {
1652                logfileLine("MigrateContainer","security alert");
1653                cSSHOptions[0]=0;
1654        }
1655        char cSCPOptions[256]={""};
1656        GetConfiguration("cSCPOptions",cSCPOptions,gfuDatacenter,gfuNode,0,0);//First try node specific
1657        if(!cSCPOptions[0])
1658        {
1659                GetConfiguration("cSCPOptions",cSCPOptions,gfuDatacenter,0,0,0);//Second try datacenter wide
1660                if(!cSCPOptions[0])
1661                        GetConfiguration("cSCPOptions",cSCPOptions,0,0,0,0);//Last try global
1662        }
1663        //Default for less conditions below
1664        if(!cSCPOptions[0] || uNotValidSystemCallArg(cSCPOptions))
1665                sprintf(cSCPOptions,"-P 22 -c arcfour");
1666
1667
1668        if(uPrevStatus==uACTIVE)
1669        {
1670                if(cSSHOptions[0])
1671                        sprintf(gcQuery,"export PATH=/usr/sbin:/usr/bin:/bin:/usr/local/bin:/usr/local/sbin;"
1672                                "/usr/sbin/vzmigrate --ssh=\"%s\" --keep-dst --online -v -v %s %u",
1673                                        cSSHOptions,cTargetNodeIPv4,uContainer);
1674                else
1675                        sprintf(gcQuery,"export PATH=/usr/sbin:/usr/bin:/bin;"
1676                                "/usr/sbin/vzmigrate --keep-dst --online -v -v %s %u",
1677                                        cTargetNodeIPv4,uContainer);
1678        }
1679        else
1680        {
1681                if(cSSHOptions[0])
1682                        sprintf(gcQuery,"export PATH=/usr/sbin:/usr/bin:/bin:/usr/local/bin:/usr/local/sbin;"
1683                                "/usr/sbin/vzmigrate --ssh=\"%s\" --keep-dst -v -v %s %u",
1684                                        cSSHOptions,cTargetNodeIPv4,uContainer);
1685                else
1686                        sprintf(gcQuery,"export PATH=/usr/sbin:/usr/bin:/bin;"
1687                                "/usr/sbin/vzmigrate --keep-dst -v -v %s %u",
1688                                        cTargetNodeIPv4,uContainer);
1689        }
1690
1691        if(system(gcQuery))
1692        {
1693                //We may not want this optional behavior may violate QoS for given migration
1694                logfileLine("MigrateContainer","Trying offline migration");
1695
1696                if(cSSHOptions[0])
1697                        sprintf(gcQuery,"export PATH=/usr/sbin:/usr/bin:/bin:/usr/local/bin:/usr/local/sbin;"
1698                                "/usr/sbin/vzmigrate --ssh=\"%s\" --keep-dst -v -v %s %u",
1699                                        cSSHOptions,cTargetNodeIPv4,uContainer);
1700                else
1701                        sprintf(gcQuery,"export PATH=/usr/sbin:/usr/bin:/bin:/usr/local/bin:/usr/local/sbin;"
1702                                "/usr/sbin/vzmigrate --keep-dst -v -v %s %u",
1703                                        cTargetNodeIPv4,uContainer);
1704                if(system(gcQuery))
1705                {
1706                        logfileLine("MigrateContainer","Giving up!");
1707                        tJobErrorUpdate(uJob,"vzmigrate on/off-line failed");
1708                        return;
1709                }
1710        }
1711
1712        //If container rrd files exists in our standard fixed dir cp to new node
1713        //Note that cleanup maybe required in the future
1714        sprintf(gcQuery,"/var/lib/rrd/%u.rrd",uContainer);
1715        if(!access(gcQuery,R_OK))
1716        {
1717                sprintf(gcQuery,"/usr/bin/scp %s /var/lib/rrd/%u.rrd %s:/var/lib/rrd/",
1718                        cSCPOptions,uContainer,cTargetNodeIPv4);
1719                if(system(gcQuery))
1720                        logfileLine("MigrateContainer",gcQuery);
1721        }
1722
1723        //Everything ok
1724        SetContainerStatus(uContainer,uPrevStatus);//Previous to awaiting migration
1725        SetContainerNode(uContainer,uTargetNode);//Migrated!
1726        SetContainerDatacenter(uContainer,uTargetDatacenter);
1727        tJobDoneUpdate(uJob);
1728
1729}//void MigrateContainer(...)
1730
1731
1732
1733
1734void GetGroupProp(const unsigned uGroup,const char *cName,char *cValue)
1735{
1736        MYSQL_RES *res;
1737        MYSQL_ROW field;
1738
1739        if(uGroup==0) return;
1740
1741        sprintf(gcQuery,"SELECT cValue FROM tProperty WHERE uKey=%u AND uType=11 AND cName='%s'",
1742                                uGroup,cName);
1743        mysql_query(&gMysql,gcQuery);
1744        if(mysql_errno(&gMysql))
1745        {
1746                logfileLine("GetGroupProp",mysql_error(&gMysql));
1747                exit(2);
1748        }
1749        res=mysql_store_result(&gMysql);
1750        if((field=mysql_fetch_row(res)))
1751        {
1752                char *cp;
1753                if((cp=strchr(field[0],'\n')))
1754                        *cp=0;
1755                sprintf(cValue,"%.255s",field[0]);
1756        }
1757        mysql_free_result(res);
1758
1759}//void GetGroupProp(...)
1760
1761
1762void GetContainerProp(const unsigned uContainer,const char *cName,char *cValue)
1763{
1764        MYSQL_RES *res;
1765        MYSQL_ROW field;
1766
1767        if(uContainer==0) return;
1768
1769        sprintf(gcQuery,"SELECT cValue FROM tProperty WHERE uKey=%u AND uType=3 AND cName='%s'",
1770                                uContainer,cName);
1771        mysql_query(&gMysql,gcQuery);
1772        if(mysql_errno(&gMysql))
1773        {
1774                if(gLfp!=NULL)
1775                {
1776                        logfileLine("GetContainerProp",mysql_error(&gMysql));
1777                        exit(2);
1778                }
1779                else
1780                {
1781                        htmlPlainTextError(mysql_error(&gMysql));
1782                }
1783        }
1784        res=mysql_store_result(&gMysql);
1785        if((field=mysql_fetch_row(res)))
1786        {
1787                char *cp;
1788                if((cp=strchr(field[0],'\n')))
1789                        *cp=0;
1790                sprintf(cValue,"%.255s",field[0]);
1791        }
1792        mysql_free_result(res);
1793
1794}//void GetContainerProp(...)
1795
1796
1797void UpdateContainerUBC(unsigned uJob,unsigned uContainer,const char *cJobData)
1798{
1799
1800        float luBar=0,luLimit=0;
1801        char cBuf[256]={""};
1802        char cResource[256]={""};
1803        char cApplyConfigPath[100]={""};
1804        char cContainerPath[100]={""};
1805        char cUBC[64]={""};
1806        char *cp;
1807
1808        sscanf(cJobData,"cResource=%32s;",cResource);
1809        if((cp=strchr(cResource,';')))
1810                *cp=0;
1811        if(!cResource[0])
1812        {
1813                logfileLine("UpdateContainerUBC","Could not determine cResource");
1814                tJobErrorUpdate(uJob,"cResource[0]==0");
1815                goto CommonExit;
1816        }
1817
1818        sprintf(cUBC,"%.32s.luBarrier",cResource);
1819        GetContainerProp(uContainer,cUBC,cBuf);
1820        sscanf(cBuf,"%f",&luBar);
1821
1822        sprintf(cUBC,"%.32s.luLimit",cResource);
1823        GetContainerProp(uContainer,cUBC,cBuf);
1824        sscanf(cBuf,"%f",&luLimit);
1825
1826        //No PID control yet. 10% increase
1827        //No resource based rules
1828        //No node resources based adjustments
1829        //No expert per resource rules applied
1830        luBar = luBar + luBar * 0.1;
1831        luLimit = luLimit + luLimit * 0.1;
1832
1833        if(uNotValidSystemCallArg(cResource))
1834        {
1835                logfileLine("UpdateContainerUBC","security alert");
1836                tJobErrorUpdate(uJob,"failed sec alert!");
1837                goto CommonExit;
1838        }
1839
1840        //1-.
1841        sprintf(gcQuery,"/usr/sbin/vzctl set %u --%s %.0f:%.0f --save",
1842                uContainer,cResource,luBar,luLimit);
1843        if(system(gcQuery))
1844        {
1845                logfileLine("UpdateContainerUBC",gcQuery);
1846                tJobErrorUpdate(uJob,"vzctl set failed");
1847                goto CommonExit;
1848        }
1849
1850        //2-. validate and/or repair conf file
1851        sprintf(gcQuery,"/usr/sbin/vzcfgvalidate -r /etc/vz/conf/%u.conf > "
1852                        " /tmp/UpdateContainerUBC.vzcfgcheck.output 2>&1",uContainer);
1853        if(system(gcQuery))
1854        {
1855                logfileLine("UpdateContainerUBC",gcQuery);
1856                tJobErrorUpdate(uJob,"vzcfgvalidate failed");
1857                goto CommonExit;
1858        }
1859
1860        //2a-. See if vzcfgvalidate -r changed anything if so report in log and then use
1861        // changed conf file for updates
1862        FILE *fp;
1863        unsigned uChange=0;
1864        if((fp=fopen("/tmp/UpdateContainerUBC.vzcfgcheck.output","r")))
1865        {
1866                while(fgets(cBuf,255,fp)!=NULL)
1867                {
1868                        if(strncmp(cBuf,"set to ",7))
1869                                continue;
1870                        //May have multiple set to lines, the last one is the one we want
1871                        sscanf(cBuf,"set to %f:%f",&luBar,&luLimit);
1872                        uChange++;
1873                }
1874                fclose(fp);
1875                unlink("/tmp/UpdateContainerUBC.vzcfgcheck.output");
1876        }
1877
1878        if(uChange)
1879        {
1880                //3-. See 4-.
1881                sprintf(cContainerPath,"/etc/vz/conf/%u.conf",uContainer);
1882                sprintf(cApplyConfigPath,"/etc/vz/conf/ve-%u.conf-sample",uContainer);
1883                if(symlink(cContainerPath,cApplyConfigPath))
1884                {
1885                        logfileLine("UpdateContainerUBC","symlink failed");
1886                        tJobErrorUpdate(uJob,"symlink failed");
1887                        goto CommonExit;
1888                }
1889
1890                //4-. Apply any changes produced by vzcfgvalidate -r
1891                sprintf(gcQuery,"/usr/sbin/vzctl set %u --applyconfig %u --save",
1892                        uContainer,uContainer);
1893                if(system(gcQuery))
1894                {
1895                        logfileLine("UpdateContainerUBC",gcQuery);
1896                        tJobErrorUpdate(uJob,"vzctl set 4 failed");
1897                        goto CommonExit;
1898                }
1899                unlink(cApplyConfigPath);
1900        }
1901
1902        //5-.
1903        sprintf(gcQuery,"INSERT INTO tLog SET"
1904                " cLabel='UpdateContainerUBC()',"
1905                "uLogType=4,uLoginClient=1,"
1906                "cLogin='unxsVZ.cgi',cMessage='set %u --%s %.0f:%.0f (c=%u)',"
1907                "cServer='%s',uOwner=1,uCreatedBy=1,"
1908                "uCreatedDate=UNIX_TIMESTAMP(NOW())",
1909                                uContainer,cResource,luBar,luLimit,uChange,cHostname);
1910        mysql_query(&gMysql,gcQuery);
1911        if(mysql_errno(&gMysql))
1912        {
1913                logfileLine("UpdateContainerUBC",gcQuery);
1914                tJobErrorUpdate(uJob,"INSERT INTO tLog failed");
1915                goto CommonExit;
1916        }
1917
1918        //Everything ok
1919        tJobDoneUpdate(uJob);
1920
1921CommonExit:
1922        return;
1923
1924}//void UpdateContainerUBC(...)
1925
1926
1927void SetContainerUBC(unsigned uJob,unsigned uContainer,const char *cJobData)
1928{
1929
1930        long unsigned luBar=0,luLimit=0;
1931        char cBuf[256];
1932        char cResource[64]={""};
1933        char cApplyConfigPath[100]={""};
1934        char cContainerPath[100]={""};
1935        char *cp;
1936
1937        sscanf(cJobData,"--%63s %lu:%lu",cResource,&luBar,&luLimit);
1938        if((cp=strchr(cResource,' ')))
1939                *cp=0;
1940        if(!cResource[0])
1941        {
1942                logfileLine("SetContainerUBC","Could not determine cResource");
1943                tJobErrorUpdate(uJob,"cResource[0]==0");
1944                return;
1945        }
1946        if(!luBar || !luLimit)
1947        {
1948                logfileLine("SetContainerUBC","Could not determine luBar||luLimit");
1949                tJobErrorUpdate(uJob,"!luBar||!luLimit");
1950                return;
1951        }
1952
1953        if(uNotValidSystemCallArg(cResource))
1954        {
1955                logfileLine("SetContainerUBC","security alert");
1956                tJobErrorUpdate(uJob,"failed sec alert!");
1957                return;
1958        }
1959
1960        //1-.
1961        sprintf(gcQuery,"/usr/sbin/vzctl set %u --%s %lu:%lu --save",
1962                uContainer,cResource,luBar,luLimit);
1963        if(system(gcQuery))
1964        {
1965                logfileLine("SetContainerUBC",gcQuery);
1966                tJobErrorUpdate(uJob,"vzctl set failed");
1967                return;
1968        }
1969
1970        //2-. validate and/or repair conf file
1971        sprintf(gcQuery,"/usr/sbin/vzcfgvalidate -r /etc/vz/conf/%u.conf > "
1972                        " /tmp/SetContainerUBC.vzcfgcheck.output 2>&1",uContainer);
1973        if(system(gcQuery))
1974        {
1975                logfileLine("SetContainerUBC",gcQuery);
1976                tJobErrorUpdate(uJob,"vzcfgvalidate failed");
1977                //No need to roll back above set
1978                return;
1979        }
1980
1981        //2a-. See if vzcfgvalidate -r changed anything if so report in log and then use
1982        // changed conf file for updates
1983        FILE *fp;
1984        unsigned uChange=0;
1985        if((fp=fopen("/tmp/SetContainerUBC.vzcfgcheck.output","r")))
1986        {
1987                while(fgets(cBuf,255,fp)!=NULL)
1988                {
1989                        if(strncmp(cBuf,"set to ",7))
1990                                continue;
1991                        //May have multiple set to lines, the last one is the one we want
1992                        sscanf(cBuf,"set to %lu:%lu",&luBar,&luLimit);
1993                        uChange++;
1994                }
1995                fclose(fp);
1996                unlink("/tmp/SetContainerUBC.vzcfgcheck.output");
1997        }
1998
1999        if(uChange)
2000        {
2001                //3-. See 4-.
2002                sprintf(cContainerPath,"/etc/vz/conf/%u.conf",uContainer);
2003                sprintf(cApplyConfigPath,"/etc/vz/conf/ve-%u.conf-sample",uContainer);
2004                if(symlink(cContainerPath,cApplyConfigPath))
2005                {
2006                        logfileLine("SetContainerUBC",cContainerPath);
2007                        tJobErrorUpdate(uJob,"symlink failed");
2008                        //no rollback needed
2009                        return;
2010                }
2011
2012                //4-. Apply any changes produced by vzcfgvalidate -r
2013                sprintf(gcQuery,"/usr/sbin/vzctl set %u --applyconfig %u --save",
2014                        uContainer,uContainer);
2015                if(system(gcQuery))
2016                {
2017                        logfileLine("SetContainerUBC",gcQuery);
2018                        tJobErrorUpdate(uJob,"vzctl set 4 failed");
2019                        //no rollback needed
2020                        return;
2021                }
2022                unlink(cApplyConfigPath);
2023        }
2024
2025        //5-.
2026        sprintf(gcQuery,"INSERT INTO tLog SET"
2027                " cLabel='SetContainerUBC()',"
2028                "uLogType=4,uLoginClient=1,"
2029                "cLogin='unxsVZ.cgi',cMessage='set %u --%s %lu:%lu (c=%u)',"
2030                "cServer='%s',uOwner=1,uCreatedBy=1,"
2031                "uCreatedDate=UNIX_TIMESTAMP(NOW())",
2032                                uContainer,cResource,luBar,luLimit,uChange,cHostname);
2033        mysql_query(&gMysql,gcQuery);
2034        if(mysql_errno(&gMysql))
2035        {
2036                logfileLine("SetContainerUBC",mysql_error(&gMysql));
2037                tJobErrorUpdate(uJob,"INSERT INTO tLog failed");
2038                return;
2039        }
2040
2041        //Everything ok
2042        tJobDoneUpdate(uJob);
2043
2044}//void SetContainerUBC(...)
2045
2046
2047void TemplateContainer(unsigned uJob,unsigned uContainer,const char *cJobData)
2048{
2049        //Only run one vzdump job per HN. Wait for lock release.
2050        //Log this rare condition
2051        //This lock file is created by the external proxmox script vzdump
2052        if(access("/var/run/vzdump.lock",R_OK)==0)
2053        {
2054                logfileLine("TemplateContainer","/var/run/vzdump.lock exists");
2055                tJobWaitingUpdate(uJob);
2056                return;
2057        }
2058
2059        MYSQL_RES *res;
2060        MYSQL_ROW field;
2061
2062        char cConfigLabel[32]={""};
2063        char cOSTemplateBase[68]={"centos-5-x86_64"};
2064        char *cp;
2065        register int i;
2066        struct stat statInfo;
2067        unsigned uOwner=1;
2068        unsigned uCreatedBy=1;
2069        unsigned uPrevStatus=0;
2070
2071        //Parse data and basic sanity checks
2072        sscanf(cJobData,"tConfig.Label=%31s;",cConfigLabel);
2073        if((cp=strchr(cConfigLabel,';')))
2074                *cp=0;
2075        if(!cConfigLabel[0])
2076        {
2077                logfileLine("TemplateContainer","Could not determine cConfigLabel");
2078                tJobErrorUpdate(uJob,"cConfigLabel[0]==0");
2079                goto CommonExit;
2080        }
2081        if((cp=strstr(cJobData,"uPrevStatus=")))
2082                sscanf(cp+12,"%u",&uPrevStatus);
2083        if(!uPrevStatus)
2084        {
2085                logfileLine("TemplateContainer","Could not determine uPrevStatus assuming active");
2086                uPrevStatus=1;
2087        }
2088
2089
2090        sprintf(gcQuery,"SELECT tOSTemplate.cLabel FROM tContainer,tOSTemplate"
2091                        " WHERE tContainer.uOSTemplate=tOSTemplate.uOSTemplate AND"
2092                        " tContainer.uContainer=%u",uContainer);
2093        mysql_query(&gMysql,gcQuery);
2094        if(mysql_errno(&gMysql))
2095        {
2096                logfileLine("TemplateContainer",mysql_error(&gMysql));
2097                tJobErrorUpdate(uJob,"SELECT tOSTemplate.cLabel");
2098                goto CommonExit;
2099        }
2100        res=mysql_store_result(&gMysql);
2101        if((field=mysql_fetch_row(res)))
2102                sprintf(cOSTemplateBase,"%.67s",field[0]);
2103        mysql_free_result(res);
2104        if(!cOSTemplateBase[0])
2105        {
2106                logfileLine("TemplateContainer","Could not determine cOSTemplateBase");
2107                tJobErrorUpdate(uJob,"cOSTemplateBase[0]==0");
2108                goto CommonExit;
2109        }
2110
2111        //Remove ending dash part if any
2112        for(i=strlen(cOSTemplateBase)-1;i>0;i--)
2113        {
2114                if(cOSTemplateBase[i]=='-')
2115                {
2116                        cOSTemplateBase[i]=0;   
2117                        break;
2118                }
2119        }
2120        //debug only
2121        //printf("cConfigLabel=%s; cOSTemplateBase=%s;\n",cConfigLabel,cOSTemplateBase);
2122        //exit(0);
2123
2124        if(uNotValidSystemCallArg(cOSTemplateBase) || uNotValidSystemCallArg(cConfigLabel))
2125        {
2126                logfileLine("TemplateContainer","security alert");
2127                tJobErrorUpdate(uJob,"failed sec alert!");
2128                goto CommonExit;
2129        }
2130
2131        char cSnapshotDir[256]={""};
2132        GetConfiguration("cSnapshotDir",cSnapshotDir,gfuDatacenter,gfuNode,0,0);//First try node specific
2133        if(!cSnapshotDir[0])
2134        {
2135                GetConfiguration("cSnapshotDir",cSnapshotDir,gfuDatacenter,0,0,0);//Second try datacenter wide
2136                if(!cSnapshotDir[0])
2137                        GetConfiguration("cSnapshotDir",cSnapshotDir,0,0,0,0);//Last try global
2138        }
2139        if(uNotValidSystemCallArg(cSnapshotDir))
2140                cSnapshotDir[0]=0;
2141        //1-.
2142        if(!cSnapshotDir[0])
2143                sprintf(gcQuery,"/usr/sbin/vzdump --compress --suspend %u",uContainer);
2144        else
2145                sprintf(gcQuery,"/usr/sbin/vzdump --compress --dumpdir %s --snapshot %u",
2146                                                                        cSnapshotDir,uContainer);
2147        if(system(gcQuery))
2148        {
2149                logfileLine("TemplateContainer",gcQuery);
2150                tJobErrorUpdate(uJob,"vzdump error1");
2151                goto CommonExit;
2152        }
2153
2154        //New vzdump uses new file format, E.G.: /var/vzdump/vzdump-openvz-10511-2011_02_03-07_37_01.tgz
2155        //Quick fix (hackorama) just mv it to old format
2156        //Added support for old vzdump
2157        if(!cSnapshotDir[0])
2158                sprintf(gcQuery,"if [ ! -f /var/vzdump/vzdump-%u.tgz ];then"
2159                                " mv `ls -1 /vz/dump/vzdump*-%u-*.tgz | head -n 1` /vz/dump/vzdump-%u.tgz; fi;",
2160                                        uContainer,uContainer,uContainer);
2161        else
2162                sprintf(gcQuery,"if [ -f /var/vzdump/vzdump-%u.tgz ] && [ \"%s\" != \"/var/vzdump\" ];then"
2163                                " mv /var/vzdump/vzdump-%u.tgz %s/vzdump-%u.tgz;else"
2164                                " if [ -f %s/vzdump*-%u-*.tgz ];then mv `ls -1 %s/vzdump*-%u-*.tgz | head -n 1` %s/vzdump-%u.tgz;fi;fi;",
2165                                uContainer,cSnapshotDir,
2166                                uContainer,cSnapshotDir,uContainer,
2167                                cSnapshotDir,uContainer,cSnapshotDir,uContainer,cSnapshotDir,uContainer);
2168        if(system(gcQuery))
2169        {
2170                logfileLine("TemplateContainer",gcQuery);
2171                tJobErrorUpdate(uJob,"error 1a1");
2172                goto CommonExit;
2173        }
2174
2175
2176        //2-.   
2177        if(!cSnapshotDir[0])
2178                sprintf(gcQuery,"mv /vz/dump/vzdump-%u.tgz /vz/template/cache/%.67s-%.32s.tar.gz",
2179                                uContainer,cOSTemplateBase,cConfigLabel);
2180        else
2181                sprintf(gcQuery,"mv %s/vzdump-%u.tgz /vz/template/cache/%.67s-%.32s.tar.gz",
2182                                cSnapshotDir,uContainer,cOSTemplateBase,cConfigLabel);
2183        if(system(gcQuery))
2184        {
2185                logfileLine("TemplateContainer",gcQuery);
2186                tJobErrorUpdate(uJob,"mv tgz to cache tar.gz failed");
2187                goto CommonExit;
2188        }
2189
2190        //2b-. md5sum generation
2191        if(!stat("/usr/bin/md5sum",&statInfo))
2192        {
2193                sprintf(gcQuery,"/usr/bin/md5sum /vz/template/cache/%.67s-%.32s.tar.gz >"
2194                                " /vz/template/cache/%.67s-%.32s.tar.gz.md5sum",
2195                        cOSTemplateBase,cConfigLabel,cOSTemplateBase,cConfigLabel);
2196                if(system(gcQuery))
2197                {
2198                        logfileLine("TemplateContainer",gcQuery);
2199                        tJobErrorUpdate(uJob,"md5sum tgz failed");
2200                        goto CommonExit;
2201                }
2202        }
2203
2204
2205        //3-. scp template to all nodes depends on /usr/sbin/allnodescp.sh installed and configured correctly
2206        if(!stat("/usr/sbin/allnodescp.sh",&statInfo))
2207        {
2208                sprintf(gcQuery,"/usr/sbin/allnodescp.sh /vz/template/cache/%.67s-%.32s.tar.gz",
2209                        cOSTemplateBase,cConfigLabel);
2210                if(system(gcQuery))
2211                {
2212                        logfileLine("TemplateContainer",gcQuery);
2213                        tJobErrorUpdate(uJob,"allnodescp.sh .tar.gz failed");
2214                        goto CommonExit;
2215                }
2216                sprintf(gcQuery,"/usr/sbin/allnodescp.sh /vz/template/cache/%.67s-%.32s.tar.gz.md5sum",
2217                        cOSTemplateBase,cConfigLabel);
2218                if(system(gcQuery))
2219                {
2220                        logfileLine("TemplateContainer",gcQuery);
2221                        tJobErrorUpdate(uJob,"allnodescp.sh .tar.gz.md5sum failed");
2222                        goto CommonExit;
2223                }
2224        }
2225
2226        //3b-. check transfer via md5sum
2227        //Relies on new version of "/usr/sbin/allnodecmd.sh" that adds return values.
2228        if(!stat("/usr/sbin/allnodecmd.sh",&statInfo) && !stat("/usr/bin/md5sum",&statInfo))
2229        {
2230                sprintf(gcQuery,"/usr/sbin/allnodecmd.sh \"/usr/bin/md5sum -c /vz/template/cache/%.67s-%.32s.tar.gz.md5sum\"",
2231                        cOSTemplateBase,cConfigLabel);
2232                if(system(gcQuery))
2233                {
2234                        logfileLine("TemplateContainer",gcQuery);
2235                        tJobErrorUpdate(uJob,"allnodecmd.sh md5sum -c .tar.gz.md5sum failed");
2236                        goto CommonExit;
2237                }
2238        }
2239
2240        //4-. Make /etc/vz/conf tConfig file and scp to all nodes. ve-proxpop.conf-sample
2241        sprintf(gcQuery,"/bin/cp /etc/vz/conf/%u.conf /etc/vz/conf/ve-%.32s.conf-sample",
2242                uContainer,cConfigLabel);
2243        if(system(gcQuery))
2244        {
2245                logfileLine("TemplateContainer",gcQuery);
2246                tJobErrorUpdate(uJob,"cp conf container failed");
2247                goto CommonExit;
2248        }
2249        if(!stat("/usr/sbin/allnodescp.sh",&statInfo))
2250        {
2251                sprintf(gcQuery,"/usr/sbin/allnodescp.sh /etc/vz/conf/ve-%.32s.conf-sample",cConfigLabel);
2252                if(system(gcQuery))
2253                {
2254                        logfileLine("TemplateContainer",gcQuery);
2255                        tJobErrorUpdate(uJob,"allnodescp.sh .conf failed");
2256                        goto CommonExit;
2257                }
2258        }
2259
2260        //5a-. Add tOSTemplate and tConfig entries if not already there tContainer wizard
2261        //should help prevent this.
2262        sprintf(gcQuery,"SELECT uOwner,uCreatedBy FROM tJob WHERE uJob=%u",uJob);
2263        mysql_query(&gMysql,gcQuery);
2264        if(mysql_errno(&gMysql))
2265        {
2266                logfileLine("TemplateContainer",mysql_error(&gMysql));
2267        }
2268        else
2269        {
2270                res=mysql_store_result(&gMysql);
2271                if((field=mysql_fetch_row(res)))
2272                {
2273                        sscanf(field[0],"%u",&uOwner);
2274                        sscanf(field[1],"%u",&uCreatedBy);
2275                }
2276                mysql_free_result(res);
2277        }
2278
2279        sprintf(gcQuery,"SELECT uOSTemplate FROM tOSTemplate WHERE cLabel='%.67s-%.32s'"
2280                                                        ,cOSTemplateBase,cConfigLabel);
2281        mysql_query(&gMysql,gcQuery);
2282        if(mysql_errno(&gMysql))
2283        {
2284                logfileLine("TemplateContainer",mysql_error(&gMysql));
2285                tJobErrorUpdate(uJob,"SELECT tOSTemplate");
2286                goto CommonExit;
2287        }
2288        res=mysql_store_result(&gMysql);
2289        if(mysql_num_rows(res)<1)
2290        {
2291                sprintf(gcQuery,"INSERT tOSTemplate SET cLabel='%.67s-%.32s',uOwner=%u,uCreatedBy=%u,"
2292                                "uCreatedDate=UNIX_TIMESTAMP(NOW())",cOSTemplateBase,cConfigLabel,
2293                                                                        uOwner,uCreatedBy);
2294                mysql_query(&gMysql,gcQuery);
2295                if(mysql_errno(&gMysql))
2296                {
2297                        logfileLine("TemplateContainer",mysql_error(&gMysql));
2298                        tJobErrorUpdate(uJob,"INSERT tOSTemplate");
2299                        goto CommonExit;
2300                }
2301        }
2302        mysql_free_result(res);
2303        //5b-.
2304        sprintf(gcQuery,"SELECT uConfig FROM tConfig WHERE cLabel='%.32s'",cConfigLabel);
2305        mysql_query(&gMysql,gcQuery);
2306        if(mysql_errno(&gMysql))
2307        {
2308                logfileLine("TemplateContainer",mysql_error(&gMysql));
2309                tJobErrorUpdate(uJob,"SELECT tConfig");
2310                goto CommonExit;
2311        }
2312        res=mysql_store_result(&gMysql);
2313        if(mysql_num_rows(res)<1)
2314        {
2315                sprintf(gcQuery,"INSERT tConfig SET cLabel='%.32s',uOwner=%u,uCreatedBy=%u,"
2316                                "uCreatedDate=UNIX_TIMESTAMP(NOW())",cConfigLabel,uOwner,uCreatedBy);
2317                mysql_query(&gMysql,gcQuery);
2318                if(mysql_errno(&gMysql))
2319                {
2320                        logfileLine("TemplateContainer",mysql_error(&gMysql));
2321                        tJobErrorUpdate(uJob,"INSERT tConfig");
2322                        goto CommonExit;
2323                }
2324        }
2325        mysql_free_result(res);
2326
2327        //Everything ok
2328        SetContainerStatus(uContainer,uPrevStatus);
2329        tJobDoneUpdate(uJob);
2330
2331//This goto MAYBE ok
2332CommonExit:
2333        //6-. remove lock file
2334        //vzdump script should handle this?
2335        unlink("/var/run/vzdump.lock");
2336        return;
2337
2338}//void TemplateContainer(...)
2339
2340
2341//OpenVZ action scripts
2342void ActionScripts(unsigned uJob,unsigned uContainer)
2343{
2344        //0 means do not overwrite existing files.
2345        if(CreateActionScripts(uContainer,0))
2346        {
2347                logfileLine("ActionScripts","CreateActionScripts(x,0) failed");
2348                tJobErrorUpdate(uJob,"CreateActionScripts(x,0) failed");
2349                return;
2350        }
2351
2352        tJobDoneUpdate(uJob);
2353        return;
2354
2355}//void ActionScripts(unsigned uJob,unsigned uContainer);
2356
2357
2358void CloneContainer(unsigned uJob,unsigned uContainer,char *cJobData)
2359{
2360        MYSQL_RES *res;
2361        MYSQL_ROW field;
2362        char cTargetNodeIPv4[256]={""};
2363        unsigned uNewVeid=0;
2364        unsigned uCloneStop=0;
2365        unsigned uStatus=0;
2366        unsigned uPrevStatus=0;
2367        unsigned uTargetNode=0;
2368        char cNewIP[32]={""};
2369        char cHostname[100]={""};
2370        char cName[32]={""};
2371
2372
2373        //We can't clone a container that is not ready
2374        if(GetContainerStatus(uContainer,&uStatus))
2375        {
2376                logfileLine("CloneContainer","GetContainerStatus() failed");
2377                //Keep job status running...hopefully someone will notice.
2378                return;
2379        }
2380        if(!(uStatus==uACTIVE || uStatus==uSTOPPED || uStatus==uAWAITCLONE))
2381        {
2382                sprintf(gcQuery,"UPDATE tJob SET uJobStatus=1,cRemoteMsg='Waiting for source container',uModBy=1,"
2383                                "uModDate=UNIX_TIMESTAMP(NOW()) WHERE uJob=%u",uJob);
2384                mysql_query(&gMysql,gcQuery);
2385                if(mysql_errno(&gMysql))
2386                        logfileLine("ProcessJob()",mysql_error(&gMysql));
2387                logfileLine("CloneContainer","Waiting");
2388                return;
2389        }
2390
2391        //CloneWizard created a new tContainer with "Awaiting Clone" status.
2392        //CloneWizard created a job (this job) that runs on the source container node.
2393        //The created job has job data to complete the operations on source and
2394        //target nodes.
2395        //vzdump script must be installed on all datacenter nodes.
2396
2397        //Only run one CloneContainer job per HN. Wait for lock release.
2398        //Log this rare condition
2399        //This lock file is created by the external proxmox script vzdump
2400        if(access("/var/run/vzdump.lock",R_OK)==0)
2401        {
2402                logfileLine("CloneContainer","/var/run/vzdump.lock exists");
2403                tJobWaitingUpdate(uJob);
2404                return;
2405        }
2406
2407        //Set job data based vars
2408        sscanf(cJobData,"uTargetNode=%u;",&uTargetNode);
2409        if(!uTargetNode)
2410        {
2411                logfileLine("CloneContainer","Could not determine uTargetNode");
2412                tJobErrorUpdate(uJob,"uTargetNode==0");
2413                goto CommonExit;
2414        }
2415        sscanf(cJobData,"uTargetNode=%*u;\nuNewVeid=%u;",&uNewVeid);
2416        if(!uNewVeid)
2417        {
2418                logfileLine("CloneContainer","Could not determine uNewVeid");
2419                tJobErrorUpdate(uJob,"uNewVeid==0");
2420                goto CommonExit;
2421        }
2422
2423        //
2424        //Handle remote datacenter clone jobs differently
2425        unsigned uTargetDatacenter=0;
2426        sprintf(gcQuery,"SELECT uDatacenter FROM tContainer WHERE uContainer=%u",uNewVeid);
2427        mysql_query(&gMysql,gcQuery);
2428        if(mysql_errno(&gMysql))
2429        {
2430                logfileLine("CloneContainer",mysql_error(&gMysql));
2431                tJobErrorUpdate(uJob,"SELECT uDatacenter");
2432                goto CommonExit;
2433        }
2434        res=mysql_store_result(&gMysql);
2435        if((field=mysql_fetch_row(res)))
2436                sscanf(field[0],"%u",&uTargetDatacenter);
2437        mysql_free_result(res);
2438        if(gfuDatacenter!=uTargetDatacenter && uTargetDatacenter!=0 && gfuDatacenter!=0)
2439        {
2440                logfileLine("CloneContainer","CloneRemoteContainer() bypass test on");
2441                //CloneRemoteContainer(uJob,uContainer,cJobData,uNewVeid);
2442                //return;
2443        }
2444
2445        //
2446        sscanf(cJobData,"uTargetNode=%*u;\nuNewVeid=%*u;\nuCloneStop=%u;",&uCloneStop);
2447        sscanf(cJobData,"uTargetNode=%*u;\nuNewVeid=%*u;\nuCloneStop=%*u;\nuPrevStatus=%u;",&uPrevStatus);
2448        if(!uPrevStatus)
2449        {
2450                logfileLine("CloneContainer","Could not determine uPrevStatus");
2451                tJobErrorUpdate(uJob,"uPrevStatus==0");
2452                goto CommonExit;
2453        }
2454
2455        sprintf(gcQuery,"SELECT tIP.cLabel,tContainer.cHostname,tContainer.cLabel FROM tIP,tContainer"
2456                                " WHERE tIP.uIP=tContainer.uIPv4"
2457                                " AND tContainer.uContainer=%u",uNewVeid);
2458        mysql_query(&gMysql,gcQuery);
2459        if(mysql_errno(&gMysql))
2460        {
2461                logfileLine("CloneContainer",mysql_error(&gMysql));
2462                tJobErrorUpdate(uJob,"SELECT tIP.cLabel");
2463                goto CommonExit;
2464        }
2465        res=mysql_store_result(&gMysql);
2466        if((field=mysql_fetch_row(res)))
2467        {
2468                sprintf(cNewIP,"%.31s",field[0]);
2469                sprintf(cHostname,"%.99s",field[1]);
2470                sprintf(cName,"%.31s",field[2]);
2471        }
2472        mysql_free_result(res);
2473
2474        if(!cNewIP[0])
2475        {
2476                logfileLine("CloneContainer","Could not determine cNewIP");
2477                tJobErrorUpdate(uJob,"No cNewIP");
2478                goto CommonExit;
2479        }
2480
2481        if(!cHostname[0])
2482        {
2483                logfileLine("CloneContainer","Could not determine cHostname");
2484                tJobErrorUpdate(uJob,"No cHostname");
2485                goto CommonExit;
2486        }
2487
2488        if(!cName[0])
2489        {
2490                logfileLine("CloneContainer","Could not determine cName");
2491                tJobErrorUpdate(uJob,"No cName");
2492                goto CommonExit;
2493        }
2494
2495        //This needs it's tcontainerfunc.h counterpart on new and a tConfiguration entry
2496        //to set this IP to either the internal transfer IP or the public IP if servers
2497        //have only one NIC (yuck ;)
2498        GetNodeProp(uTargetNode,"cIPv4",cTargetNodeIPv4);
2499        if(!cTargetNodeIPv4[0])
2500        {
2501                logfileLine("CloneContainer","Could not determine cTargetNodeIPv4");
2502                tJobErrorUpdate(uJob,"cTargetNodeIPv4");
2503                goto CommonExit;
2504        }
2505
2506        //if(uDebug)
2507        //{
2508        //      printf("uNewVeid=%u uTargetNode=%u cNewIP=%s cHostname=%s cTargetNodeIPv4=%s"
2509        //              "cSourceContainerIP=%s uCloneStop=%u\n",
2510        //                      uNewVeid,uTargetNode,cNewIP,cHostname,
2511        //                      cTargetNodeIPv4,cSourceContainerIP,uCloneStop);
2512        //      return;
2513        //}
2514
2515        //1-. vzdump w/suspend on source node or if cSnapshotDir is not empty we try to use LVM2
2516        //2-. scp dump to target node
2517        //3-. restore on target node to new veid
2518        //4-. change ip, name and hostname
2519        //5-. remove any other /etc/vz/conf/veid.x files
2520        //6-. conditionally start new veid and modify VEID.conf file to not start on boot.
2521        //7-. update source container status
2522        //8-. update target container status
2523        //9-. remove /vz/dump files
2524
2525        //Most specific tConfiguration is used. This allows for some nodes to be set global
2526        //and others specific. But is slower than the other option with what maybe
2527        //very large numbers of per node tConfiguration entries.
2528        char cSSHOptions[256]={""};
2529        GetConfiguration("cSSHOptions",cSSHOptions,gfuDatacenter,gfuNode,0,0);//First try node specific
2530        if(!cSSHOptions[0])
2531        {
2532                GetConfiguration("cSSHOptions",cSSHOptions,gfuDatacenter,0,0,0);//Second try datacenter wide
2533                if(!cSSHOptions[0])
2534                        GetConfiguration("cSSHOptions",cSSHOptions,0,0,0,0);//Last try global
2535        }
2536        //Default for less conditions below
2537        if(!cSSHOptions[0] || uNotValidSystemCallArg(cSSHOptions))
2538                sprintf(cSSHOptions,"-p 22 -c arcfour");
2539
2540        char cSCPOptions[256]={""};
2541        GetConfiguration("cSCPOptions",cSCPOptions,gfuDatacenter,gfuNode,0,0);//First try node specific
2542        if(!cSCPOptions[0])
2543        {
2544                GetConfiguration("cSCPOptions",cSCPOptions,gfuDatacenter,0,0,0);//Second try datacenter wide
2545                if(!cSCPOptions[0])
2546                        GetConfiguration("cSCPOptions",cSCPOptions,0,0,0,0);//Last try global
2547        }
2548        //Default for less conditions below
2549        if(!cSCPOptions[0] || uNotValidSystemCallArg(cSCPOptions))
2550                sprintf(cSCPOptions,"-P 22 -c arcfour");
2551
2552        char cSnapshotDir[256]={""};
2553        GetConfiguration("cSnapshotDir",cSnapshotDir,gfuDatacenter,gfuNode,0,0);//First try node specific
2554        if(!cSnapshotDir[0])
2555        {
2556                GetConfiguration("cSnapshotDir",cSnapshotDir,gfuDatacenter,0,0,0);//Second try datacenter wide
2557                if(!cSnapshotDir[0])
2558                        GetConfiguration("cSnapshotDir",cSnapshotDir,0,0,0,0);//Last try global
2559        }
2560        if(uNotValidSystemCallArg(cSnapshotDir))
2561                cSnapshotDir[0]=0;
2562        //1-.
2563        if(!cSnapshotDir[0])
2564                sprintf(gcQuery,"/usr/sbin/vzdump --compress --suspend %u",uContainer);
2565        else
2566                sprintf(gcQuery,"/usr/sbin/vzdump --compress --dumpdir %s --snapshot %u",
2567                                                                        cSnapshotDir,uContainer);
2568        if(system(gcQuery))
2569        {
2570                logfileLine("CloneContainer",gcQuery);
2571                tJobErrorUpdate(uJob,"error 1");
2572                goto CommonExit;
2573        }
2574
2575
2576        //Support for old and new vzdump
2577        //New vzdump uses new file format, E.G.: /var/vzdump/vzdump-openvz-10511-2011_02_03-07_37_01.tgz
2578        //Quick fix (hackorama) just mv it to old format
2579        if(!cSnapshotDir[0])
2580                sprintf(gcQuery,"if [ ! -f /var/vzdump/vzdump-%u.tgz ];then"
2581                                " mv `ls -1 /vz/dump/vzdump*-%u-*.tgz | head -n 1` /vz/dump/vzdump-%u.tgz; fi;",
2582                                        uContainer,uContainer,uContainer);
2583        else
2584                sprintf(gcQuery,"if [ -f /var/vzdump/vzdump-%u.tgz ] && [ \"%s\" != \"/var/vzdump\" ];then"
2585                                " mv /var/vzdump/vzdump-%u.tgz %s/vzdump-%u.tgz;else"
2586                                " if [ -f %s/vzdump*-%u-*.tgz ];then mv `ls -1 %s/vzdump*-%u-*.tgz | head -n 1` %s/vzdump-%u.tgz;fi;fi;",
2587                                uContainer,cSnapshotDir,
2588                                uContainer,cSnapshotDir,uContainer,
2589                                cSnapshotDir,uContainer,cSnapshotDir,uContainer,cSnapshotDir,uContainer);
2590        if(system(gcQuery))
2591        {
2592                logfileLine("CloneContainer",gcQuery);
2593                tJobErrorUpdate(uJob,"error 1a1a");
2594                goto CommonExit;
2595        }
2596
2597
2598        //1a-. Need an md5sum file created. TODO
2599        if(!cSnapshotDir[0])
2600                sprintf(gcQuery,"/usr/bin/md5sum /vz/dump/vzdump-%u.tgz > /vz/dump/vzdump-%u.tgz.md5sum",
2601                                uContainer,uContainer);
2602        else
2603                //Some trickery to get the right file listed in the md5sum file
2604                sprintf(gcQuery,"ln -s %s/vzdump-%u.tgz /vz/dump/vzdump-%u.tgz;"
2605                                " /usr/bin/md5sum /vz/dump/vzdump-%u.tgz > %s/vzdump-%u.tgz.md5sum;"
2606                                " rm -f /vz/dump/vzdump-%u.tgz",
2607                                cSnapshotDir,uContainer,uContainer,uContainer,cSnapshotDir,uContainer,uContainer);
2608        if(system(gcQuery))
2609        {
2610                logfileLine("CloneContainer",gcQuery);
2611                tJobErrorUpdate(uJob,"error 1a");
2612                goto CommonExit;
2613        }
2614
2615
2616        //2-.
2617        if(uNotValidSystemCallArg(cTargetNodeIPv4))
2618        {
2619                tJobErrorUpdate(uJob,"fail sec alert!");
2620                goto CommonExit;
2621        }
2622        if(!cSnapshotDir[0])
2623                sprintf(gcQuery,"/usr/bin/scp %s /vz/dump/vzdump-%u.tgz %s:/vz/dump/vzdump-%u.tgz",
2624                                cSCPOptions,uContainer,cTargetNodeIPv4,uContainer);
2625        else
2626                sprintf(gcQuery,"/usr/bin/scp %s %s/vzdump-%u.tgz %s:/vz/dump/vzdump-%u.tgz",
2627                                cSCPOptions,cSnapshotDir,uContainer,cTargetNodeIPv4,uContainer);
2628        if(system(gcQuery))
2629        {
2630                logfileLine("CloneContainer",gcQuery);
2631                tJobErrorUpdate(uJob,"error 2");
2632                goto CommonExit;
2633        }
2634
2635        //2a-. Need md5sum file moved to target. TODO
2636        if(!cSnapshotDir[0])
2637                sprintf(gcQuery,"/usr/bin/scp %s /vz/dump/vzdump-%u.tgz.md5sum %s:/vz/dump/vzdump-%u.tgz.md5sum",
2638                                cSCPOptions,uContainer,cTargetNodeIPv4,uContainer);
2639        else
2640                sprintf(gcQuery,"/usr/bin/scp %s %s/vzdump-%u.tgz.md5sum %s:/vz/dump/vzdump-%u.tgz.md5sum",
2641                                cSCPOptions,cSnapshotDir,uContainer,cTargetNodeIPv4,uContainer);
2642        if(system(gcQuery))
2643        {
2644                logfileLine("CloneContainer",gcQuery);
2645                tJobErrorUpdate(uJob,"error 2a");
2646                goto CommonExit;
2647        }
2648
2649        //2b-. Need an md5sum check. TODO
2650        sprintf(gcQuery,"ssh %s %s '/usr/bin/md5sum -c /vz/dump/vzdump-%u.tgz.md5sum'",
2651                                cSSHOptions,cTargetNodeIPv4,uContainer);
2652        if(system(gcQuery))
2653        {
2654                logfileLine("CloneContainer",gcQuery);
2655                tJobErrorUpdate(uJob,"error 2b");
2656                goto CommonExit;
2657        }
2658
2659        //3-.
2660        sprintf(gcQuery,"ssh %s %s '/usr/sbin/vzdump --compress --restore /vz/dump/vzdump-%u.tgz %u'",
2661                                cSSHOptions,cTargetNodeIPv4,uContainer,uNewVeid);
2662        //debug only
2663        //logfileLine("CloneContainer",gcQuery);
2664        if(system(gcQuery))
2665        {
2666                //We need to check the error number and if like this error (that maybe be related to cascading cloning
2667                //operations):
2668                //INFO: extracting configuration to '/etc/vz/conf/3281.conf'
2669                //command 'sed -e 's/VE_ROOT=.*/VE_ROOT=\"\/vz\/root\/$VEID\"/' -e 's/VE_PRIVATE=.*/VE_PRIVATE=\"\/vz\/private\/$VEID\"/'  <'/vz/private/3281/etc/vzdump/vps.conf' >'/etc/vz/conf/3281.conf'' failed with exit code 1
2670                //INFO: sh: /vz/private/3281/etc/vzdump/vps.conf: No such file or directory
2671                //Apr 01 17:24:19 jobqueue.CloneContainer[16404]: ssh -p 12337 -c blowfish -C 10.0.10.2 '/usr/sbin/vzdump --compress --restore /vz/dump/vzdump-2704.tgz 3281'
2672                //then we "resubmit" the job for 30 mins in the future. 30 mins tConfiguration configurable.
2673
2674                //Try new version vzrestore
2675                sprintf(gcQuery,"ssh %s %s '/usr/sbin/vzrestore /vz/dump/vzdump-%u.tgz %u'",
2676                                cSSHOptions,cTargetNodeIPv4,uContainer,uNewVeid);
2677                if(system(gcQuery))
2678                {
2679                        logfileLine("CloneContainer",gcQuery);
2680                        tJobErrorUpdate(uJob,"error 3");
2681                        goto CommonExit;
2682                }
2683        }
2684
2685        //4a-.
2686        if(uNotValidSystemCallArg(cHostname))
2687        {
2688                tJobErrorUpdate(uJob,"fail sec alert!");
2689                goto CommonExit;
2690        }
2691        sprintf(gcQuery,"ssh %s %s 'vzctl set %u --hostname %s --save'",
2692                                cSSHOptions,cTargetNodeIPv4,uNewVeid,cHostname);
2693        //debug only
2694        //logfileLine("CloneContainer",gcQuery);
2695        if(system(gcQuery))
2696        {
2697                logfileLine("CloneContainer",gcQuery);
2698                tJobErrorUpdate(uJob,"error 4a");
2699                goto CommonExit;
2700        }
2701
2702        //4b-.
2703        sprintf(gcQuery,"ssh %s %s 'vzctl set %u --name %s --save'",
2704                                cSSHOptions,cTargetNodeIPv4,uNewVeid,cName);
2705        //debug only
2706        //logfileLine("CloneContainer",gcQuery);
2707        if(system(gcQuery))
2708        {
2709                logfileLine("CloneContainer",gcQuery);
2710                tJobErrorUpdate(uJob,"error 4b");
2711                goto CommonExit;
2712        }
2713
2714        //4c-.
2715        //Some containers have more than one IP when how? Not via jobqueue.c
2716        //Only via action scripts other IPs are used.
2717        //Any way we can use --ipdel all instead of ticket #83
2718        if(uNotValidSystemCallArg(cTargetNodeIPv4))
2719        {
2720                tJobErrorUpdate(uJob,"fail sec alert!");
2721                goto CommonExit;
2722        }
2723        sprintf(gcQuery,"ssh %s %s 'vzctl set %u --ipdel all --save'",
2724                                cSSHOptions,cTargetNodeIPv4,uNewVeid);
2725        if(system(gcQuery))
2726        {
2727                logfileLine("CloneContainer",gcQuery);
2728                tJobErrorUpdate(uJob,"error 4c");
2729                goto CommonExit;
2730        }
2731        //4d-.
2732        sprintf(gcQuery,"ssh %s %s 'vzctl set %u --ipadd %s --save'",
2733                                cSSHOptions,cTargetNodeIPv4,uNewVeid,cNewIP);
2734        //debug only
2735        //logfileLine("CloneContainer",gcQuery);
2736        if(system(gcQuery))
2737        {
2738                logfileLine("CloneContainer",gcQuery);
2739                tJobErrorUpdate(uJob,"error 4d");
2740                goto CommonExit;
2741        }
2742
2743        //5-. Remove action script files if found
2744        //Business logic: Target container may have these files, but we need them only if we
2745        //'Failover' to this cloned VE. Also we defer to that action the setup of the
2746        //containers tProperty values needed for processing the action script templates:
2747        //cNetmask, cExtraNodeIP, cPrivateIPs, cService1, cService2, cVEID.mount and cVEID.umount, etc.
2748        sprintf(gcQuery,"ssh %3$s %1$s 'rm -f /etc/vz/conf/%2$u.umount /etc/vz/conf/%2$u.mount"
2749                                        " /etc/vz/conf/%2$u.start /etc/vz/conf/%2$u.stop'",
2750                                                cTargetNodeIPv4,uNewVeid,cSSHOptions);
2751        if(system(gcQuery))
2752        {
2753                logfileLine("CloneContainer",gcQuery);
2754                tJobErrorUpdate(uJob,"error 5");
2755                goto CommonExit;
2756        }
2757
2758        //6-.
2759        //This is optional since clones can be in stopped state and still be
2760        //kept in sync with source container. Also the failover can start (a fast operation)
2761        //with the extra advantage of being able to keep original IPs. Only needing an arping
2762        //to move the VIPs around the datacenter.
2763        if(uCloneStop==0)
2764        {
2765                sprintf(gcQuery,"ssh %s %s 'vzctl start %u'",cSSHOptions,cTargetNodeIPv4,uNewVeid);
2766                if(system(gcQuery))
2767                {
2768                        logfileLine("CloneContainer",gcQuery);
2769                        tJobErrorUpdate(uJob,"error 6");
2770                        goto CommonExit;
2771                }
2772                sprintf(gcQuery,"ssh %s %s 'vzctl set %u --onboot yes --save'",
2773                                                                cSSHOptions,cTargetNodeIPv4,uNewVeid);
2774                if(system(gcQuery))
2775                {
2776                        logfileLine("CloneContainer",gcQuery);
2777                        tJobErrorUpdate(uJob,"error 6b");
2778                        goto CommonExit;
2779                }
2780                SetContainerStatus(uNewVeid,uACTIVE);
2781        }
2782        else
2783        {
2784                sprintf(gcQuery,"ssh %s %s 'vzctl set %u --onboot no --save'",
2785                                                                cSSHOptions,cTargetNodeIPv4,uNewVeid);
2786                if(system(gcQuery))
2787                {
2788                        logfileLine("CloneContainer",gcQuery);
2789                        tJobErrorUpdate(uJob,"error 6c");
2790                        goto CommonExit;
2791                }
2792                SetContainerStatus(uNewVeid,uSTOPPED);
2793        }
2794
2795        //if(uDebug)
2796        //      return;
2797
2798        //7-. 8-. Everything ok
2799        if(uPrevStatus!=uINITSETUP)
2800                //Not an auto clone job is only possibility but this maybe a hack. TODO
2801                SetContainerStatus(uContainer,uPrevStatus);
2802        tJobDoneUpdate(uJob);
2803
2804        //9a-. local clean up
2805        if(!cSnapshotDir[0])
2806                sprintf(gcQuery,"rm /vz/dump/vzdump-%u.tgz",uContainer);
2807        else
2808                sprintf(gcQuery,"rm %s/vzdump-%u.tgz",cSnapshotDir,uContainer);
2809        if(system(gcQuery))
2810                logfileLine("CloneContainer",gcQuery);
2811       
2812        //9b-. remote clean up
2813        sprintf(gcQuery,"ssh %s %s 'rm /vz/dump/vzdump-%u.tgz'",cSSHOptions,cTargetNodeIPv4,uContainer);
2814        if(system(gcQuery))
2815                logfileLine("CloneContainer",gcQuery);
2816        sprintf(gcQuery,"ssh %s %s 'rm /vz/dump/vzdump-%u.tgz.md5sum'",cSSHOptions,cTargetNodeIPv4,uContainer);
2817        if(system(gcQuery))
2818                logfileLine("CloneContainer",gcQuery);
2819
2820//This goto MIGHT be ok.
2821CommonExit:
2822        //9c-. remove lock file
2823        //vzdump script should handle this?
2824        unlink("/var/run/vzdump.lock");
2825
2826        return;
2827
2828}//void CloneContainer(...)
2829
2830
2831//Required by libtemplate
2832void AppFunctions(FILE *fp,char *cFunction)
2833{
2834}//void AppFunctions(FILE *fp,char *cFunction)
2835
2836
2837//OpenVZ action scripts: Creates all OpenVZ action scripts will rename when time permits.
2838int CreateActionScripts(unsigned uContainer, unsigned uOverwrite)
2839{
2840        //Create VEID.mount and VEID.umount files if container so specifies via tProperty
2841        //      and everything needed is available: template and template vars from tProperty.
2842        MYSQL_RES *res2;
2843        MYSQL_ROW field2;
2844        FILE *fp;
2845        char cTemplateName[256]={""};//required
2846        char cFile[100]={""};//required
2847        char cVeID[32]={""};//required
2848        char cService1[256]={"80"};//default
2849        char cService2[256]={"443"};//default
2850        char cExtraNodeIP[256]={""};//required by some templates not all TODO fix this mess
2851        char cNetmask[256]={"255.255.255.0"};//default
2852        char cPrivateIPs[256]={"10.0.0.0/24"};//default
2853        char cIPv4[32]={""};
2854        struct stat statInfo;
2855
2856        sprintf(cVeID,"%u",uContainer);
2857        if(GetContainerMainIP(uContainer,cIPv4))
2858        {
2859                logfileLine("CreateActionScripts","Empty cIPv4");
2860                return(1);
2861        }
2862
2863        GetContainerProp(uContainer,"cExtraNodeIP",cExtraNodeIP);
2864        if(!cExtraNodeIP[0])
2865                //Allow backwards compatability
2866                GetContainerProp(uContainer,"cNodeIP",cExtraNodeIP);
2867
2868
2869        //First action script set
2870        GetContainerProp(uContainer,"cVEID.mount",cTemplateName);
2871        sprintf(cFile,"/etc/vz/conf/%u.mount",uContainer);
2872        //Do not overwrite existing mount files! Do that before if you really want to.
2873        //stat returns 0 if file exists
2874        if(cTemplateName[0] && (stat(cFile,&statInfo) || uOverwrite))
2875        {
2876                GetContainerProp(uContainer,"cNetmask",cNetmask);
2877                GetContainerProp(uContainer,"cPrivateIPs",cPrivateIPs);
2878                GetContainerProp(uContainer,"cService1",cService1);
2879                GetContainerProp(uContainer,"cService2",cService2);
2880
2881                if((fp=fopen(cFile,"w"))==NULL)
2882                {
2883                        logfileLine("CreateActionScripts-1",cFile);
2884                        return(1);
2885                }
2886
2887                TemplateSelect(cTemplateName);
2888                res2=mysql_store_result(&gMysql);
2889                if((field2=mysql_fetch_row(res2)))
2890                {
2891                        struct t_template template;
2892
2893                        template.cpName[0]="cExtraNodeIP";
2894                        template.cpValue[0]=cExtraNodeIP;
2895                                       
2896                        template.cpName[1]="cNetmask";
2897                        template.cpValue[1]=cNetmask;
2898                                       
2899                        template.cpName[2]="cPrivateIPs";
2900                        template.cpValue[2]=cPrivateIPs;
2901                                       
2902                        template.cpName[3]="cVeID";
2903                        template.cpValue[3]=cVeID;
2904
2905                        template.cpName[4]="cService1";
2906                        template.cpValue[4]=cService1;
2907                                       
2908                        template.cpName[5]="cService2";
2909                        template.cpValue[5]=cService2;
2910                                       
2911                        template.cpName[6]="cIPv4";
2912                        template.cpValue[6]=cIPv4;
2913                                       
2914                        template.cpName[7]="";
2915                        Template(field2[0],&template,fp);
2916                }
2917                mysql_free_result(res2);
2918                fclose(fp);
2919                chmod(cFile,S_IRUSR|S_IWUSR|S_IXUSR);
2920        }
2921
2922        cTemplateName[0]=0;
2923        GetContainerProp(uContainer,"cVEID.umount",cTemplateName);
2924        sprintf(cFile,"/etc/vz/conf/%u.umount",uContainer);
2925        if(cTemplateName[0] && (stat(cFile,&statInfo) || uOverwrite) )
2926        {
2927                if((fp=fopen(cFile,"w"))==NULL)
2928                {
2929                        logfileLine("CreateActionScripts-2",cFile);
2930                        return(1);
2931                }
2932
2933                TemplateSelect(cTemplateName);
2934                res2=mysql_store_result(&gMysql);
2935                if((field2=mysql_fetch_row(res2)))
2936                {
2937                        struct t_template template;
2938
2939                        template.cpName[0]="cExtraNodeIP";
2940                        template.cpValue[0]=cExtraNodeIP;
2941                                               
2942                        template.cpName[1]="cNetmask";
2943                        template.cpValue[1]=cNetmask;
2944                                       
2945                        template.cpName[2]="cPrivateIPs";
2946                        template.cpValue[2]=cPrivateIPs;
2947                                       
2948                        template.cpName[3]="cVeID";
2949                        template.cpValue[3]=cVeID;
2950
2951                        template.cpName[4]="cService1";
2952                        template.cpValue[4]=cService1;
2953                                       
2954                        template.cpName[5]="cService2";
2955                        template.cpValue[5]=cService2;
2956                                       
2957                        template.cpName[6]="cIPv4";
2958                        template.cpValue[6]=cIPv4;
2959                               
2960                        template.cpName[7]="";
2961                        Template(field2[0],&template,fp);
2962                }
2963                mysql_free_result(res2);
2964                fclose(fp);
2965                chmod(cFile,S_IRUSR|S_IWUSR|S_IXUSR);
2966        }
2967
2968        //Second action script set: Always a set of both start and stop? No!
2969        GetContainerProp(uContainer,"cVEID.start",cTemplateName);
2970        sprintf(cFile,"/etc/vz/conf/%u.start",uContainer);
2971        //Do not overwrite existing files! Do that before if you really want to.
2972        //stat returns 0 if file exists
2973        if(cTemplateName[0] && (stat(cFile,&statInfo) || uOverwrite))
2974        {
2975                if((fp=fopen(cFile,"w"))==NULL)
2976                {
2977                        logfileLine("CreateActionScripts-3",cFile);
2978                        return(1);
2979                }
2980
2981                TemplateSelect(cTemplateName);
2982                res2=mysql_store_result(&gMysql);
2983                if((field2=mysql_fetch_row(res2)))
2984                {
2985                        struct t_template template;
2986
2987                        template.cpName[0]="cIPv4";
2988                        template.cpValue[0]=cIPv4;
2989                                       
2990                        template.cpName[1]="";
2991                        Template(field2[0],&template,fp);
2992                }
2993                mysql_free_result(res2);
2994                fclose(fp);
2995                chmod(cFile,S_IRUSR|S_IWUSR|S_IXUSR);
2996        }
2997
2998        cTemplateName[0]=0;
2999        GetContainerProp(uContainer,"cVEID.stop",cTemplateName);
3000        sprintf(cFile,"/etc/vz/conf/%u.stop",uContainer);
3001        if(cTemplateName[0] && (stat(cFile,&statInfo) || uOverwrite) )
3002        {
3003                if((fp=fopen(cFile,"w"))==NULL)
3004                {
3005                        logfileLine("CreateActionScripts-4",cFile);
3006                        return(1);
3007                }
3008
3009                TemplateSelect(cTemplateName);
3010                res2=mysql_store_result(&gMysql);
3011                if((field2=mysql_fetch_row(res2)))
3012                {
3013                        struct t_template template;
3014
3015                        template.cpName[0]="cIPv4";
3016                        template.cpValue[0]=cIPv4;
3017                                       
3018                        template.cpName[1]="";
3019                        Template(field2[0],&template,fp);
3020
3021                }
3022                mysql_free_result(res2);
3023                fclose(fp);
3024                chmod(cFile,S_IRUSR|S_IWUSR|S_IXUSR);
3025        }
3026
3027        return(0);
3028
3029}//int CreateActionScripts()
3030
3031
3032//Make sure internal sabotage or db compromise does not allow exploit via system call injection
3033unsigned uNotValidSystemCallArg(char *cSSHOptions)
3034{
3035        int register i;
3036
3037        for(i=0;cSSHOptions[i];i++)
3038        {
3039                if(
3040                        cSSHOptions[i]==';' ||
3041                        cSSHOptions[i]=='&' ||
3042                        cSSHOptions[i]=='`' ||
3043                        cSSHOptions[i]=='\'' ||
3044                        cSSHOptions[i]=='"' ||
3045                        cSSHOptions[i]=='|' ||
3046                        cSSHOptions[i]=='*' ||
3047                        cSSHOptions[i]=='?' ||
3048                        cSSHOptions[i]=='~' ||
3049                        cSSHOptions[i]=='<' ||
3050                        cSSHOptions[i]=='>' ||
3051                        cSSHOptions[i]=='^' ||
3052                        cSSHOptions[i]=='(' ||
3053                        cSSHOptions[i]==')' ||
3054                        cSSHOptions[i]=='[' ||
3055                        cSSHOptions[i]==']' ||
3056                        cSSHOptions[i]=='{' ||
3057                        cSSHOptions[i]=='}' ||
3058                        cSSHOptions[i]=='$' ||
3059                        cSSHOptions[i]=='\\'
3060                                                )
3061                        {
3062                                return(1);
3063                        }
3064        }
3065
3066        return(0);
3067
3068}//unsigned uNotValidSystemCallArg(char *cSSHOptions)
3069
3070
3071void LocalImportTemplate(unsigned uJob,unsigned uDatacenter,const char *cJobData)
3072{
3073        MYSQL_RES *res;
3074        MYSQL_ROW field;
3075
3076        char cOSTemplateFilePath[55]={"/vz/template/cache/"};
3077        char cOSTemplateFile[200]={""};
3078        char cOSTemplateFileMd5sum[200]={""};
3079        struct stat statInfo;
3080        unsigned uOSTemplate=0;
3081
3082        //1-. Parse data and basic sanity checks
3083        sscanf(cJobData,"uOSTemplate=%u;",&uOSTemplate);
3084        if(!uOSTemplate)
3085        {
3086                logfileLine("LocalImportTemplate","Could not determine uOSTemplate");
3087                tJobErrorUpdate(uJob,"uOSTemplate=0");
3088                return;
3089        }
3090
3091        sprintf(gcQuery,"SELECT cLabel FROM tOSTemplate"
3092                        " WHERE uOSTemplate=%u",uOSTemplate);
3093        mysql_query(&gMysql,gcQuery);
3094        if(mysql_errno(&gMysql))
3095        {
3096                logfileLine("LocalImportTemplate",mysql_error(&gMysql));
3097                tJobErrorUpdate(uJob,"SELECT tOSTemplate.cLabel");
3098                return;
3099        }
3100        res=mysql_store_result(&gMysql);
3101        if((field=mysql_fetch_row(res)))
3102        {
3103                sprintf(cOSTemplateFile,"%.54s%.100s.tar.gz",cOSTemplateFilePath,field[0]);
3104        }
3105        else
3106        {
3107                mysql_free_result(res);
3108                logfileLine("LocalImportTemplate","Could not determine tOSTemplate.cLabel\n");
3109                tJobErrorUpdate(uJob,"tOSTemplate.cLabel");
3110                return;
3111        }
3112        mysql_free_result(res);
3113        if(uNotValidSystemCallArg(cOSTemplateFile))
3114        {
3115                logfileLine("LocalImportTemplate","security alert");
3116                tJobErrorUpdate(uJob,"failed sec alert!");
3117                return;
3118        }
3119
3120        //2-. stat file
3121        if(stat(cOSTemplateFile,&statInfo)!=0)
3122        {
3123                logfileLine("LocalImportTemplate",cOSTemplateFile);
3124                tJobErrorUpdate(uJob,"cOSTemplateFile stat");
3125                return;
3126        }
3127
3128        //3-. stat file.md5sum
3129        sprintf(cOSTemplateFileMd5sum,"%.154s.md5sum",cOSTemplateFile);
3130        if(stat(cOSTemplateFileMd5sum,&statInfo)!=0)
3131        {
3132                logfileLine("LocalImportTemplate",cOSTemplateFileMd5sum);
3133                tJobErrorUpdate(uJob,"cOSTemplateFilemd5sum stat");
3134                return;
3135        }
3136
3137        //4-. check md5sum
3138        sprintf(gcQuery,"/usr/bin/md5sum -c %s > /dev/null 2>&1",cOSTemplateFileMd5sum);
3139        if(system(gcQuery))
3140        {
3141                logfileLine("LocalImportTemplate","md5sum -c failed");
3142                tJobErrorUpdate(uJob,"md5sum -c failed!");
3143                return;
3144        }
3145
3146
3147        //5-. copy to all same datacenter nodes nicely (hopefully on GB 2nd NIC internal lan.)
3148        char cSCPOptions[256]={""};
3149        GetConfiguration("cSCPOptions",cSCPOptions,gfuDatacenter,gfuNode,0,0);//First try node specific
3150        if(!cSCPOptions[0])
3151        {
3152                GetConfiguration("cSCPOptions",cSCPOptions,gfuDatacenter,0,0,0);//Second try datacenter wide
3153                if(!cSCPOptions[0])
3154                        GetConfiguration("cSCPOptions",cSCPOptions,0,0,0,0);//Last try global
3155        }
3156        //Default for less conditions below
3157        if(!cSCPOptions[0] || uNotValidSystemCallArg(cSCPOptions))
3158                sprintf(cSCPOptions,"-P 22 -c arcfour");
3159        sprintf(gcQuery,"SELECT cLabel FROM tNode WHERE uDatacenter=%u AND uNode!=%u",gfuDatacenter,gfuNode);
3160        mysql_query(&gMysql,gcQuery);
3161        if(mysql_errno(&gMysql))
3162        {
3163                logfileLine("LocalImportTemplate",mysql_error(&gMysql));
3164                tJobErrorUpdate(uJob,"SELECT tNode.cLabel");
3165                return;
3166        }
3167        res=mysql_store_result(&gMysql);
3168        while((field=mysql_fetch_row(res)))
3169        {
3170                sprintf(gcQuery,"nice /usr/bin/scp %s %s %s:%s\n",cSCPOptions,cOSTemplateFile,field[0],cOSTemplateFile);
3171                if(system(gcQuery))
3172                {
3173                        mysql_free_result(res);
3174                        logfileLine("LocalImportTemplate",gcQuery);
3175                        tJobErrorUpdate(uJob,"scp-1 failed!");
3176                        return;
3177                }
3178                sprintf(gcQuery,"nice /usr/bin/scp %s %s %s:%s\n",cSCPOptions,cOSTemplateFileMd5sum,field[0],
3179                                                cOSTemplateFileMd5sum);
3180                if(system(gcQuery))
3181                {
3182                        mysql_free_result(res);
3183                        logfileLine("LocalImportTemplate",gcQuery);
3184                        tJobErrorUpdate(uJob,"scp-1 failed!");
3185                        return;
3186                }
3187        }
3188        mysql_free_result(res);
3189
3190        //Everything ok
3191        tJobDoneUpdate(uJob);
3192
3193}//void LocalImportTemplate(unsigned uJob,unsigned uContainer,const char *cJobData)
3194
3195
3196void LocalImportConfig(unsigned uJob,unsigned uDatacenter,const char *cJobData)
3197{
3198        MYSQL_RES *res;
3199        MYSQL_ROW field;
3200
3201        char cConfigFilePath[55]={"/etc/vz/conf/"};
3202        char cConfigFile[200]={""};
3203        struct stat statInfo;
3204        unsigned uConfig=0;
3205
3206        //1-. Parse data and basic sanity checks
3207        sscanf(cJobData,"uConfig=%u;",&uConfig);
3208        if(!uConfig)
3209        {
3210                logfileLine("LocalImportConfig","Could not determine uConfig");
3211                tJobErrorUpdate(uJob,"uConfig=0");
3212                return;
3213        }
3214
3215        sprintf(gcQuery,"SELECT cLabel FROM tConfig"
3216                        " WHERE uConfig=%u",uConfig);
3217        mysql_query(&gMysql,gcQuery);
3218        if(mysql_errno(&gMysql))
3219        {
3220                logfileLine("LocalImportConfig",mysql_error(&gMysql));
3221                tJobErrorUpdate(uJob,"SELECT tConfig.cLabel");
3222                return;
3223        }
3224        res=mysql_store_result(&gMysql);
3225        if((field=mysql_fetch_row(res)))
3226        {
3227                sprintf(cConfigFile,"%.54sve-%.100s.conf-sample",cConfigFilePath,field[0]);
3228        }
3229        else
3230        {
3231                mysql_free_result(res);
3232                logfileLine("LocalImportConfig","Could not determine tConfig.cLabel");
3233                tJobErrorUpdate(uJob,"tConfig.cLabel");
3234                return;
3235        }
3236        mysql_free_result(res);
3237        if(uNotValidSystemCallArg(cConfigFile))
3238        {
3239                logfileLine("LocalImportConfig","security alert");
3240                tJobErrorUpdate(uJob,"failed sec alert!");
3241                return;
3242        }
3243
3244        //2-. stat file
3245        if(stat(cConfigFile,&statInfo)!=0)
3246        {
3247                logfileLine("LocalImportConfig",cConfigFile);
3248                tJobErrorUpdate(uJob,"cConfigFile stat");
3249                return;
3250        }
3251
3252        //3-. copy to all same datacenter nodes nicely (hopefully on GB 2nd NIC internal lan.)
3253        char cSCPOptions[256]={""};
3254        GetConfiguration("cSCPOptions",cSCPOptions,gfuDatacenter,gfuNode,0,0);//First try node specific
3255        if(!cSCPOptions[0])
3256        {
3257                GetConfiguration("cSCPOptions",cSCPOptions,gfuDatacenter,0,0,0);//Second try datacenter wide
3258                if(!cSCPOptions[0])
3259                        GetConfiguration("cSCPOptions",cSCPOptions,0,0,0,0);//Last try global
3260        }
3261        //Default for less conditions below
3262        if(!cSCPOptions[0] || uNotValidSystemCallArg(cSCPOptions))
3263                sprintf(cSCPOptions,"-P 22 -c arcfour");
3264        sprintf(gcQuery,"SELECT cLabel FROM tNode WHERE uDatacenter=%u AND uNode!=%u",gfuDatacenter,gfuNode);
3265        mysql_query(&gMysql,gcQuery);
3266        if(mysql_errno(&gMysql))
3267        {
3268                logfileLine("LocalImportConfig",mysql_error(&gMysql));
3269                tJobErrorUpdate(uJob,"SELECT tNode.cLabel");
3270                return;
3271        }
3272        res=mysql_store_result(&gMysql);
3273        while((field=mysql_fetch_row(res)))
3274        {
3275                sprintf(gcQuery,"nice /usr/bin/scp %s %s %s:%s\n",cSCPOptions,cConfigFile,field[0],cConfigFile);
3276                //debug only
3277                //printf("%s\n",gcQuery);
3278                if(system(gcQuery))
3279                {
3280                        mysql_free_result(res);
3281                        logfileLine("LocalImportConfig",gcQuery);
3282                        tJobErrorUpdate(uJob,"scp failed!");
3283                        return;
3284                }
3285        }
3286        mysql_free_result(res);
3287
3288        //Everything ok
3289        tJobDoneUpdate(uJob);
3290
3291}//void LocalImportConfig(unsigned uJob,unsigned uContainer,const char *cJobData)
3292
3293
3294void FailoverTo(unsigned uJob,unsigned uContainer,const char *cJobData)
3295{
3296        //Notes
3297        //Initial rollback has no error checking, just best effort.
3298
3299        unsigned uRetVal=0;
3300        unsigned uStatus=0;//Real vzlist status
3301        unsigned uSourceContainer=0;
3302        char cIP[32]={""};
3303        char cLabel[32]={""};
3304        char cHostname[64]={""};
3305        //For rollback
3306        char cOrigIP[32]={""};
3307        char cOrigLabel[32]={""};
3308        char cOrigHostname[64]={""};
3309       
3310        //Get this cloned container source
3311        if(GetContainerSource(uContainer,&uSourceContainer))
3312        {
3313                logfileLine("FailoverTo","GetContainerSource()");
3314                tJobErrorUpdate(uJob,"No uSourceContainer");
3315                return;
3316        }
3317        //Now we quickly unset to avoid failed clon sync jobs
3318        if(SetContainerSource(uContainer,0))
3319        {
3320                logfileLine("FailoverTo","SetContainerSource()");
3321                tJobErrorUpdate(uJob,"SetContainerSource");
3322                return;
3323        }
3324        //Get data about container
3325        if(GetContainerNodeStatus(uContainer,&uStatus))
3326        {
3327                logfileLine("FailoverTo","GetContainerNodeStatus()");
3328                tJobErrorUpdate(uJob,"GetContainerNodeStatus");
3329
3330                //rollback
3331                SetContainerSource(uContainer,uSourceContainer);
3332                //level 1 done
3333                return;
3334        }
3335
3336        //1-.
3337        //If container is stopped must start. Since for unknown reasons
3338        //the container may already be running (vzctl returns 32 in the version we have at this time)
3339        //we do not consider that start error to be fatal for now.
3340        if(uStatus==uSTOPPED)   
3341        {
3342                sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u ",uContainer);
3343                if((uRetVal=system(gcQuery)))
3344                {
3345                        if(uRetVal==32)//32 is vzctl already running
3346                        {
3347                                logfileLine("FailoverTo",gcQuery);
3348                        }
3349                        else
3350                        {
3351                                logfileLine("FailoverTo",gcQuery);
3352                                tJobErrorUpdate(uJob,"start error");
3353
3354                                //rollback
3355                                SetContainerSource(uContainer,uSourceContainer);
3356                                //level 1 done
3357                                return;
3358                        }
3359                }
3360
3361                sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot yes --save",uContainer);
3362                if(system(gcQuery))
3363                {
3364                        logfileLine("FailoverTo",gcQuery);
3365                        tJobErrorUpdate(uJob,"set onboot failed");
3366
3367                        //rollback
3368                        SetContainerSource(uContainer,uSourceContainer);
3369                        //level 1 done
3370                        return;
3371                }
3372        }
3373        SetContainerStatus(uContainer,uACTIVE);//rollback item
3374
3375        //2-.
3376        //We remove all the previous IPs.
3377        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3378        if(system(gcQuery))
3379        {
3380                logfileLine("FailoverTo",gcQuery);
3381                tJobErrorUpdate(uJob,"ipdel all");
3382
3383                //rollback
3384                SetContainerSource(uContainer,uSourceContainer);
3385                //level 1 done
3386                if(uStatus==uSTOPPED)   
3387                {
3388                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u ",uContainer);
3389                        system(gcQuery);
3390                }
3391                SetContainerStatus(uContainer,uAWAITFAIL);
3392                //level 2 done
3393                return;
3394        }
3395
3396        //3-.
3397        //We add (from the source container!) (any other IPs?) first the main IP
3398        GetContainerMainIP(uContainer,cOrigIP);//rollback required
3399        if((uRetVal=GetContainerMainIP(uSourceContainer,cIP)))
3400        {
3401                logfileLine("FailoverTo","GetContainerMainIP()");
3402                tJobErrorUpdate(uJob,"GetContainerMainIP");
3403
3404                //rollback
3405                SetContainerSource(uContainer,uSourceContainer);
3406                //level 1 done
3407                if(uStatus==uSTOPPED)   
3408                {
3409                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u ",uContainer);
3410                        system(gcQuery);
3411                }
3412                SetContainerStatus(uContainer,uAWAITFAIL);
3413                //level 2 done
3414                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3415                system(gcQuery);
3416                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3417                system(gcQuery);
3418                //level 3 done
3419                return;
3420        }
3421        if(uNotValidSystemCallArg(cIP))
3422        {
3423                logfileLine("FailoverTo","security alert cIP");
3424                tJobErrorUpdate(uJob,"cIP security");
3425
3426                //rollback
3427                SetContainerSource(uContainer,uSourceContainer);
3428                //level 1 done
3429                if(uStatus==uSTOPPED)   
3430                {
3431                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u ",uContainer);
3432                        system(gcQuery);
3433                }
3434                SetContainerStatus(uContainer,uAWAITFAIL);
3435                //level 2 done
3436                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3437                system(gcQuery);
3438                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3439                system(gcQuery);
3440                //level 3 done
3441        }
3442        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cIP);
3443        if(system(gcQuery))
3444        {
3445                logfileLine("FailoverTo",gcQuery);
3446                tJobErrorUpdate(uJob,"ipadd cIP");
3447
3448                //rollback
3449                SetContainerSource(uContainer,uSourceContainer);
3450                //level 1 done
3451                if(uStatus==uSTOPPED)   
3452                {
3453                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u ",uContainer);
3454                        system(gcQuery);
3455                }
3456                SetContainerStatus(uContainer,uAWAITFAIL);
3457                //level 2 done
3458                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3459                system(gcQuery);
3460                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3461                system(gcQuery);
3462                //level 3 done
3463        }
3464        //3b-.
3465        //No we can update the db for the new production container
3466        if(SetContainerIP(uContainer,cIP))
3467        {
3468                logfileLine("FailoverTo","SetContainerIP()");
3469                tJobErrorUpdate(uJob,"SetContainerIP");
3470
3471                //rollback
3472                SetContainerSource(uContainer,uSourceContainer);
3473                //level 1 done
3474                if(uStatus==uSTOPPED)   
3475                {
3476                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u ",uContainer);
3477                        system(gcQuery);
3478                        SetContainerStatus(uContainer,uAWAITFAIL);
3479                }
3480                SetContainerStatus(uContainer,uAWAITFAIL);
3481                //level 2 done
3482                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3483                system(gcQuery);
3484                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3485                system(gcQuery);
3486                //level 3 done
3487        }
3488        //3c-.
3489        //Change the names to the source ones
3490        if(GetContainerNames(uSourceContainer,cHostname,cLabel))
3491        {
3492                logfileLine("FailoverTo","GetContainerNames()");
3493                tJobErrorUpdate(uJob,"GetContainerNames");
3494
3495                //rollback
3496                SetContainerSource(uContainer,uSourceContainer);
3497                //level 1 done
3498                if(uStatus==uSTOPPED)   
3499                {
3500                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u ",uContainer);
3501                        system(gcQuery);
3502                }
3503                SetContainerStatus(uContainer,uAWAITFAIL);
3504                //level 2 done
3505                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3506                system(gcQuery);
3507                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3508                system(gcQuery);
3509                //level 3 done
3510                SetContainerIP(uContainer,cOrigIP);
3511                //level 4 done
3512                return;
3513        }
3514        //This is needed until the sister job runs, due to unique index on cLabel,uDatacenter
3515        char cVEIDLabel[32];
3516        sprintf(cVEIDLabel,"%.28s.fo",cLabel);
3517        if(SetContainerHostname(uSourceContainer,cHostname,cVEIDLabel) ||
3518                SetContainerHostname(uContainer,cHostname,cLabel))
3519        {
3520                logfileLine("FailoverTo","SetContainerHostname()");
3521                tJobErrorUpdate(uJob,"SetContainerHostname");
3522
3523                //rollback
3524                SetContainerSource(uContainer,uSourceContainer);
3525                //level 1 done
3526                if(uStatus==uSTOPPED)   
3527                {
3528                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u ",uContainer);
3529                        system(gcQuery);
3530                }
3531                SetContainerStatus(uContainer,uAWAITFAIL);
3532                //level 2 done
3533                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3534                system(gcQuery);
3535                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3536                system(gcQuery);
3537                //level 3 done
3538                SetContainerIP(uContainer,cOrigIP);
3539                //level 4 done
3540                return;
3541        }
3542        else
3543        {
3544                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --hostname %s --name %s --save",
3545                                uContainer,cHostname,cLabel);
3546                if(system(gcQuery))
3547                {
3548                        logfileLine("FailoverTo",gcQuery);
3549                        tJobErrorUpdate(uJob,"vzctl set hostname");
3550
3551                        //rollback
3552                        SetContainerSource(uContainer,uSourceContainer);
3553                        //level 1 done
3554                        if(uStatus==uSTOPPED)   
3555                        {
3556                                sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u ",uContainer);
3557                                system(gcQuery);
3558                        }
3559                        SetContainerStatus(uContainer,uAWAITFAIL);
3560                        //level 2 done
3561                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3562                        system(gcQuery);
3563                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3564                        system(gcQuery);
3565                        //level 3 done
3566                        SetContainerIP(uContainer,cOrigIP);
3567                        //level 4 done
3568                        return;
3569                }
3570        }
3571
3572        //4-.
3573        //When we clone we purposefully remove any action scripts
3574        //Here we must add them.
3575        //Trouble is that these scripts must allow for failover.
3576        //for example if strange firewall rules or IP ranges are used
3577        //these scripts will not be portable --even in the same datacenter!
3578        //It follows that all hardware nodes of the same type (VENET xor VETH)
3579        //must have the same basic firewall and device settings. HN device differences
3580        //can be added later via tNode properties.
3581        if(CreateActionScripts(uContainer,1))
3582        {
3583                logfileLine("FailoverTo","CreateActionScripts(x,1)");
3584                tJobErrorUpdate(uJob,"CreateActionScripts(x,1)");
3585
3586                //rollback
3587                SetContainerSource(uContainer,uSourceContainer);
3588                //level 1 done
3589                if(uStatus==uSTOPPED)   
3590                {
3591                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u ",uContainer);
3592                        system(gcQuery);
3593                }
3594                SetContainerStatus(uContainer,uAWAITFAIL);
3595                //level 2 done
3596                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3597                system(gcQuery);
3598                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3599                system(gcQuery);
3600                //level 3 done
3601                SetContainerIP(uContainer,cOrigIP);
3602                //level 4 done
3603                GetContainerNames(uContainer,cOrigHostname,cOrigLabel);
3604                SetContainerHostname(uContainer,cOrigHostname,cOrigLabel);
3605                //level 5 done
3606                return;
3607        }
3608
3609
3610        //Everything ok
3611        tJobDoneUpdate(uJob);
3612
3613}//void FailoverTo()
3614
3615
3616void FailoverFrom(unsigned uJob,unsigned uContainer,const char *cJobData)
3617{
3618        //These are the clone container's
3619        unsigned uSource=0;
3620        unsigned uFailToJob=0;
3621        unsigned uStatus=0;
3622        unsigned uIPv4=0;
3623        char cIP[32]={""};
3624        char cLabel[32]={""};
3625        char cHostname[64]={""};
3626        char *cp,*cp2;
3627        //For rollback
3628        char cOrigIP[32]={""};
3629        char cOrigLabel[32]={""};
3630        char cOrigHostname[64]={""};
3631
3632        unsigned uDebug=0;
3633
3634        if(uDebug)
3635                printf("DEBUG FailoverFrom() uJob=%u uContainer=%u\n",uJob,uContainer);
3636
3637
3638        //0-. uCloneContainer not used yet.
3639        if((cp=strstr(cJobData,"uIPv4=")))
3640        {
3641                sscanf(cp+6,"%u",&uIPv4);
3642        }
3643        if(!uIPv4)
3644        {
3645                logfileLine("FailoverFrom","no uIPv4");
3646                tJobErrorUpdate(uJob,"no uIPv4");
3647                return;
3648        }
3649
3650        if((cp=strstr(cJobData,"cLabel=")))
3651        {
3652                if((cp2=strchr(cp+7,';')))
3653                {
3654                        *cp2=0;
3655                        sprintf(cLabel,"%.31s",cp+7);
3656                        *cp2=';';
3657                }
3658               
3659        }
3660        if(!cLabel[0])
3661        {
3662                logfileLine("FailoverFrom","no cLabel");
3663                tJobErrorUpdate(uJob,"no cLabel");
3664                return;
3665        }
3666
3667        if((cp=strstr(cJobData,"cHostname=")))
3668        {
3669                if((cp2=strchr(cp+10,';')))
3670                {
3671                        *cp2=0;
3672                        sprintf(cHostname,"%.63s",cp+10);
3673                        *cp2=';';
3674                }
3675               
3676        }
3677        if(!cHostname[0])
3678        {
3679                logfileLine("FailoverFrom","no cHostname");
3680                tJobErrorUpdate(uJob,"no cHostname");
3681                return;
3682        }
3683
3684        if((cp=strstr(cJobData,"uSource=")))
3685        {
3686                sscanf(cp+8,"%u",&uSource);
3687        }
3688        if(!uSource)
3689        {
3690                logfileLine("FailoverFrom","no uSource");
3691                tJobErrorUpdate(uJob,"no uSource");
3692                return;
3693        }
3694
3695        if((cp=strstr(cJobData,"uStatus=")))
3696        {
3697                sscanf(cp+8,"%u",&uStatus);
3698        }
3699        if(!uStatus)
3700        {
3701                logfileLine("FailoverFrom","no uStatus");
3702                tJobErrorUpdate(uJob,"no uStatus");
3703                return;
3704        }
3705
3706        if((cp=strstr(cJobData,"uFailToJob=")))
3707        {
3708                sscanf(cp+11,"%u",&uFailToJob);
3709        }
3710        if(!uFailToJob)
3711        {
3712                logfileLine("FailoverFrom","no uFailToJob");
3713                tJobErrorUpdate(uJob,"no uFailToJob");
3714                return;
3715        }
3716
3717        //Does this job have to run AFTER FailoverTo()? yes!
3718        //So if it hasn't we contine to wait.
3719        if(!FailToJobDone(uFailToJob))
3720        {
3721                char cuFailToJob[64];
3722                sprintf(cuFailToJob,"uFailToJob=%u",uFailToJob);
3723                logfileLine("FailoverFrom",cuFailToJob);
3724                tJobWaitingUpdate(uJob);
3725                return;
3726        }
3727
3728
3729        if(uDebug)
3730                printf("DEBUG FailoverFrom() cJobData: uIPv4=%u cLabel=%s cHostname=%s uSource=%u\n",
3731                                uIPv4,cLabel,cHostname,uSource);
3732
3733        //1-.
3734        GetContainerMainIP(uContainer,cOrigIP);//rollback required
3735        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3736        if(system(gcQuery))
3737        {
3738                logfileLine("FailoverFrom",gcQuery);
3739                tJobErrorUpdate(uJob,"ipdel all");
3740                return;
3741        }
3742
3743
3744        //2-.
3745        //If the clone was running we should also keep the new clone running also
3746        //If not we keep in some state that is assumed to be uACTIVE from the way the
3747        //backend creates these jobs.
3748        if(uStatus==uSTOPPED)
3749        {
3750                sprintf(gcQuery,"/usr/sbin/vzctl --verbose stop %u",uContainer);
3751                if(system(gcQuery))
3752                {
3753                        logfileLine("FailoverFrom",gcQuery);
3754                        tJobErrorUpdate(uJob,"vzctl stop");
3755
3756                        //rollback
3757                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3758                        system(gcQuery);
3759                        //level 1 done
3760                        return;
3761                }
3762
3763                //If we stop we keep stopped on reboot.
3764                sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot no --save",uContainer);
3765                system(gcQuery);
3766
3767                SetContainerStatus(uContainer,uSTOPPED);
3768        }
3769        else
3770        {
3771                SetContainerStatus(uContainer,uACTIVE);
3772        }
3773
3774        //Everything ok as far as failover goes, now we do housekeeping.
3775
3776        //3-.
3777        //Change the names to the cloned ones
3778        GetContainerNames(uContainer,cOrigHostname,cOrigLabel);
3779        if(SetContainerHostname(uContainer,cHostname,cLabel))
3780        {
3781                logfileLine("FailoverFrom","SetContainerHostname()");
3782                tJobErrorUpdate(uJob,"SetContainerHostname");
3783
3784                //rollback
3785                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3786                system(gcQuery);
3787                //level 1 done
3788                SetContainerStatus(uContainer,uAWAITFAIL);
3789                if(uStatus==uSTOPPED)
3790                {
3791                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
3792                        system(gcQuery);
3793                        sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot yes --save",uContainer);
3794                        system(gcQuery);
3795                }
3796                //level 2 done
3797                return;
3798        }
3799        else
3800        {
3801                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --hostname %s --name %s --save",
3802                                uContainer,cHostname,cLabel);
3803                if(system(gcQuery))
3804                {
3805                        logfileLine("FailoverFrom",gcQuery);
3806                        tJobErrorUpdate(uJob,"vzctl set hostname");
3807
3808                        //rollback
3809                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3810                        system(gcQuery);
3811                        //level 1 done
3812                        SetContainerStatus(uContainer,uAWAITFAIL);
3813                        if(uStatus==uSTOPPED)
3814                        {
3815                                sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
3816                                system(gcQuery);
3817                                sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot yes --save",uContainer);
3818                                system(gcQuery);
3819                        }
3820                        //level 2 done
3821                        SetContainerHostname(uContainer,cOrigHostname,cOrigLabel);
3822                        //level 3 done
3823                        return;
3824                }
3825        }
3826
3827
3828        //4-.
3829        //Change IP over to the one the clone used to have
3830        GetIPFromtIP(uIPv4,cIP);
3831        if(SetContainerIP(uContainer,cIP))
3832        {
3833                logfileLine("FailoverFrom","SetContainerIP()");
3834                tJobErrorUpdate(uJob,"SetContainerIP");
3835
3836                //rollback
3837                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3838                system(gcQuery);
3839                //level 1 done
3840                SetContainerStatus(uContainer,uAWAITFAIL);
3841                if(uStatus==uSTOPPED)
3842                {
3843                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
3844                        system(gcQuery);
3845                        sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot yes --save",uContainer);
3846                        system(gcQuery);
3847                }
3848                //level 2 done
3849                SetContainerHostname(uContainer,cOrigHostname,cOrigLabel);
3850                //level 3 done
3851                return;
3852        }
3853        else
3854        {
3855                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cIP);
3856                if(system(gcQuery))
3857                {
3858                        logfileLine("FailoverFrom",gcQuery);
3859                        tJobErrorUpdate(uJob,"ipadd");
3860
3861                        //rollback
3862                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3863                        system(gcQuery);
3864                        //level 1 done
3865                        SetContainerStatus(uContainer,uAWAITFAIL);
3866                        if(uStatus==uSTOPPED)
3867                        {
3868                                sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
3869                                system(gcQuery);
3870                                sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot yes --save",uContainer);
3871                                system(gcQuery);
3872                        }
3873                        //level 2 done
3874                        SetContainerHostname(uContainer,cOrigHostname,cOrigLabel);
3875                        //level 3 done
3876                        SetContainerIP(uContainer,cOrigIP);
3877                        //level 4 done
3878                        return;
3879
3880                }
3881        }
3882
3883
3884        //5-. Remove any action script files.
3885        sprintf(gcQuery,"rm -f /etc/vz/conf/%1$u.umount /etc/vz/conf/%1$u.mount"
3886                                " /etc/vz/conf/%1$u.start /etc/vz/conf/%1$u.stop"
3887                                        ,uContainer);
3888        if(system(gcQuery))
3889        {
3890                logfileLine("FailoverFrom",gcQuery);
3891                tJobErrorUpdate(uJob,"rm action scripts");
3892
3893                //rollback
3894                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3895                system(gcQuery);
3896                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3897                system(gcQuery);
3898                //level 1 done
3899                SetContainerStatus(uContainer,uAWAITFAIL);
3900                if(uStatus==uSTOPPED)
3901                {
3902                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
3903                        system(gcQuery);
3904                        sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot yes --save",uContainer);
3905                        system(gcQuery);
3906                }
3907                //level 2 done
3908                SetContainerHostname(uContainer,cOrigHostname,cOrigLabel);
3909                //level 3 done
3910                SetContainerIP(uContainer,cOrigIP);
3911                //level 4 done
3912                //level 5 done see expanded level 1 done
3913                return;
3914        }
3915
3916        //This is relatively safe since a cuSyncPeriod non 0 has to exist for this container.
3917        //The issues identified so far are:
3918        //A-. What if the new production container does not work and the old source has
3919        //      important data that could fix this problem quickly?
3920        if(SetContainerSource(uContainer,uSource))
3921        {
3922                logfileLine("FailoverFrom","SetContainerSource()");
3923                tJobErrorUpdate(uJob,"SetContainerSource");
3924
3925                //rollback
3926                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel all --save",uContainer);
3927                system(gcQuery);
3928                sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cOrigIP);
3929                system(gcQuery);
3930                //level 1 done
3931                SetContainerStatus(uContainer,uAWAITFAIL);
3932                if(uStatus==uSTOPPED)
3933                {
3934                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose start %u",uContainer);
3935                        system(gcQuery);
3936                        sprintf(gcQuery,"/usr/sbin/vzctl set %u --onboot yes --save",uContainer);
3937                        system(gcQuery);
3938                }
3939                //level 2 done
3940                SetContainerHostname(uContainer,cOrigHostname,cOrigLabel);
3941                //level 3 done
3942                SetContainerIP(uContainer,cOrigIP);
3943                //level 4 done
3944                //level 5 done see expanded level 1
3945                return;
3946        }
3947        //To play it safe for now we remove any cuSyncPeriod property.
3948        //This means that once the node is operational and we want to resume
3949        //clone sync operations we need to copy the source container cuSyncPeriod
3950        //to the clone container for sync operation to resume.
3951        SetContainerProperty(uContainer,"cuSyncPeriod","0");
3952
3953        //Everything ok
3954        tJobDoneUpdate(uJob);
3955
3956}//void FailoverFrom()
3957
3958
3959unsigned GetContainerStatus(const unsigned uContainer, unsigned *uStatus)
3960{
3961        MYSQL_RES *res;
3962        MYSQL_ROW field;
3963
3964        if(uContainer==0) return(1);
3965
3966        sprintf(gcQuery,"SELECT uStatus FROM tContainer WHERE uContainer=%u",uContainer);
3967        mysql_query(&gMysql,gcQuery);
3968        if(mysql_errno(&gMysql))
3969        {
3970                logfileLine("GetContainerStatus",mysql_error(&gMysql));
3971                return(2);
3972        }
3973        res=mysql_store_result(&gMysql);
3974        if((field=mysql_fetch_row(res)))
3975        {
3976                sscanf(field[0],"%u",uStatus);
3977                if(!uStatus) return(3);
3978        }
3979        else
3980        {
3981                mysql_free_result(res);
3982                return(4);
3983        }
3984        mysql_free_result(res);
3985        return(0);
3986
3987}//unsigned GetContainerStatus()
3988
3989
3990unsigned GetContainerMainIP(const unsigned uContainer,char *cIP)
3991{
3992        MYSQL_RES *res;
3993        MYSQL_ROW field;
3994
3995        if(uContainer==0) return(1);
3996
3997        sprintf(gcQuery,"SELECT tIP.cLabel FROM tContainer,tIP WHERE tIP.uIP=tContainer.uIPv4 AND"
3998                                " tContainer.uContainer=%u",uContainer);
3999        mysql_query(&gMysql,gcQuery);
4000        if(mysql_errno(&gMysql))
4001        {
4002                logfileLine("GetContainerMainIP",mysql_error(&gMysql));
4003                return(2);
4004        }
4005        res=mysql_store_result(&gMysql);
4006        if((field=mysql_fetch_row(res)))
4007        {
4008                sprintf(cIP,"%.31s",field[0]);
4009                if(!cIP[0]) return(3);
4010        }
4011        else
4012        {
4013                mysql_free_result(res);
4014                return(4);
4015        }
4016        mysql_free_result(res);
4017        return(0);
4018
4019}//void GetContainerMainIP()
4020
4021
4022unsigned GetContainerSource(const unsigned uContainer, unsigned *uSource)
4023{
4024        MYSQL_RES *res;
4025        MYSQL_ROW field;
4026
4027        if(uContainer==0) return(1);
4028
4029        sprintf(gcQuery,"SELECT uSource FROM tContainer WHERE uContainer=%u",uContainer);
4030        mysql_query(&gMysql,gcQuery);
4031        if(mysql_errno(&gMysql))
4032        {
4033                logfileLine("GetContainerSource",mysql_error(&gMysql));
4034                return(2);
4035        }
4036        res=mysql_store_result(&gMysql);
4037        if((field=mysql_fetch_row(res)))
4038        {
4039                sscanf(field[0],"%u",uSource);
4040                if(!uSource) return(3);
4041        }
4042        else
4043        {
4044                mysql_free_result(res);
4045                return(4);
4046        }
4047        mysql_free_result(res);
4048        return(0);
4049
4050}//void GetContainerSource()
4051
4052
4053unsigned SetContainerIP(const unsigned uContainer,char *cIP)
4054{
4055        if(uContainer==0 || cIP[0]==0)
4056                return(1);
4057
4058        sprintf(gcQuery,"UPDATE tContainer SET uIPv4=(SELECT uIP FROM tIP WHERE cLabel='%s' LIMIT 1) WHERE"
4059                                " uContainer=%u",cIP,uContainer);
4060        mysql_query(&gMysql,gcQuery);
4061        if(mysql_errno(&gMysql))
4062        {
4063                logfileLine("SetContainerIP",mysql_error(&gMysql));
4064                return(2);
4065        }
4066        return(0);
4067
4068}//void SetContainerIP()
4069
4070
4071unsigned SetContainerSource(const unsigned uContainer,const unsigned uSource)
4072{
4073        if(uContainer==0) return(1);
4074
4075        sprintf(gcQuery,"UPDATE tContainer SET uSource=%u WHERE uContainer=%u",uSource,uContainer);
4076        mysql_query(&gMysql,gcQuery);
4077        if(mysql_errno(&gMysql))
4078        {
4079                logfileLine("SetContainerSource",mysql_error(&gMysql));
4080                return(2);
4081        }
4082        return(0);
4083
4084}//void SetContainerSource()
4085
4086
4087void GetIPFromtIP(const unsigned uIPv4,char *cIP)
4088{
4089        MYSQL_RES *res;
4090        MYSQL_ROW field;
4091
4092        if(uIPv4==0)
4093                return;
4094
4095        sprintf(gcQuery,"SELECT cLabel FROM tIP WHERE uIP=%u",uIPv4);
4096        mysql_query(&gMysql,gcQuery);
4097        if(mysql_errno(&gMysql))
4098        {
4099                logfileLine("GetIPFromtIP",mysql_error(&gMysql));
4100        }
4101        res=mysql_store_result(&gMysql);
4102        if((field=mysql_fetch_row(res)))
4103        {
4104                sprintf(cIP,"%.31s",field[0]);
4105        }
4106        mysql_free_result(res);
4107
4108}//void GetIPFromtIP(const unsigned uIPv4,char *cIP)
4109
4110
4111unsigned SetContainerHostname(const unsigned uContainer,
4112                        const char *cHostname,const char *cLabel)
4113{
4114        if(uContainer==0) return(1);
4115
4116        sprintf(gcQuery,"UPDATE tContainer SET cHostname='%s',cLabel='%s' WHERE uContainer=%u",
4117                cHostname,cLabel,uContainer);
4118        mysql_query(&gMysql,gcQuery);
4119        if(mysql_errno(&gMysql))
4120        {
4121                logfileLine("SetContainerHostname",mysql_error(&gMysql));
4122                return(2);
4123        }
4124        return(0);
4125
4126}//void SetContainerHostname()
4127
4128
4129unsigned GetContainerNames(const unsigned uContainer,char *cHostname,char *cLabel)
4130{
4131        MYSQL_RES *res;
4132        MYSQL_ROW field;
4133
4134        if(uContainer==0) return(1);
4135
4136        sprintf(gcQuery,"SELECT cLabel,cHostname FROM tContainer WHERE uContainer=%u",uContainer);
4137        mysql_query(&gMysql,gcQuery);
4138        if(mysql_errno(&gMysql))
4139        {
4140                logfileLine("GetContainerNames",mysql_error(&gMysql));
4141        }
4142        res=mysql_store_result(&gMysql);
4143        if((field=mysql_fetch_row(res)))
4144        {
4145                sprintf(cLabel,"%.31s",field[0]);
4146                sprintf(cHostname,"%.63s",field[1]);
4147                if(!cLabel[0]) return(2);
4148                if(!cHostname[0]) return(3);
4149        }
4150        else
4151        {
4152                mysql_free_result(res);
4153                return(4);
4154        }
4155        mysql_free_result(res);
4156
4157        return(0);
4158
4159}//unsigned GetContainerNames()
4160
4161
4162unsigned GetContainerNodeStatus(const unsigned uContainer, unsigned *uStatus)
4163{
4164        //Notes
4165        //This is the real running or stopped status on the node this runs on
4166        //for the given container.
4167
4168        //first check
4169        sprintf(gcQuery,"/usr/sbin/vzlist --no-header %u > /dev/null 2>&1",uContainer);
4170        if(system(gcQuery))
4171                return(1);
4172
4173        //now get status
4174        sprintf(gcQuery,"/usr/sbin/vzlist --no-header %u | /bin/grep running > /dev/null 2>&1",
4175                                                                                uContainer);
4176        if(system(gcQuery))
4177                *uStatus=uSTOPPED;
4178        else
4179                *uStatus=uACTIVE;
4180
4181        return(0);
4182
4183}//void GetContainerNodeStatus()
4184
4185
4186unsigned SetContainerProperty(const unsigned uContainer,const char *cPropertyName,const  char *cPropertyValue)
4187{
4188        MYSQL_RES *res;
4189        MYSQL_ROW field;
4190
4191        if(uContainer==0 || cPropertyName[0]==0 || cPropertyValue[0]==0)
4192                return(1);
4193
4194        sprintf(gcQuery,"SELECT uProperty FROM tProperty WHERE uType=3 AND uKey=%u AND cName='%s'",
4195                                        uContainer,cPropertyName);
4196        mysql_query(&gMysql,gcQuery);
4197        if(mysql_errno(&gMysql))
4198        {
4199                logfileLine("SetContainerProperty",mysql_error(&gMysql));
4200                return(2);
4201        }
4202        res=mysql_store_result(&gMysql);
4203        if((field=mysql_fetch_row(res)))
4204        {
4205                sprintf(gcQuery,"UPDATE tProperty SET cValue='%s' WHERE uProperty=%s",
4206                                        cPropertyValue,field[0]);
4207                mysql_query(&gMysql,gcQuery);
4208                if(mysql_errno(&gMysql))
4209                {
4210                        mysql_free_result(res);
4211                        logfileLine("SetContainerProperty",mysql_error(&gMysql));
4212                        return(3);
4213                }
4214        }
4215        else
4216        {
4217                sprintf(gcQuery,"INSERT INTO tProperty SET cName='%s',cValue='%s',uType=3,uKey=%u,"
4218                                "uOwner=(SELECT uOwner FROM tContainer WHERE uContainer=%u),"
4219                                "uCreatedBy=1,uCreatedDate=UNIX_TIMESTAMP(NOW())",
4220                                        cPropertyName,cPropertyValue,uContainer,uContainer);
4221                mysql_query(&gMysql,gcQuery);
4222                if(mysql_errno(&gMysql))
4223                {
4224                        mysql_free_result(res);
4225                        logfileLine("SetContainerProperty",mysql_error(&gMysql));
4226                        return(4);
4227                }
4228        }
4229        mysql_free_result(res);
4230
4231        return(0);
4232
4233}//void SetContainerProperty()
4234
4235
4236unsigned FailToJobDone(unsigned uJob)
4237{
4238        MYSQL_RES *res;
4239
4240        if(uJob==0)
4241        {
4242                logfileLine("FailToJobDone","uJob==0");
4243                return(0);
4244        }
4245
4246        sprintf(gcQuery,"SELECT uJob FROM tJob WHERE uJob=%u AND uJobStatus=3",uJob);
4247        mysql_query(&gMysql,gcQuery);
4248        if(mysql_errno(&gMysql))
4249        {
4250                logfileLine("FailToJobDone",mysql_error(&gMysql));
4251                return(0);
4252        }
4253        res=mysql_store_result(&gMysql);
4254        if(mysql_num_rows(res)>0)
4255        {
4256                mysql_free_result(res);
4257                return(1);
4258        }
4259        mysql_free_result(res);
4260        return(0);
4261
4262}//unsigned FailToJobDone(unsigned uContainer)
4263
4264
4265void GetNodeProp(const unsigned uNode,const char *cName,char *cValue)
4266{
4267        MYSQL_RES *res;
4268        MYSQL_ROW field;
4269
4270        if(uNode==0) return;
4271
4272        //2 is node
4273        sprintf(gcQuery,"SELECT cValue FROM tProperty WHERE uKey=%u AND uType=2 AND cName='%s'",
4274                                uNode,cName);
4275        mysql_query(&gMysql,gcQuery);
4276        if(mysql_errno(&gMysql))
4277        {
4278                if(gLfp!=NULL)
4279                {
4280                        logfileLine("GetNodeProp",mysql_error(&gMysql));
4281                        exit(2);
4282                }
4283                else
4284                {
4285                        htmlPlainTextError(mysql_error(&gMysql));
4286                }
4287        }
4288        res=mysql_store_result(&gMysql);
4289        if((field=mysql_fetch_row(res)))
4290        {
4291                char *cp;
4292                if((cp=strchr(field[0],'\n')))
4293                        *cp=0;
4294                sprintf(cValue,"%.255s",field[0]);
4295        }
4296        mysql_free_result(res);
4297
4298}//void GetNodeProp()
4299
4300
4301void GetDatacenterProp(const unsigned uDatacenter,const char *cName,char *cValue)
4302{
4303        MYSQL_RES *res;
4304        MYSQL_ROW field;
4305
4306        if(uDatacenter==0) return;
4307
4308        //1 is datacenter
4309        sprintf(gcQuery,"SELECT cValue FROM tProperty WHERE uKey=%u AND uType=1 AND cName='%s'",
4310                                uDatacenter,cName);
4311        mysql_query(&gMysql,gcQuery);
4312        if(mysql_errno(&gMysql))
4313        {
4314                if(gLfp!=NULL)
4315                {
4316                        logfileLine("GetDatacenterProp",mysql_error(&gMysql));
4317                        exit(2);
4318                }
4319                else
4320                {
4321                        htmlPlainTextError(mysql_error(&gMysql));
4322                }
4323        }
4324        res=mysql_store_result(&gMysql);
4325        if((field=mysql_fetch_row(res)))
4326        {
4327                char *cp;
4328                if((cp=strchr(field[0],'\n')))
4329                        *cp=0;
4330                sprintf(cValue,"%.255s",field[0]);
4331        }
4332        mysql_free_result(res);
4333
4334}//void GetDatacenterProp()
4335
4336
4337void logfileLine(const char *cFunction,const char *cLogline)
4338{
4339        time_t luClock;
4340        char cTime[32];
4341        pid_t pidThis;
4342        const struct tm *tmTime;
4343
4344        pidThis=getpid();
4345
4346        time(&luClock);
4347        tmTime=localtime(&luClock);
4348        strftime(cTime,31,"%b %d %T",tmTime);
4349
4350        fprintf(gLfp,"%s jobqueue.%s[%u]: %s\n",cTime,cFunction,pidThis,cLogline);
4351        fflush(gLfp);
4352
4353}//void logfileLine(char *cLogline)
4354
4355
4356unsigned ProcessCloneSyncJob(unsigned uNode,unsigned uContainer,unsigned uCloneContainer)
4357{
4358        MYSQL_RES *res;
4359        MYSQL_ROW field;
4360        unsigned uPeriod=0;
4361
4362        if(guDebug)
4363        {
4364                sprintf(gcQuery,"Start uContainer=%u,uCloneContainer=%u",uContainer,uCloneContainer);
4365                logfileLine("ProcessCloneSyncJob",gcQuery);
4366        }
4367
4368        //After failover cuSyncPeriod is 0 for clone (remote) container.
4369        //This allows for safekeeping of potentially useful data.
4370        //mainfunc RecoverMode recover cuSyncPeriod from source to clone.
4371        sprintf(gcQuery,"SELECT cValue FROM tProperty WHERE uKey=%u AND uType=3 AND cName='cuSyncPeriod'",
4372                                        uCloneContainer);
4373        mysql_query(&gMysql,gcQuery);
4374        if(mysql_errno(&gMysql))
4375        {
4376                logfileLine("ProcessCloneSyncJob",mysql_error(&gMysql));
4377                return(2);
4378        }
4379        res=mysql_store_result(&gMysql);
4380        if((field=mysql_fetch_row(res)))
4381                sscanf(field[0],"%u",&uPeriod);
4382        mysql_free_result(res);
4383
4384        if(uPeriod!=0)
4385        {
4386                if(guDebug)
4387                {
4388                        sprintf(gcQuery,"uPeriod=%u",uPeriod);
4389                        logfileLine("ProcessCloneSyncJob",gcQuery);
4390                }
4391
4392                sprintf(gcQuery,"SELECT tNode.cLabel FROM tContainer,tNode WHERE"
4393                                " tContainer.uNode=tNode.uNode AND"
4394                                " tNode.uStatus=1 AND"//Active NODE
4395                                " tContainer.uContainer=%u AND"
4396                                " tContainer.uBackupDate+%u<=UNIX_TIMESTAMP(NOW())",uCloneContainer,uPeriod);
4397                mysql_query(&gMysql,gcQuery);
4398                if(mysql_errno(&gMysql))
4399                {
4400                        logfileLine("ProcessCloneSyncJob",mysql_error(&gMysql));
4401                        return(3);
4402                }
4403                res=mysql_store_result(&gMysql);
4404                if((field=mysql_fetch_row(res)))
4405                {
4406                        if(uNotValidSystemCallArg(field[0]))
4407                        {
4408                                mysql_free_result(res);
4409                                logfileLine("ProcessCloneSyncJob","security alert");
4410                                return(4);
4411                        }
4412
4413                        //Try to keep options out of scripts
4414                        char cSSHOptions[256]={""};
4415                        GetConfiguration("cSSHOptions",cSSHOptions,gfuDatacenter,gfuNode,0,0);//First try node specific
4416                        if(!cSSHOptions[0])
4417                        {
4418                                GetConfiguration("cSSHOptions",cSSHOptions,gfuDatacenter,0,0,0);//Second try datacenter wide
4419                                if(!cSSHOptions[0])
4420                                        GetConfiguration("cSSHOptions",cSSHOptions,0,0,0,0);//Last try global
4421                        }
4422                        //Default for less conditions below
4423                        if(!cSSHOptions[0] || uNotValidSystemCallArg(cSSHOptions))
4424                                sprintf(cSSHOptions,"-p 22 -c arcfour");
4425                        unsigned uSSHPort=22;
4426                        char *cp;
4427                        if((cp=strstr(cSSHOptions,"-p ")))
4428                                sscanf(cp+3,"%u",&uSSHPort);
4429
4430                        //New uBackupDate
4431                        unsigned uLastBackupDate=0;
4432                        MYSQL_RES *res2;
4433                        MYSQL_ROW field2;
4434                        sprintf(gcQuery,"SELECT uBackupDate FROM tContainer"
4435                                                " WHERE uContainer=%u",uCloneContainer);
4436                        mysql_query(&gMysql,gcQuery);
4437                        if(mysql_errno(&gMysql))
4438                        {
4439                                mysql_free_result(res);
4440                                logfileLine("ProcessCloneSyncJob",mysql_error(&gMysql));
4441                                return(5);
4442                        }
4443                        res2=mysql_store_result(&gMysql);
4444                        if((field2=mysql_fetch_row(res2)))
4445                                sscanf(field2[0],"%u",&uLastBackupDate);
4446                        mysql_free_result(res2);
4447                        sprintf(gcQuery,"UPDATE tContainer SET uBackupDate=UNIX_TIMESTAMP(NOW())"
4448                                                " WHERE uContainer=%u",uCloneContainer);
4449                        mysql_query(&gMysql,gcQuery);
4450                        if(mysql_errno(&gMysql))
4451                        {
4452                                mysql_free_result(res);
4453                                logfileLine("ProcessCloneSyncJob",mysql_error(&gMysql));
4454                                return(5);
4455                        }
4456
4457                        sprintf(gcQuery,"/usr/sbin/clonesync.sh %u %u %s %u",uContainer,uCloneContainer,field[0],uSSHPort);
4458                        if(guDebug)
4459                                logfileLine("ProcessCloneSyncJob",gcQuery);
4460
4461                        if(system(gcQuery))
4462                        {
4463                                mysql_free_result(res);
4464                                logfileLine("ProcessCloneSyncJob",gcQuery);
4465                                sprintf(gcQuery,"UPDATE tContainer SET uBackupDate=%u"
4466                                                " WHERE uContainer=%u",uLastBackupDate,uCloneContainer);
4467                                mysql_query(&gMysql,gcQuery);
4468                                if(mysql_errno(&gMysql))
4469                                {
4470                                        mysql_free_result(res);
4471                                        logfileLine("ProcessCloneSyncJob",mysql_error(&gMysql));
4472                                        return(7);
4473                                }
4474                                return(6);
4475                        }
4476                }
4477                mysql_free_result(res);
4478        }
4479        if(guDebug)
4480                logfileLine("ProcessCloneSyncJob","End");
4481        return(0);
4482
4483}//void ProcessCloneSyncJob()
4484
4485
4486void LogError(char *cErrorMsg,unsigned uKey)
4487{
4488        sprintf(gcQuery,"INSERT INTO tLog SET"
4489                " cLabel='unxsVZ CLI Error',"
4490                "uLogType=4,uLoginClient=1,"
4491                "cLogin='unxsVZ.cgi',cMessage=\"%s uKey=%u\","
4492                "cServer='%s',uOwner=1,uCreatedBy=1,"
4493                "uCreatedDate=UNIX_TIMESTAMP(NOW())",
4494                                        cErrorMsg,uKey,cHostname);
4495        mysql_query(&gMysql,gcQuery);
4496        if(mysql_errno(&gMysql))
4497        {
4498                logfileLine("LogError",mysql_error(&gMysql));
4499                exit(2);
4500        }
4501
4502}//void LogError(char *cErrorMsg)
4503
4504
4505void RecurringJob(unsigned uJob,unsigned uDatacenter,unsigned uNode,unsigned uContainer,const char *cJobData)
4506{
4507        MYSQL_RES *mysqlRes;
4508        MYSQL_ROW mysqlField;
4509        char *cp;
4510        unsigned uMin=-1,uHour=-1,uDayOfWeek=-1,uDayOfMonth=-1,uMonth=-1;
4511        char cRecurringJob[100]={""};
4512        char cCommand[100]={""};
4513        time_t luClock;
4514        struct tm structTm;
4515        struct stat statInfo;
4516
4517        //error policy: only on job format or sql errors mark as error, otherwise try again later
4518        //      but provide tJob error/info message.
4519
4520        //devel only
4521        //unsigned guDebug=1;
4522
4523        //Parse job data
4524        if((cp=strstr(cJobData,"uMin=")))
4525                sscanf(cp+5,"%u",&uMin);
4526        if((cp=strstr(cJobData,"uHour=")))
4527                sscanf(cp+6,"%u",&uHour);
4528        if((cp=strstr(cJobData,"uDayOfWeek=")))
4529                sscanf(cp+11,"%u",&uDayOfWeek);
4530        if((cp=strstr(cJobData,"uDayOfMonth=")))
4531                sscanf(cp+12,"%u",&uDayOfMonth);
4532        if((cp=strstr(cJobData,"uMonth=")))
4533                sscanf(cp+7,"%u",&uMonth);
4534        if(uMin== -1 || uHour== -1 || uDayOfWeek== -1 || uDayOfMonth== -1 || uMonth== -1)
4535        {
4536                logfileLine("RecurringJob One or more data=-1 cJobData=",cJobData);
4537                tJobErrorUpdate(uJob,"recurring job data=-1");
4538                return;
4539        }
4540        if(!uMin && !uHour && !uDayOfWeek && !uDayOfMonth && !uMonth)
4541        {
4542                logfileLine("RecurringJob All recurring job data=0 cJobData=",cJobData);
4543                tJobErrorUpdate(uJob,"recurring job data=0");
4544                return;
4545        }
4546
4547        if((cp=strstr(cJobData,"cRecurringJob=")))
4548                sprintf(cRecurringJob,"%.99s",cp+14);
4549        if((cp=strchr(cRecurringJob,';')))
4550                *cp=0;
4551        if(!cRecurringJob[0])   
4552        {
4553                logfileLine("RecurringJob cRecurringJob empty cJobData=",cJobData);
4554                tJobErrorUpdate(uJob,"cRecurringJob empty");
4555                return;
4556        }
4557
4558        //Determine if we run the job
4559        if(guDebug)
4560        {
4561                sprintf(gcQuery,"Job: uMonth=%u uDayOfMonth=%u uDayOfWeek=%u uHour=%u uMin=%u",
4562                                uMonth,uDayOfMonth,uDayOfWeek,uHour,uMin);
4563                logfileLine("RecurringJob info",gcQuery);
4564        }
4565
4566        time(&luClock);
4567        localtime_r(&luClock,&structTm);
4568
4569        //Note structTm.tm_mon+1. We adjust for normal 1-12
4570        if(guDebug)
4571        {
4572                sprintf(gcQuery,"Now: uMonth=%d uDayOfMonth=%d uDayOfWeek=%d uHour=%d uMin=%d",
4573                        structTm.tm_mon+1,structTm.tm_mday,structTm.tm_wday+1,structTm.tm_hour,structTm.tm_min);
4574                logfileLine("RecurringJob info",gcQuery);
4575        }
4576
4577        //If not any month and now month is less than job month do not run.
4578        if(uMonth && uMonth>structTm.tm_mon+1)
4579        {
4580                if(guDebug)
4581                        logfileLine("RecurringJob info","uMonth not reached");
4582                goto Common_WaitingExit;
4583        }
4584        //If not any day of month and now day of month is less than job day of month do not run.
4585        if(uDayOfMonth && uDayOfMonth>structTm.tm_mday)
4586        {
4587                if(guDebug)
4588                        logfileLine("RecurringJob info","uDayOfMonth not reached");
4589                goto Common_WaitingExit;
4590        }
4591        //If not any day of week and now day of week is less than job day of week do not run.
4592        if(uDayOfWeek && uDayOfWeek>structTm.tm_wday+1)
4593        {
4594                if(guDebug)
4595                        logfileLine("RecurringJob info","uDayOfWeek not reached");
4596                goto Common_WaitingExit;
4597        }
4598        //If not any hour and now hour is less than job hour do not run.
4599        if(uHour && uHour>structTm.tm_hour)
4600        {
4601                if(guDebug)
4602                        logfileLine("RecurringJob info","uHour not reached");
4603                goto Common_WaitingExit;
4604        }
4605        //If now min is less than job min do not run.
4606        if(uMin>structTm.tm_min)
4607        {
4608                if(guDebug)
4609                        logfileLine("RecurringJob info","uMin not reached");
4610                goto Common_WaitingExit;
4611        }
4612
4613        //Passed all constraints run job
4614        //Get command via cRecurringJob
4615
4616        sprintf(gcQuery,"SELECT TRIM(cValue) FROM tProperty WHERE uKey=0 AND uType=%u AND cName='%.99s'",
4617                                                                                uPROP_RECJOB,cRecurringJob);
4618        mysql_query(&gMysql,gcQuery);
4619        if(mysql_errno(&gMysql))
4620        {
4621                logfileLine("RecurringJob",mysql_error(&gMysql));
4622                tJobErrorUpdate(uJob,"tProperty WHERE uKey=0 AND uType");
4623                return;
4624        }
4625        mysqlRes=mysql_store_result(&gMysql);
4626        if((mysqlField=mysql_fetch_row(mysqlRes)))
4627                sprintf(cCommand,"%.99s",mysqlField[0]);
4628        mysql_free_result(mysqlRes);
4629
4630        //Remove trailing junk
4631        if((cp=strchr(cCommand,'\n')) || (cp=strchr(cCommand,'\r')))
4632                *cp=0;
4633               
4634        if(guDebug)
4635        {
4636                sprintf(gcQuery,"Proposed job to run: %s",cCommand);
4637                logfileLine("RecurringJob info",gcQuery);
4638        }
4639
4640        if(uNotValidSystemCallArg(cCommand))
4641        {
4642                tJobErrorUpdate(uJob,"cCommand sec alert!");
4643                logfileLine("RecurringJob","cCommand security alert");
4644                goto Common_WaitingExit;
4645        }
4646        //Only run if command is chmod 500 for extra security reasons.
4647        if(stat(cCommand,&statInfo))
4648        {
4649                tJobErrorUpdate(uJob,"stat(cCommand)");
4650                logfileLine("RecurringJob","stat failed for cCommand");
4651                goto Common_WaitingExit;
4652        }
4653        if(statInfo.st_mode & ( S_IWOTH | S_IWGRP | S_IWUSR | S_IXOTH | S_IROTH | S_IXGRP | S_IRGRP ) )
4654        {
4655                tJobErrorUpdate(uJob,"cCommand is not chmod 500");
4656                logfileLine("RecurringJob","cCommand is not chmod 500");
4657                goto Common_WaitingExit;
4658        }
4659        //printf("good perms (%x)\n",statInfo.st_mode&(S_IWOTH|S_IWGRP|S_IWUSR|S_IXOTH|S_IROTH|S_IXGRP|S_IRGRP));
4660        //goto Common_WaitingExit;
4661        if(guDebug)
4662        {
4663                sprintf(gcQuery,"Attempting %s",cCommand);
4664                logfileLine("RecurringJob",gcQuery);
4665        }
4666        if(system(cCommand))
4667        {
4668                tJobErrorUpdate(uJob,"system(cCommand)");
4669                logfileLine("RecurringJob",cCommand);
4670                goto Common_WaitingExit;
4671        }
4672        sprintf(gcQuery,"Ran %s",cCommand);
4673        logfileLine("RecurringJob",gcQuery);
4674        //Update uJobDate based on cJobData.
4675        //TODO: Analyze what happens when jobs for some reason do not run for given periods.
4676        //Case 1: Job set to run every Sunday (day 7) at 3:15 AM. Server was down since last saturday, it is now
4677        //       Friday and job has not run since Sunday more than a week ago. So
4678        //      tJob.uJobDate<UNIX_TIMESTAMP(NOW)) and RecurringJob() will
4679        //      be run. Since uDayOfWeek is 5 job will not run. On Sunday it will run correctly.
4680        //Case 2: Job is set to run every day 1 of every month. Server was down from previous month up to
4681        //      day 2. RecurringJob() will be called since it is day 2 > day 1 job will run. But next time
4682        //      it will also run on day 2 instead of day 1 unless we adjust the DATE_ADD() by 1 month minus 1
4683        //      day (i.e. Current day - target day.) (This at first blush seems to able to be extended to
4684        //      all the cases below except the every hour case, which does not require it -it seems.)
4685        //SELECT FROM_UNIXTIME( UNIX_TIMESTAMP(NOW())  -
4686        //      (EXTRACT(MINUTE FROM NOW())*60) -
4687        //      (EXTRACT(SECOND FROM NOW())) +
4688        //               3600 ) AS RoundUpNextHour;
4689        if(uMonth)
4690                sprintf(gcQuery,"UPDATE tJob SET"
4691                " uJobDate=UNIX_TIMESTAMP(DATE_ADD(CURDATE(),INTERVAL 1 YEAR))+%u+%u-((DAYOFYEAR(CURDATE())-(%u*30))*86400)"
4692                " WHERE uJob=%u",uMin*60,uHour*3600,uMonth,uJob);
4693        else if(uDayOfMonth)
4694                sprintf(gcQuery,"UPDATE tJob SET"
4695                " uJobDate=UNIX_TIMESTAMP(DATE_ADD(CURDATE(),INTERVAL 1 MONTH))+%u+%u-((DAY(CURDATE())-%u)*86400)"
4696                " WHERE uJob=%u",uMin*60,uHour*3600,uDayOfMonth,uJob);
4697        else if(uDayOfWeek)
4698                sprintf(gcQuery,"UPDATE tJob SET"
4699                " uJobDate=UNIX_TIMESTAMP(DATE_ADD(CURDATE(),INTERVAL 1 WEEK))+%u+%u-((DAYOFWEEK(CURDATE())-%u)*86400)"
4700                " WHERE uJob=%u",uMin*60,uHour*3600,uDayOfWeek,uJob);
4701        else if(1)
4702                sprintf(gcQuery,"UPDATE tJob SET"
4703                " uJobDate=UNIX_TIMESTAMP(NOW())-(EXTRACT(MINUTE FROM NOW())*60)-(EXTRACT(SECOND FROM NOW()))+3600+%u+%u"
4704                " WHERE uJob=%u",uMin*60,uHour*3600,uJob);
4705        mysql_query(&gMysql,gcQuery);
4706        if(mysql_errno(&gMysql))
4707        {
4708                logfileLine("RecurringJob",mysql_error(&gMysql));
4709                tJobErrorUpdate(uJob,"DateAdjustSQL");
4710                return;
4711        }
4712        tJobDoneUpdate(uJob);
4713
4714Common_WaitingExit:
4715        SetJobStatus(uJob,uWAITING);
4716        return;
4717
4718}//void RecurringJob(uJob,uDatacenter,uNode,uContainer,cJobData)
4719
4720
4721void SetJobStatus(unsigned uJob,unsigned uJobStatus)
4722{
4723        sprintf(gcQuery,"UPDATE tJob SET uJobStatus=%u,uModBy=1,"
4724                                "uModDate=UNIX_TIMESTAMP(NOW()) WHERE uJob=%u",uJobStatus,uJob);
4725        mysql_query(&gMysql,gcQuery);
4726        if(mysql_errno(&gMysql))
4727        {
4728                logfileLine("SetJobStatus",mysql_error(&gMysql));
4729                exit(2);
4730        }
4731
4732}//void SetJobStatus(unsigned uJob,unsigned uJobStatus)
4733
4734
4735unsigned ProcessOSDeltaSyncJob(unsigned uNode,unsigned uContainer,unsigned uCloneContainer)
4736{
4737        MYSQL_RES *res;
4738        MYSQL_ROW field;
4739        unsigned uPeriod=0;
4740        char cSyncMode[32]={""};
4741
4742        sprintf(gcQuery,"SELECT cValue FROM tProperty WHERE uKey=%u AND uType=3 AND cName='cSyncMode'",
4743                                        uCloneContainer);
4744        mysql_query(&gMysql,gcQuery);
4745        if(mysql_errno(&gMysql))
4746        {
4747                logfileLine("ProcessOSDeltaSyncJob",mysql_error(&gMysql));
4748                return(2);
4749        }
4750        res=mysql_store_result(&gMysql);
4751        if((field=mysql_fetch_row(res)))
4752                sprintf(cSyncMode,"%.31s",field[0]);
4753        mysql_free_result(res);
4754
4755        if(guDebug)
4756        {
4757                sprintf(gcQuery,"Start uContainer=%u,uCloneContainer=%u,cSyncMode=%s",uContainer,uCloneContainer,cSyncMode);
4758                logfileLine("ProcessOSDeltaSyncJob",gcQuery);
4759        }
4760
4761        if(cSyncMode[0]==0 || cSyncMode[0]!='C')
4762                return(0);
4763
4764        //After failover cuSyncPeriod is 0 for clone (remote) container.
4765        //This allows for safekeeping of potentially useful data.
4766        //mainfunc RecoverMode recover cuSyncPeriod from source to clone.
4767        sprintf(gcQuery,"SELECT cValue FROM tProperty WHERE uKey=%u AND uType=3 AND cName='cuSyncPeriod'",
4768                                        uCloneContainer);
4769        mysql_query(&gMysql,gcQuery);
4770        if(mysql_errno(&gMysql))
4771        {
4772                logfileLine("ProcessOSDeltaSyncJob",mysql_error(&gMysql));
4773                return(2);
4774        }
4775        res=mysql_store_result(&gMysql);
4776        if((field=mysql_fetch_row(res)))
4777                sscanf(field[0],"%u",&uPeriod);
4778        mysql_free_result(res);
4779
4780        if(uPeriod!=0)
4781        {
4782                if(guDebug)
4783                {
4784                        sprintf(gcQuery,"uPeriod=%u",uPeriod);
4785                        logfileLine("ProcessOSDeltaSyncJob",gcQuery);
4786                }
4787
4788                sprintf(gcQuery,"SELECT tNode.cLabel FROM tContainer,tNode WHERE"
4789                                " tContainer.uNode=tNode.uNode AND"
4790                                " tNode.uStatus=1 AND"//Active NODE
4791                                " tContainer.uContainer=%u AND"
4792                                " tContainer.uBackupDate+%u<=UNIX_TIMESTAMP(NOW())",uCloneContainer,uPeriod);
4793                mysql_query(&gMysql,gcQuery);
4794                if(mysql_errno(&gMysql))
4795                {
4796                        logfileLine("ProcessOSDeltaSyncJob",mysql_error(&gMysql));
4797                        return(3);
4798                }
4799                res=mysql_store_result(&gMysql);
4800                if((field=mysql_fetch_row(res)))
4801                {
4802                        if(uNotValidSystemCallArg(field[0]))
4803                        {
4804                                mysql_free_result(res);
4805                                logfileLine("ProcessOSDeltaSyncJob","security alert");
4806                                return(4);
4807                        }
4808
4809                        //Try to keep options out of scripts
4810                        char cSSHOptions[256]={""};
4811                        GetConfiguration("cSSHOptions",cSSHOptions,gfuDatacenter,gfuNode,0,0);//First try node specific
4812                        if(!cSSHOptions[0])
4813                        {
4814                                GetConfiguration("cSSHOptions",cSSHOptions,gfuDatacenter,0,0,0);//Second try datacenter wide
4815                                if(!cSSHOptions[0])
4816                                        GetConfiguration("cSSHOptions",cSSHOptions,0,0,0,0);//Last try global
4817                        }
4818                        //Default for less conditions below
4819                        if(!cSSHOptions[0] || uNotValidSystemCallArg(cSSHOptions))
4820                                sprintf(cSSHOptions,"-p 22 -c arcfour");
4821                        unsigned uSSHPort=22;
4822                        char *cp;
4823                        if((cp=strstr(cSSHOptions,"-p ")))
4824                                sscanf(cp+3,"%u",&uSSHPort);
4825
4826                        //New uBackupDate. Undone later if backup fails
4827                        unsigned uLastBackupDate=0;
4828                        MYSQL_RES *res2;
4829                        MYSQL_ROW field2;
4830                        sprintf(gcQuery,"SELECT uBackupDate FROM tContainer"
4831                                                " WHERE uContainer=%u",uCloneContainer);
4832                        mysql_query(&gMysql,gcQuery);
4833                        if(mysql_errno(&gMysql))
4834                        {
4835                                mysql_free_result(res);
4836                                logfileLine("ProcessOSDeltaSyncJob",mysql_error(&gMysql));
4837                                return(5);
4838                        }
4839                        res2=mysql_store_result(&gMysql);
4840                        if((field2=mysql_fetch_row(res2)))
4841                                sscanf(field2[0],"%u",&uLastBackupDate);
4842                        mysql_free_result(res2);
4843                        sprintf(gcQuery,"UPDATE tContainer SET uBackupDate=UNIX_TIMESTAMP(NOW())"
4844                                                " WHERE uContainer=%u",uCloneContainer);
4845                        mysql_query(&gMysql,gcQuery);
4846                        if(mysql_errno(&gMysql))
4847                        {
4848                                mysql_free_result(res);
4849                                logfileLine("ProcessOSDeltaSyncJob",mysql_error(&gMysql));
4850                                return(5);
4851                        }
4852
4853                        sprintf(gcQuery,"/usr/sbin/osdeltasync.sh %u %u %s %u",uContainer,uCloneContainer,field[0],uSSHPort);
4854                        if(guDebug)
4855                                logfileLine("ProcessOSDeltaSyncJob",gcQuery);
4856                        if(system(gcQuery))
4857                        {
4858                                mysql_free_result(res);
4859                                logfileLine("ProcessOSDeltaSyncJob",gcQuery);
4860                                //sync script failed so we reset the backup date
4861                                sprintf(gcQuery,"UPDATE tContainer SET uBackupDate=%u"
4862                                                " WHERE uContainer=%u",uLastBackupDate,uCloneContainer);
4863                                mysql_query(&gMysql,gcQuery);
4864                                if(mysql_errno(&gMysql))
4865                                {
4866                                        mysql_free_result(res);
4867                                        logfileLine("ProcessOSDeltaSyncJob",mysql_error(&gMysql));
4868                                        return(7);
4869                                }
4870                                return(6);
4871                        }
4872                }
4873                mysql_free_result(res);
4874        }
4875        if(guDebug)
4876                logfileLine("ProcessOSDeltaSyncJob","End");
4877        return(0);
4878
4879}//void ProcessOSDeltaSyncJob()
4880
4881
4882void CloneRemoteContainer(unsigned uJob,unsigned uContainer,char *cJobData,unsigned uNewVeid)
4883{
4884        MYSQL_RES *res;
4885        MYSQL_ROW field;
4886        char cTargetNodeIPv4[256]={""};
4887        unsigned uCloneStop=0;
4888        unsigned uPrevStatus=0;
4889        unsigned uTargetNode=0;
4890        char cNewIP[32]={""};
4891        char cHostname[100]={""};
4892        char cName[32]={""};
4893        char cOSTemplate[32]={""};
4894        char cConfig[32]={""};
4895
4896        logfileLine("CloneRemoteContainer","Start");
4897
4898        //Set job data based vars
4899        sscanf(cJobData,"uTargetNode=%u;",&uTargetNode);
4900        sscanf(cJobData,"uTargetNode=%*u;\nuNewVeid=%*u;\nuCloneStop=%u;",&uCloneStop);
4901        sscanf(cJobData,"uTargetNode=%*u;\nuNewVeid=%*u;\nuCloneStop=%*u;\nuPrevStatus=%u;",&uPrevStatus);
4902        if(!uPrevStatus)
4903        {
4904                logfileLine("CloneRemoteContainer","Could not determine uPrevStatus");
4905                tJobErrorUpdate(uJob,"uPrevStatus==0");
4906                goto CommonExit;
4907        }
4908
4909        sprintf(gcQuery,"SELECT tIP.cLabel,tContainer.cHostname,tContainer.cLabel FROM tIP,tContainer"
4910                                " WHERE tIP.uIP=tContainer.uIPv4"
4911                                " AND tContainer.uContainer=%u",uNewVeid);
4912        mysql_query(&gMysql,gcQuery);
4913        if(mysql_errno(&gMysql))
4914        {
4915                logfileLine("CloneRemoteContainer",mysql_error(&gMysql));
4916                tJobErrorUpdate(uJob,"SELECT tIP.cLabel");
4917                goto CommonExit;
4918        }
4919        res=mysql_store_result(&gMysql);
4920        if((field=mysql_fetch_row(res)))
4921        {
4922                sprintf(cNewIP,"%.31s",field[0]);
4923                sprintf(cHostname,"%.99s",field[1]);
4924                sprintf(cName,"%.31s",field[2]);
4925        }
4926        mysql_free_result(res);
4927        if(!cNewIP[0])
4928        {
4929                logfileLine("CloneRemoteContainer","Could not determine cNewIP");
4930                tJobErrorUpdate(uJob,"No cNewIP");
4931                goto CommonExit;
4932        }
4933        if(!cHostname[0])
4934        {
4935                logfileLine("CloneRemoteContainer","Could not determine cHostname");
4936                tJobErrorUpdate(uJob,"No cHostname");
4937                goto CommonExit;
4938        }
4939        if(!cName[0])
4940        {
4941                logfileLine("CloneRemoteContainer","Could not determine cName");
4942                tJobErrorUpdate(uJob,"No cName");
4943                goto CommonExit;
4944        }
4945
4946        sprintf(gcQuery,"SELECT tOSTemplate.cLabel FROM tOSTemplate,tContainer WHERE tOSTemplate.uOSTemplate=tContainer.uOSTemplate"
4947                        " AND tContainer.uContainer=%u",uNewVeid);
4948        mysql_query(&gMysql,gcQuery);
4949        if(mysql_errno(&gMysql))
4950        {
4951                logfileLine("CloneRemoteContainer",mysql_error(&gMysql));
4952                tJobErrorUpdate(uJob,"SELECT tOSTemplate.cLabel");
4953                goto CommonExit;
4954        }
4955        res=mysql_store_result(&gMysql);
4956        if((field=mysql_fetch_row(res)))
4957                sprintf(cOSTemplate,"%.31s",field[0]);
4958        mysql_free_result(res);
4959        if(!cOSTemplate[0])
4960        {
4961                logfileLine("CloneRemoteContainer","Could not determine cOSTemplate");
4962                tJobErrorUpdate(uJob,"No cOSTemplate");
4963                goto CommonExit;
4964        }
4965
4966        sprintf(gcQuery,"SELECT tConfig.cLabel FROM tConfig,tContainer WHERE tConfig.uConfig=tContainer.uConfig"
4967                        " AND tContainer.uContainer=%u",uNewVeid);
4968        mysql_query(&gMysql,gcQuery);
4969        if(mysql_errno(&gMysql))
4970        {
4971                logfileLine("CloneRemoteContainer",mysql_error(&gMysql));
4972                tJobErrorUpdate(uJob,"SELECT tConfig.cLabel");
4973                goto CommonExit;
4974        }
4975        res=mysql_store_result(&gMysql);
4976        if((field=mysql_fetch_row(res)))
4977                sprintf(cConfig,"%.31s",field[0]);
4978        mysql_free_result(res);
4979        if(!cOSTemplate[0])
4980        {
4981                logfileLine("CloneRemoteContainer","Could not determine cConfig");
4982                tJobErrorUpdate(uJob,"No cConfig");
4983                goto CommonExit;
4984        }
4985
4986        //Remote datacenter node: We use the node cLabel. It follows that DNS/hosts must
4987        //be setup correctly.
4988        sprintf(cTargetNodeIPv4,"%.31s",ForeignKey("tNode","cLabel",uTargetNode));
4989        if(!cTargetNodeIPv4[0])
4990        {
4991                logfileLine("CloneRemoteContainer","Could not determine cTargetNodeIPv4");
4992                tJobErrorUpdate(uJob,"cTargetNodeIPv4");
4993                goto CommonExit;
4994        }
4995
4996        //Most specific tConfiguration is used. This allows for some nodes to be set global
4997        //and others specific. But is slower than the other option with what maybe
4998        //very large numbers of per node tConfiguration entries.
4999        char cSSHOptions[256]={""};
5000        GetConfiguration("cSSHOptions",cSSHOptions,gfuDatacenter,gfuNode,0,0);//First try node specific
5001        if(!cSSHOptions[0])
5002        {
5003                GetConfiguration("cSSHOptions",cSSHOptions,gfuDatacenter,0,0,0);//Second try datacenter wide
5004                if(!cSSHOptions[0])
5005                        GetConfiguration("cSSHOptions",cSSHOptions,0,0,0,0);//Last try global
5006        }
5007        //Default for less conditions below
5008        if(!cSSHOptions[0] || uNotValidSystemCallArg(cSSHOptions))
5009                sprintf(cSSHOptions,"-p 22 -c arcfour");
5010
5011        //debug only
5012        //printf("uNewVeid=%u uTargetNode=%u cNewIP=%s cHostname=%s cTargetNodeIPv4=%s"
5013        //              " cOSTemplate=%s uCloneStop=%u cSSHOptions=%s cConfig=%s\n",
5014        //                      uNewVeid,uTargetNode,cNewIP,cHostname,
5015        //                      cTargetNodeIPv4,cOSTemplate,uCloneStop,cSSHOptions,cConfig);
5016
5017        //0-. we check data that could be comprimised that will be used by root shell commands
5018        //1-. we create a container on target node from same os template as source container
5019        //2-. we run osdeltasync on this source node to create a working clone
5020        //3-. we set ip, name and hostname
5021        //4-. remove any other /etc/vz/conf/veid.x files
5022        //5-. conditionally start new veid and modify VEID.conf file to not start on boot.
5023        //6-. update source container status
5024        //7-. update target container status
5025
5026        //0-.
5027        if(uNotValidSystemCallArg(cTargetNodeIPv4))
5028        {
5029                tJobErrorUpdate(uJob,"fail sec alert!");
5030                goto CommonExit;
5031        }
5032        if(uNotValidSystemCallArg(cHostname))
5033        {
5034                tJobErrorUpdate(uJob,"fail sec alert!");
5035                goto CommonExit;
5036        }
5037        if(uNotValidSystemCallArg(cName))
5038        {
5039                tJobErrorUpdate(uJob,"fail sec alert!");
5040                goto CommonExit;
5041        }
5042
5043        //2 is no container cold initial state only in db
5044        if(uCloneStop!=COLD_CLONE)
5045        {
5046
5047                //1-.
5048                sprintf(gcQuery,"ssh %s %s '/usr/sbin/vzctl --verbose create %u --ostemplate %s --config %s'",
5049                                cSSHOptions,cTargetNodeIPv4,
5050                                uNewVeid,cOSTemplate,cConfig);
5051                if(system(gcQuery))
5052                {
5053                        logfileLine("CloneRemoteContainer",gcQuery);
5054                        tJobErrorUpdate(uJob,"vzctl create failed");
5055                        goto CommonExit;
5056                }
5057        }
5058
5059        //2-.
5060        unsigned uSSHPort=22;
5061        char *cp;
5062        if((cp=strstr(cSSHOptions,"-p ")))
5063                sscanf(cp+3,"%u",&uSSHPort);
5064        sprintf(gcQuery,"/usr/sbin/osdeltasync.sh %u %u %s %u",uContainer,uNewVeid,cTargetNodeIPv4,uSSHPort);
5065        if(system(gcQuery))
5066        {
5067                logfileLine("CloneRemoteContainer",gcQuery);
5068                tJobErrorUpdate(uJob,"osdeltasync.sh");
5069                //rollback
5070                if(uCloneStop!=COLD_CLONE)
5071                {
5072                        sprintf(gcQuery,"ssh %s %s 'vzctl destroy %u'",
5073                                cSSHOptions,cTargetNodeIPv4,uNewVeid);
5074                        system(gcQuery);
5075                }
5076                goto CommonExit;
5077        }
5078
5079        if(uCloneStop!=COLD_CLONE)
5080        {
5081                //3-.
5082                //cHostname set
5083                sprintf(gcQuery,"ssh %s %s 'vzctl set %u --hostname %s --save'",
5084                                cSSHOptions,cTargetNodeIPv4,uNewVeid,cHostname);
5085                if(system(gcQuery))
5086                {
5087                        logfileLine("CloneRemoteContainer",gcQuery);
5088                        tJobErrorUpdate(uJob,"cHostname");
5089                        goto CommonExit;
5090                }
5091                //cName set
5092                sprintf(gcQuery,"ssh %s %s 'vzctl set %u --name %s --save'",
5093                                cSSHOptions,cTargetNodeIPv4,uNewVeid,cName);
5094                if(system(gcQuery))
5095                {
5096                        logfileLine("CloneRemoteContainer",gcQuery);
5097                        tJobErrorUpdate(uJob,"cName");
5098                        goto CommonExit;
5099                }
5100                //IP set
5101                sprintf(gcQuery,"ssh %s %s 'vzctl set %u --ipdel all --save'",
5102                                cSSHOptions,cTargetNodeIPv4,uNewVeid);
5103                if(system(gcQuery))
5104                {
5105                        logfileLine("CloneRemoteContainer",gcQuery);
5106                        tJobErrorUpdate(uJob,"error 4c");
5107                        goto CommonExit;
5108                }
5109                sprintf(gcQuery,"ssh %s %s 'vzctl set %u --ipadd %s --save'",
5110                                cSSHOptions,cTargetNodeIPv4,uNewVeid,cNewIP);
5111                if(system(gcQuery))
5112                {
5113                        logfileLine("CloneRemoteContainer",gcQuery);
5114                        tJobErrorUpdate(uJob,"error 4d");
5115                        goto CommonExit;
5116                }
5117
5118                //4-. Remove action script files if found
5119                //Business logic: Target container may have these files, but we need them only if we
5120                //'Failover' to this cloned VE. Also we defer to that action the setup of the
5121                //containers tProperty values needed for processing the action script templates:
5122                //cNetmask, cExtraNodeIP, cPrivateIPs, cService1, cService2, cVEID.mount and cVEID.umount, etc.
5123                sprintf(gcQuery,"ssh %3$s %1$s 'rm -f /etc/vz/conf/%2$u.umount /etc/vz/conf/%2$u.mount"
5124                                        " /etc/vz/conf/%2$u.start /etc/vz/conf/%2$u.stop'",
5125                                                cTargetNodeIPv4,uNewVeid,cSSHOptions);
5126                if(system(gcQuery))
5127                {
5128                        logfileLine("CloneRemoteContainer",gcQuery);
5129                        tJobErrorUpdate(uJob,"error 4");
5130                        goto CommonExit;
5131                }
5132
5133                //5-.
5134                //This is optional since clones can be in stopped state and still be
5135                //kept in sync with source container. Also the failover can start (a fast operation)
5136                //with the extra advantage of being able to keep original IPs. Only needing an arping
5137                //to move the VIPs around the datacenter.
5138                if(uCloneStop==HOT_CLONE)
5139                {
5140                        sprintf(gcQuery,"ssh %s %s 'vzctl start %u'",cSSHOptions,cTargetNodeIPv4,uNewVeid);
5141                        if(system(gcQuery))
5142                        {
5143                                logfileLine("CloneRemoteContainer",gcQuery);
5144                                tJobErrorUpdate(uJob,"error 5");
5145                                goto CommonExit;
5146                        }
5147                        sprintf(gcQuery,"ssh %s %s 'vzctl set %u --onboot yes --save'",
5148                                                                        cSSHOptions,cTargetNodeIPv4,uNewVeid);
5149                        if(system(gcQuery))
5150                        {
5151                                logfileLine("CloneRemoteContainer",gcQuery);
5152                                tJobErrorUpdate(uJob,"error 5b");
5153                                goto CommonExit;
5154                        }
5155                        SetContainerStatus(uNewVeid,uACTIVE);
5156                }
5157                else
5158                {
5159                        sprintf(gcQuery,"ssh %s %s 'vzctl set %u --onboot no --save'",
5160                                                                        cSSHOptions,cTargetNodeIPv4,uNewVeid);
5161                        if(system(gcQuery))
5162                        {
5163                                logfileLine("CloneRemoteContainer",gcQuery);
5164                                tJobErrorUpdate(uJob,"error 5c");
5165                                goto CommonExit;
5166                        }
5167                        SetContainerStatus(uNewVeid,uSTOPPED);
5168                }
5169        }
5170        else
5171        {
5172                //Cold clone
5173                SetContainerStatus(uNewVeid,uINITSETUP);
5174        }
5175
5176        //Some job setup may have already changed it to active?
5177        if(uPrevStatus!=uINITSETUP)     
5178                SetContainerStatus(uContainer,uPrevStatus);
5179        tJobDoneUpdate(uJob);
5180
5181//This goto MIGHT be ok.
5182CommonExit:
5183        return;
5184
5185}//void CloneRemoteContainer(...)
5186
5187
5188void SwapIPContainer(unsigned uJob,unsigned uContainer,char *cJobData)
5189{
5190
5191        char cIPNew1[31]={""};
5192        char cIPNew2[31]={""};
5193        char cIPOld1[31]={""};
5194        char cIPOld2[31]={""};
5195        char *cp;
5196        MYSQL_RES *res;
5197        MYSQL_ROW field;
5198        unsigned uVeth=0;
5199        unsigned uContainer2=0;
5200
5201        //Check 1-. Check to make sure container is on this node, if not
5202        //      give job back to queue
5203        sprintf(gcQuery,"/usr/sbin/vzlist %u > /dev/null 2>&1",uContainer);
5204        if(system(gcQuery))
5205        {
5206                logfileLine("SwapIPContainer","Job returned to queue");
5207                tJobWaitingUpdate(uJob);
5208                return;
5209        }
5210
5211
5212        //0-. Get required data
5213        sprintf(gcQuery,"SELECT tIP.cLabel,tContainer.uVeth"
5214                        " FROM tContainer,tIP WHERE uContainer=%u"
5215                        " AND tContainer.uIPv4=tIP.uIP",uContainer);
5216        mysql_query(&gMysql,gcQuery);
5217        if(mysql_errno(&gMysql))
5218        {
5219                logfileLine("SwapIPContainer",mysql_error(&gMysql));
5220                exit(2);
5221        }
5222        res=mysql_store_result(&gMysql);
5223        if((field=mysql_fetch_row(res)))
5224        {
5225                MYSQL_RES *res2;
5226                MYSQL_ROW field2;
5227
5228                //db
5229                sscanf(field[1],"%u",&uVeth);
5230
5231                sprintf(cIPNew1,"%.31s",field[0]);
5232                if(!cIPNew1[0])
5233                {
5234                        logfileLine("SwapIPContainer cIPNew",gcQuery);
5235                        tJobErrorUpdate(uJob,"Get cIPNew failed");
5236                        goto CommonExit;
5237                }
5238
5239                //job data
5240                sscanf(cJobData,"uContainer2=%u;",&uContainer2);
5241                if(!uContainer2)       
5242                {
5243                        logfileLine("SwapIPContainer uContainer2 from cJobData=",cJobData);
5244                        tJobErrorUpdate(uJob,"Get uContainer2 failed");
5245                        goto CommonExit;
5246                }
5247                sscanf(cJobData,"uContainer2=%*u;\ncIPOld1=%31s;\n",cIPOld1);
5248                if((cp=strchr(cIPOld1,';')))
5249                        *cp=0;
5250                if(!cIPOld1[0])
5251                {
5252                        logfileLine("ChangeIPContainer cIPOld1 from cJobData=",cJobData);
5253                        tJobErrorUpdate(uJob,"Get cIPOld1 failed");
5254                        goto CommonExit;
5255                }
5256                if((cp=strstr(cJobData,"cIPOld2=")))
5257                {
5258                        char *cp1;
5259
5260                        sscanf(cp,"cIPOld2=%31s;",cIPOld2);
5261                        if((cp1=strchr(cIPOld2,';')))
5262                                *cp1=0;
5263                }
5264                if(!cIPOld2[0])
5265                {
5266                        logfileLine("ChangeIPContainer cIPOld2 from cJobData=",cJobData);
5267                        tJobErrorUpdate(uJob,"Get cIPOld2 failed");
5268                        goto CommonExit;
5269                }
5270
5271                sprintf(gcQuery,"SELECT tIP.cLabel,tContainer.uVeth"
5272                        " FROM tContainer,tIP WHERE uContainer=%u"
5273                        " AND tContainer.uIPv4=tIP.uIP",uContainer2);
5274                mysql_query(&gMysql,gcQuery);
5275                if(mysql_errno(&gMysql))
5276                {
5277                        logfileLine("SwapIPContainer",mysql_error(&gMysql));
5278                        exit(2);
5279                }
5280                res2=mysql_store_result(&gMysql);
5281                if((field2=mysql_fetch_row(res2)))
5282                {
5283                        sprintf(cIPNew2,"%.31s",field2[0]);
5284                        if(!cIPNew2[0])
5285                        {
5286                                logfileLine("SwapIPContainer cIPNew2",gcQuery);
5287                                tJobErrorUpdate(uJob,"Get cIPNew2 failed");
5288                                goto CommonExit;
5289                        }
5290                }
5291                mysql_free_result(res2);
5292
5293                if(uNotValidSystemCallArg(cIPNew1)||uNotValidSystemCallArg(cIPNew2))
5294                {
5295                        logfileLine("SwapIPContainer","security alert");
5296                        tJobErrorUpdate(uJob,"failed sec alert!");
5297                        goto CommonExit;
5298                }
5299
5300
5301                //debug only
5302                sprintf(gcQuery,"%u %s %s, %u %s %s",uContainer,cIPNew1,cIPOld1,uContainer2,cIPNew2,cIPOld2);
5303                logfileLine("SwapIPContainer",gcQuery);
5304                //tJobErrorUpdate(uJob,"debug");
5305                //goto CommonExit;
5306
5307                if(!uVeth)
5308                {
5309                        //1-.
5310                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel %s --save",uContainer,cIPOld1);
5311                        if(system(gcQuery))
5312                        {
5313                                logfileLine("SwapIPContainer",gcQuery);
5314                                tJobErrorUpdate(uJob,"vzctl set ipdel failed");
5315                                goto CommonExit;
5316                        }
5317                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipdel %s --save",uContainer2,cIPOld2);
5318                        if(system(gcQuery))
5319                        {
5320                                logfileLine("SwapIPContainer",gcQuery);
5321                                tJobErrorUpdate(uJob,"vzctl set ipdel failed");
5322                                goto CommonExit;
5323                        }
5324
5325                        //2-.
5326                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer,cIPNew1);
5327                        if(system(gcQuery))
5328                        {
5329                                logfileLine("SwapIPContainer",gcQuery);
5330                                tJobErrorUpdate(uJob,"vzctl set ipadd failed");
5331                                goto CommonExit;
5332                        }
5333                        sprintf(gcQuery,"/usr/sbin/vzctl --verbose set %u --ipadd %s --save",uContainer2,cIPNew2);
5334                        if(system(gcQuery))
5335                        {
5336                                logfileLine("SwapIPContainer",gcQuery);
5337                                tJobErrorUpdate(uJob,"vzctl set ipadd failed");
5338                                goto CommonExit;
5339                        }
5340                }
5341                else
5342                {
5343                        logfileLine("SwapIPContainer","uVeth containers not supported");
5344                        tJobErrorUpdate(uJob,"uVeth container");
5345                        goto CommonExit;
5346                }
5347
5348                //Everything ok
5349                SetContainerStatus(uContainer,1);//Active
5350                SetContainerStatus(uContainer2,1);//Active
5351                tJobDoneUpdate(uJob);
5352
5353        }
5354        else
5355        {
5356                logfileLine("SwapIPContainer",gcQuery);
5357                tJobErrorUpdate(uJob,"No line from query");
5358        }
5359
5360//This goto MIGHT be ok
5361CommonExit:
5362        mysql_free_result(res);
5363        return;
5364
5365}//void SwapIPContainer()
5366
5367
5368//These functions assume something like this at end part of /etc/sysconfig/iptables:
5369// -A FORWARD -p tcp -m tcp --dport 443 -j REJECT --reject-with icmp-port-unreachable
5370void AllowAccess(unsigned uJob,const char *cJobData)
5371{
5372        char cIPv4[16]={""};
5373        char *cp;
5374
5375        sscanf(cJobData,"cIPv4=%15s;",cIPv4);
5376        if((cp=strchr(cIPv4,';')))
5377                *cp=0;
5378        if(!cIPv4[0])
5379        {
5380                logfileLine("AllowAccess","Could not determine cIPv4");
5381                tJobErrorUpdate(uJob,"cIPv4[0]==0");
5382                return;
5383        }
5384
5385        //Test fixed rule for now
5386        sprintf(gcQuery,"/sbin/iptables -L -n | grep %.15s > /dev/null; if [ $? != 0 ];then"
5387                        " /sbin/iptables -I FORWARD -s %.15s -p tcp -m tcp --dport 443 -j ACCEPT; fi;",cIPv4,cIPv4);
5388        if(system(gcQuery))
5389        {
5390                logfileLine("AllowAccess","iptables command failed");
5391                tJobErrorUpdate(uJob,"iptables command failed");
5392                return;
5393        }
5394
5395        logfileLine("AllowAccess","iptables command ok");
5396        tJobDoneUpdate(uJob);
5397        return;
5398
5399}//void AllowAccess(unsigned uJob,const char *cJobData)
5400
5401
5402void DenyAccess(unsigned uJob,const char *cJobData)
5403{
5404        char cIPv4[16]={""};
5405        char *cp;
5406
5407        sscanf(cJobData,"cIPv4=%15s;",cIPv4);
5408        if((cp=strchr(cIPv4,';')))
5409                *cp=0;
5410        if(!cIPv4[0])
5411        {
5412                logfileLine("DenyAccess","Could not determine cIPv4");
5413                tJobErrorUpdate(uJob,"cIPv4[0]==0");
5414                return;
5415        }
5416
5417        //Test fixed rule for now
5418        sprintf(gcQuery,"/sbin/iptables -L -n | grep %.15s > /dev/null; if [ $? == 0 ];then"
5419                        " /sbin/iptables -D FORWARD -s %.15s -p tcp -m tcp --dport 443 -j ACCEPT; fi;",cIPv4,cIPv4);
5420        if(system(gcQuery))
5421                logfileLine("DenyAccess","iptables del command failed but ignored");
5422
5423        logfileLine("DenyAccess","iptables command ok");
5424        tJobDoneUpdate(uJob);
5425        return;
5426
5427}//void DenyAccess(unsigned uJob,const char *cJobData)
5428
5429
5430//This is a big security risk implement some kind of MD5 hash shared secret for it
5431//If MySQL is under enemy control they can run commands as root in any and all containers
5432void ExecuteCommands(unsigned uJob,unsigned uContainer,char *cJobData)
5433{
5434        MYSQL_RES *res;
5435
5436        //Check 1-. Check to make sure container is on this node, if not
5437        //      give job back to queue
5438        sprintf(gcQuery,"/usr/sbin/vzlist %u > /dev/null 2>&1",uContainer);
5439        if(system(gcQuery))
5440        {
5441                logfileLine("ExecuteCommands","Job returned to queue no such container");
5442                tJobWaitingUpdate(uJob);
5443                return;
5444        }
5445
5446        //Check 2-. Wait till any other jobs currently in the job queue for this
5447        //      container are done.
5448        sprintf(gcQuery,"SELECT uJob FROM tJob"
5449                        " WHERE uContainer=%u AND (uJobStatus=%u OR uJobStatus=%u) AND uJob!=%u",uContainer,uWAITING,uRUNNING,uJob);
5450        mysql_query(&gMysql,gcQuery);
5451        if(mysql_errno(&gMysql))
5452        {
5453                logfileLine("ExecuteCommands",mysql_error(&gMysql));
5454                exit(2);
5455        }
5456        res=mysql_store_result(&gMysql);
5457        if(mysql_num_rows(res)>0)
5458        {
5459                logfileLine("ExecuteCommands","Job returned to queue other jobs pending");
5460                tJobWaitingUpdate(uJob);
5461                mysql_free_result(res);
5462                return;
5463        }
5464        mysql_free_result(res);
5465
5466        //1-.
5467        FILE *pfp;
5468        sprintf(gcQuery,"/usr/sbin/vzctl exec %u -",uContainer);
5469        if((pfp=popen(gcQuery,"w"))==NULL)
5470        {
5471                logfileLine("ExecuteCommands",gcQuery);
5472                tJobErrorUpdate(uJob,"popen error");
5473                return;
5474        }
5475        if(fprintf(pfp,"%s",cJobData)<0)
5476        {
5477                logfileLine("ExecuteCommands",gcQuery);
5478                tJobErrorUpdate(uJob,"fprintf error");
5479                return;
5480        }
5481        if(pclose(pfp)<0)
5482        {
5483                logfileLine("ExecuteCommands",gcQuery);
5484                tJobErrorUpdate(uJob,"pclose error");
5485                return;
5486        }
5487
5488        //Everything ok
5489        //This job has no transient status change
5490        //SetContainerStatus(uContainer,1);//Active
5491        tJobDoneUpdate(uJob);
5492        //Clean out what may be a lot of repeated cJobData
5493        sprintf(gcQuery,"UPDATE tJob SET cJobData='' WHERE uJob=%u",uJob);
5494        mysql_query(&gMysql,gcQuery);
5495        if(mysql_errno(&gMysql))
5496                logfileLine("ExecuteCommands",mysql_error(&gMysql));
5497        return;
5498
5499}//void ExecuteCommands()
5500
Note: See TracBrowser for help on using the browser.