forked from SWG-Source/swg-main
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbuild_cluster_controller.pl
executable file
·744 lines (620 loc) · 18.4 KB
/
build_cluster_controller.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
#! /usr/bin/perl
# ======================================================================
# ======================================================================
use strict;
use warnings;
use Socket;
use File::Copy;
# ======================================================================
# Constants
# ======================================================================
use constant START_COMMUNICATION => "S";
use constant START_NOT_LOCKED_READY => "B";
use constant START_LOCKED_READY => "C";
use constant START_LOCKED_READY_UNAUTHORIZED_USER => "L";
use constant START_ERROR_AUTHORIZING => "K";
use constant END_COMMUNICATION => "E";
use constant END_SUCCESSFULL => "F";
use constant SUCCESSFULL_COMMAND => "P";
use constant FAILED_COMMAND => "U";
use constant UPDATE_BOOTLEG_STEP_OK => "G";
use constant UPDATE_BOOTLEG_STEP_FAILED => "H";
use constant UPDATE_BOOTLEG_SEND_DIRECTORY => "M";
use constant UPDATE_BOOTLEG_SEND_FILE => "N";
use constant UPDATE_BOOTLEG_FILES_FINISHED => "Q";
use constant SNAPSHOT_FAILED => "O";
use constant SNAPSHOT_SUCCESSFULL => "P";
use constant COMMAND_RESTART => "a";
use constant COMMAND_RESTART_LOGIN => "b";
use constant COMMAND_RESTART_NODES => "c";
use constant COMMAND_LOCK => "d";
use constant COMMAND_UNLOCK => "e";
use constant COMMAND_UPDATE_BOOTLEG => "f";
use constant COMMAND_CONTENT_SYNC => "g";
use constant COMMAND_SYNC_SPECIFIED_CHANGELISTS => "h";
use constant COMMAND_SNAPSHOT => "i";
use constant COMMAND_BOOTLEG_VERSION => "j";
use constant COMMAND_FREE_OBJECT_IDS => "k";
# ======================================================================
# Globals
# ======================================================================
my $buildCluster = "swo-dev9.station.sony.com";
my $port = "98452";
my $candela = "p:";
my $exitcode = 0;
my $name = $0;
$name =~ s/^(.*)\\//;
my $option;
my $command;
my $user;
# ======================================================================
# Subroutines
# ======================================================================
sub usage
{
print STDERR "\nUsage:\n";
print STDERR "\t$name [command(s)]\n\n".
"\t\t-restart :\n\t\t\t restart the build cluster (central node)\n".
"\t\t-restart-login :\n\t\t\t restart the Login server\n".
"\t\t-restart-nodes :\n\t\t\t restart all nodes of the build cluster\n".
"\t\t-lock :\n\t\t\t lock the build cluster (must be authorized user)\n".
"\t\t-unlock :\n\t\t\t unlock the build cluster (must be authorized user)\n".
"\t\t-update-bootleg <branch> :\n\t\t\t update the bootleg on the build cluster (p4 key check) - needs to be run in windows\n".
"\t\t-bootleg-version:\n\t\t\t check bootleg version on the build cluster\n".
"\t\t-free-object-ids :\n\t\t\t free object IDs in the database for the build cluster\n".
"\t\t-content-sync [changelist] :\n\t\t\t shut down, content sync to specific changelist (if none, content sync to head), bring up\n".
"\t\t-sync-specified-changelists <changelist [| changelist]> :\n\t\t\t shut down, sync to multiple specified changelists, bring up\n".
"\t\t-snap <schema> <branch> [dontsubmit] :\n\t\t\t free object IDs, make a snapshot, verifies before adding files to <branch> in perforce\n\t\t\t and submits unless [dontsubmit]\n".
"\t\t\t If <schema> does not exist, it is created otherwise it is overwritten\n".
"\n\tIf multiple commands are given, the build cluster will go down / come up only once around the commands (if necessary)\n";
die "\n";
}
sub exitFailed
{
$exitcode = 1;
goto FAIL;
}
sub perforceWhere
{
local $_;
# find out where a perforce file resides on the local machine
my $result;
{
open(P4, "p4 where $_[0] |");
$_ = <P4>;
chomp;
my @where = split;
$result = $where[2];
close(P4);
}
return $result;
}
sub checkarguments()
{
my @args = @ARGV;
while(@args)
{
my $elem = shift @args;
# check if the key is valid if the command requires one
if($elem =~ /^-snap$/)
{
$elem = shift @args;
&usage() if(!(defined $elem) || $elem =~ /^-/);
$elem = shift @args;
&usage() if(!(defined $elem) || $elem =~ /^-/);
# check for optional parameter
shift @args if((defined $args[0]) && $args[0] eq "dontsubmit");
}
elsif($elem =~ /^-update-bootleg$/)
{
$elem = shift @args;
&usage() if(!(defined $elem) || $elem =~ /^-/);
}
elsif($elem =~ /^-content-sync$/)
{
shift @args if(@args && !($args[0] =~ /^-/));
}
elsif($elem =~ /^-sync-specified-changelists$/)
{
$elem = shift @args;
&usage() if(!defined $elem || $elem =~ /^-/);
while(@args)
{
last if($args[0] =~ /^-/);
shift @args;
}
}
elsif(!($elem =~ /^-restart$/ || $elem =~ /^-restart-login$/ || $elem =~ /^-restart-nodes$/ || $elem =~ /^-lock$/ || $elem =~ /^-unlock$/ || $elem =~ /^-bootleg-version$/ || $elem =~ /^-free-object-ids$/ || $elem =~ /^-build_script_publish$/))
{
&usage();
}
}
}
sub openbuildsocket
{
socket(BUILD, PF_INET, SOCK_STREAM, getprotobyname('tcp')) || die "socket failed\n";
{
my $destination = inet_aton($buildCluster) || die "inet_aton failed\n";
my $paddr = sockaddr_in($port, $destination);
connect(BUILD, $paddr) || die "connect failed\n";
# unbuffer the socket
my $oldSelect = select(BUILD);
$| = 1;
select($oldSelect);
# put the socket into binary mode
binmode BUILD;
}
}
sub getuser
{
my $user;
open(P4, "p4 user -o |") || die "p4 user failed\n";
while(<P4>)
{
$user = $1 if(/^User:\s+(\S+)/);
}
close(P4);
die "Could not get perforce user\n" if(!defined $user);
return $user;
}
sub sendstartinfo
{
print STDERR "Contacting build cluster...\n";
print BUILD START_COMMUNICATION;
my $initializer = $user;
$initializer = "buildscript" if($user eq "build_script_publish");
my $length = length $initializer;
print BUILD pack("N", $length);
print BUILD $initializer;
my $returncode;
if(read(BUILD, $returncode, 1) != 1)
{
print STDERR "Problem contacting build server\n";
return 0;
}
if($returncode eq START_NOT_LOCKED_READY)
{
print STDERR "Build server is not locked and ready\n\n";
return 1;
}
elsif($returncode eq START_LOCKED_READY)
{
print STDERR "Build server is locked and ready\n\n";
return 1;
}
elsif($returncode eq START_LOCKED_READY_UNAUTHORIZED_USER)
{
print STDERR "Build server is locked (limited access for non-authoritative user)\n\n";
return 1;
}
elsif($returncode eq START_ERROR_AUTHORIZING)
{
print STDERR "problem authorizing $user for build server\n\n";
return 0;
}
else
{
print STDERR "Build server not ready\n\n";
return 0;
}
}
sub sendendinfo
{
print STDERR "Ending communication with build cluster...\n";
print BUILD END_COMMUNICATION;
my $returncode;
my $readreturn = read(BUILD, $returncode, 1);
if(!defined $readreturn || $readreturn != 1)
{
print STDERR "Build server communication ended abruptly\n";
return 0;
}
if($returncode eq END_SUCCESSFULL)
{
print STDERR "Build server communication ended successfully\n";
return 1;
}
else
{
print STDERR "Build server communication ended with errors\n";
return 0;
}
}
sub contentsync
{
my $changelist = "";
$changelist = shift @ARGV if(@ARGV && !($ARGV[0] =~ /^-/));
my $length = length $changelist;
print BUILD pack("N", $length);
print BUILD $changelist;
# Recieve any errors from the content sync
my $buffer;
return 0 if(read(BUILD, $buffer, 4) != 4);
$length = unpack("N", $buffer);
return 0 if(read(BUILD, $buffer, $length) != $length);
print $buffer;
return 1;
}
sub syncspecifiedchangelists
{
my $changelists = "";
while(@ARGV)
{
last if($ARGV[0] =~ /^-/);
my $elem = shift @ARGV;
$changelists .= "$elem ";
}
chomp $changelists;
if($changelists eq "")
{
print BUILD pack("N", 0);
print STDERR "You must specify changelist\(s\)\n";
return 0;
}
my $length = length $changelists;
print BUILD pack("N", $length);
print BUILD $changelists;
return 1;
}
sub endsubmit
{
print "Error running: $_[0]\n";
return 0;
}
sub submitopenfiles
{
my $dontsubmit = shift;
local $_;
my @files;
system("p4 revert -a > /dev/null");
open(P4, "p4 -ztag opened -c default |");
while (<P4>)
{
chomp;
push (@files, $_) if (s/^\.\.\. depotFile //);
}
close(P4);
if(!@files)
{
print STDERR "No changed files, nothing to submit\n";
return 1;
}
my $tmpfile = "submit.tmp";
# submit all the open files
open(TMP, ">" . $tmpfile);
print TMP "Change:\tnew\n";
print TMP "\nDescription:\n";
foreach (@_)
{
print TMP "\t", $_, "\n";
}
print TMP "\nFiles:\n";
foreach (@files)
{
print TMP "\t", $_, "\n";
}
close(TMP);
if ($dontsubmit)
{
open(P4, "p4 change -i < $tmpfile |") || return 0;
while(<P4>)
{
print STDERR "Successfully created changelist $1\n" if(/Change (\d+) created/);
}
close(P4);
}
else
{
open(P4, "p4 submit -i < $tmpfile |") || return 0;
while(<P4>)
{
print STDERR "Successfully submitted at changelist $1\n" if(/Change (\d+) submitted/);
}
close(P4);
}
return 0 if ($? != 0);
unlink($tmpfile);
return 1;
}
sub snapshot
{
my $dbSchema = shift @ARGV;
my $branch = shift @ARGV;
my $dontsubmit = 0;
my $snapshotLog = "";
my $buffer = "";
my $p4operation = "submit";
if (defined($ARGV[0]) && $ARGV[0] eq "dontsubmit")
{
$dontsubmit = 1;
$p4operation = "change";
shift @ARGV;
}
print BUILD pack("N", length $dbSchema);
print BUILD $dbSchema;
if(read(BUILD, $buffer, 1) != 1 || $buffer eq SNAPSHOT_FAILED)
{
print STDERR "Snapshot not created successfully on the build cluster\n";
return 0;
}
# Recieve files
my @worldSnapshots;
print STDERR "Snapshot generation complete.\n";
while(1)
{
return 0 if (read(BUILD, $buffer, 2*4) != 2*4);
my ($fileSize, $fileNameLength) = unpack("NN", $buffer);
# check if we are finished
last if($fileSize == 0 && $fileNameLength == 0);
my $localFileName;
return 0 if (read(BUILD, $localFileName, $fileNameLength) != $fileNameLength);
# first file sent will be the snapshot log
$snapshotLog = $localFileName if($snapshotLog eq "");
# add all ws files to the array
push @worldSnapshots, $localFileName if($localFileName =~ /\.ws$/);
# receive the binary bits for the file
print STDERR "Receiving $localFileName ($fileSize bytes)...";
unlink $localFileName;
open(F, ">" . $localFileName) || return endbootleginstall("could not open $localFileName for writing");
binmode(F);
while ($fileSize)
{
my $readSize = 16 * 1024;
$readSize = $fileSize if ($fileSize < $readSize);
my $readResult = read(BUILD, $buffer, $readSize);
return 0 if (!defined($readResult));
return 0 if ($readResult == 0);
print F $buffer;
$fileSize -= $readResult;
}
return 0 if ($fileSize != 0);
close(F);
print "done\n";
}
# Echo log to user
print STDERR "--- Start of snapshot log:\n";
system("cat $snapshotLog") == 0 || return 0;
print STDERR "--- End of snapshot log:\n";
# Only verify using STDIN if we are not being called by the build script
if($user ne "build_script_publish")
{
print STDERR "\nAre the world snapshots ok to do perforce $p4operation? (y/n)\n";
while(<STDIN>)
{
chomp;
if($_ eq "y" || $_ eq "Y")
{
last;
}
elsif($_ eq "n" || $_ eq "N")
{
return 1;
}
print STDERR "Please enter \'y\' or \'n\'\n";
}
}
# If we get here, we have decided to submit
print STDERR "Proceeding with $p4operation\n";
# Get a hash of the current world snapshots in perforce
my %ws;
open(FILES, "p4 files //depot/swg/$branch/data/sku.0/sys.client/built/game/snapshot/... |") || return endsubmit("p4 files");
while(<FILES>)
{
$ws{$1} = 1 if(/\/([^\/]+\.ws)#/);
}
close(FILES);
# Edit files and move to appropriate directory
system("p4 edit //depot/swg/$branch/data/sku.0/sys.client/built/game/snapshot/...") == 0 || return endsubmit("p4 edit snapshot dir");
foreach(@worldSnapshots)
{
system("p4 add //depot/swg/$branch/data/sku.0/sys.client/built/game/snapshot/$_") == 0 || return endsubmit("p4 add") if(!exists($ws{$_}));
copy($_, perforceWhere("//depot/swg/$branch/data/sku.0/sys.client/built/game/snapshot/$_")) || return endsubmit("moving *.ws to snapshot dir");
}
system("p4 edit //depot/swg/$branch/dsrc/sku.0/sys.client/built/game/snapshot/swg_object.txt") == 0 || return endsubmit("p4 edit swg_object.txt");
copy("swg_object.txt", perforceWhere("//depot/swg/$branch/dsrc/sku.0/sys.client/built/game/snapshot/swg_object.txt")) || return endsubmit("moving object file to swg_object.txt");
# create golddata text file
createGoldDataFile($dbSchema, $branch);
submitopenfiles($dontsubmit, "[automated]", "New snapshots for $branch from build_cluster_controller ($dbSchema)") || return endsubmit("p4 $p4operation");
return 1;
}
sub createGoldDataFile
{
my ($dbSchema, $branch) = @_;
my $goldDataFile = perforceWhere("//depot/swg/$branch/src/game/server/database/build/linux/golddata.txt");
system("p4 edit $goldDataFile");
open(GOLDDATA, "> $goldDataFile");
print GOLDDATA "$dbSchema\n";
close GOLDDATA;
system("p4 add $goldDataFile");
}
sub getbootlegversion
{
my $buffer;
return 0 if(read(BUILD, $buffer, 4) != 4);
my $length = unpack("N", $buffer);
return 0 if(read(BUILD, $buffer, $length) != $length);
if($length == 0)
{
print STDERR "Could not get build cluster bootleg version\n";
return 0;
}
print STDERR "Build cluster bootleg version is: $buffer\n";
return 1;
}
sub updatebootleg
{
my $branch = shift @ARGV;
# Get the number of the most recent bootleg
my $dir = "$candela/swo/builds/$branch";
my $buffer;
my $change = 0;
opendir DH, $dir or return 0;
foreach (readdir DH)
{
$change = $_ if(/^\d+$/ && -d ($dir."/".$_) && $_ > $change);
}
closedir DH;
return 0 if(!$change);
print STDERR "Most recent blessed bootleg is: $change\n";
# Send info to build cluster
print STDERR "Syncing build cluster to $change...\n";
print BUILD pack("N", $change);
return 0 if(read(BUILD, $buffer, 1) != 1 || $buffer ne UPDATE_BOOTLEG_STEP_OK);
print STDERR "Sync of build cluster complete.\n";
# Compress the server binaries
my $file = "servers_debug.tar.gz";
print STDERR "Compressing server binaries...\n";
system("tar --create --gzip --directory=$dir/$change/servers_debug --file=/tmp/$file .") == 0 || die "Failed to compress $dir/$change/servers_debug";
print STDERR "Compress server binaries complete.\n";
# Send file to build cluster
die "Can't find server zip file!\n" if (!-s "c:/cygwin/tmp/$file");
my $fileSize = -s "c:/cygwin/tmp/$file";
print STDERR "Sending file $file ($fileSize bytes)\n";
print BUILD pack("NN", $fileSize, length $file);
print BUILD $file;
open(F, "<c:/cygwin/tmp/$file");
binmode(F);
while ($fileSize)
{
my $buffer;
my $readSize = 16 * 1024;
$readSize = $fileSize if ($fileSize < $readSize);
my $readResult = read(F, $buffer, $readSize);
die "unexpected end of file" if (!defined($readResult));
die "did not read what we expected to" if ($readResult != $readSize);
print BUILD $buffer;
$fileSize -= $readResult;
}
die "copied all the bytes but not at EOF" if (!eof(F));
close(F);
# Cleanup
unlink "c:/cygwin/tmp/$file";
if(read(BUILD, $buffer, 1) != 1 || $buffer ne UPDATE_BOOTLEG_STEP_OK)
{
print "Failed while sending file.\n";
closedir DH;
return 0;
}
print "$file sent.\n";
print STDERR "Updating database on build cluster...\n";
return 0 if(read(BUILD, $buffer, 1) != 1 || $buffer ne UPDATE_BOOTLEG_STEP_OK);
print STDERR "Database update on build cluster complete.\n";
print STDERR "Syncing individual changelists on build cluster...\n";
my @syncChangelists;
open(SYNC, "$candela/SWO/builds/$branch/$change/sync.txt") || return 0;
while(<SYNC>)
{
chomp;
push @syncChangelists, $_;
}
close(SYNC);
print BUILD pack("N", length (join(" ", @syncChangelists)));
print BUILD join(" ", @syncChangelists);
return 0 if(read(BUILD, $buffer, 1) != 1 || $buffer ne UPDATE_BOOTLEG_STEP_OK);
print STDERR "Inidividual changelist sync complete.\n";
return 1;
}
# ======================================================================
# Main
# ======================================================================
&usage if(@ARGV == 0);
# Check to see if we're testing
if($ARGV[0] eq "vthakkar-box")
{
shift;
$buildCluster = "lin-vthakkar.station.sony.com";
}
$user = getuser();
$user = "build_script_publish" if(grep("-build_script_publish" eq $_, @ARGV));
checkarguments();
openbuildsocket();
sendstartinfo() || exitFailed();
while(@ARGV)
{
$option = shift @ARGV;
if($option eq "-restart")
{
print STDERR "Restarting build cluster...\n";
print BUILD COMMAND_RESTART;
}
elsif($option eq "-restart-login")
{
print STDERR "Restarting loginserver on build cluster...\n";
print BUILD COMMAND_RESTART_LOGIN;
}
elsif($option eq "-restart-nodes")
{
print STDERR "Restarting build cluster nodes...\n";
print BUILD COMMAND_RESTART_NODES;
}
elsif($option eq "-lock")
{
print STDERR "Locking build cluster...\n";
print BUILD COMMAND_LOCK;
}
elsif($option eq "-unlock")
{
print STDERR "Unlocking build cluster...\n";
print BUILD COMMAND_UNLOCK;
}
elsif($option eq "-update-bootleg")
{
print STDERR "Updating bootleg on build cluster...\n";
print BUILD COMMAND_UPDATE_BOOTLEG;
updatebootleg() || goto ERROR;
}
elsif($option eq "-content-sync")
{
print STDERR "Content syncing build cluster...\n";
print BUILD COMMAND_CONTENT_SYNC;
contentsync() || goto ERROR;
}
elsif($option eq "-sync-specified-changelists")
{
print STDERR "Syncing build cluster to changelists...\n";
print BUILD COMMAND_SYNC_SPECIFIED_CHANGELISTS;
syncspecifiedchangelists() || goto ERROR;
}
elsif($option eq "-snap")
{
print STDERR "Creating snapshot on build cluster...\n";
print BUILD COMMAND_SNAPSHOT;
snapshot() || goto ERROR;
}
elsif($option eq "-bootleg-version")
{
print STDERR "Checking bootleg version on build cluster...\n";
print BUILD COMMAND_BOOTLEG_VERSION;
getbootlegversion() || goto ERROR;
}
elsif($option eq "-free-object-ids")
{
print STDERR "Freeing object ids on build cluster...\n";
print BUILD COMMAND_FREE_OBJECT_IDS;
}
elsif($option eq "-build_script_publish")
{
next;
}
else
{
print STDERR "Error: cannot decipher option: $option\n";
goto FAIL;
}
ERROR:
my $success;
exitFailed() if(!read(BUILD, $success, 1));
if($success eq SUCCESSFULL_COMMAND)
{
print STDERR "Successfully completed $option\n\n";
}
else
{
print STDERR "Error encountered while running $option\n\n";
exitFailed();
}
}
FAIL:
sendendinfo();
close(BUILD);
exit($exitcode);