named_setup.in 6.69 KB
Newer Older
1
#!/usr/bin/perl -wT
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
3
4

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
6
7
8
# All rights reserved.
#

9
10
11
12
13
14
use English;
use Fcntl ':flock';

#
# Suck out virtual names and create CNAME map entries.
#
15
16
# This script always does the right thing, so it does not matter who calls it. 
#
17
18
19
20
21
22
23
# usage: named_setup
#

#
# Configure variables
#
my $TB		= "@prefix@";
24
my $TBOPS       = "@TBOPSEMAIL@";
25
my $USERS	= "@USERNODE@";
26
my $DISABLED    = "@DISABLE_NAMED_SETUP@";
27
28

my $mapdir      = "/etc/namedb";
29
30
31
32
my $mapfile	= "$mapdir/@OURDOMAIN@.db";
my $mapfileback	= "$mapfile.backup";
my $mapfilehead = "$mapfile.head";
my $mapfiletail = "$mapfile.tail";
33
34
35
36
my $lockfile    = "/var/tmp/testbed_named_lockfile";
my $dbg		= 0;
my @row;

37
38
39
40
41
# If we're disabled, just quietly exit
if ($DISABLED) {
    exit 0;
}

42
43
# We don't want to run this script unless its the real version.
if ($EUID != 0) {
44
45
    die("*** $0:\n".
	"    Must be root! Maybe its a development version?\n");
46
47
}
# XXX Hacky!
48
if (1 && $TB ne "/usr/testbed") {
49
50
    die("*** $0:\n".
	"    Wrong version. Maybe its a development version?\n");
51
52
}

53
54
55
56
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/sbin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

57
58
# Turn off line buffering on output
$| = 1;
59

60
# Testbed Support libraries
61
62
63
use lib "@prefix@/lib";
use libtestbed;
use libdb;
64
65
66
67
68
69
70

#
# We need to serialize this script to avoid a trashed map file. Use
# a dummy file in /var/tmp, opened for writing and flock'ed. 
#
open(LOCK, ">>$lockfile") || fatal("Couldn't open $lockfile\n");
$count = 0;
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
if (flock(LOCK, LOCK_EX|LOCK_NB) == 0) {
    #
    # If we don't get it the first time, we wait for:
    # 1) The lock to become free, in which case we do our thing
    # 2) The time on the lock to change, in which case we wait for that process
    #    to finish
    #
    my $oldlocktime = (stat(LOCK))[9];
    my $gotlock = 0;
    while (1) {
	print "Another named map update in progress, waiting for it to finish\n";
	if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
	    # OK, got the lock, we can do what we're supposed to
	    $gotlock = 1;
	    last;
	}
	$locktime = (stat(LOCK))[9];
	if ($locktime != $oldlocktime) {
	    $oldlocktime = $locktime;
	    last;
	}
	if ($count++ > 20)  {
	    fatal("Could not get the lock after a long time!\n");
	}
	sleep(1);
    }

    $count = 0;
    #
    # If we didn't get the lock, wait for the processes that did to finish
    #
    if (!$gotlock) {
103
104
105
106
107
108
109
110
	while (1) {
	    if ((stat(LOCK))[9] != $oldlocktime) {
		exit(0);
	    }
	    if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
		close(LOCK);
		exit(0);
	    }
111
	    if ($count++ > 20)  {
112
		fatal("Process with the lock didn't finish after a long time!\n");
113
114
	    }
	    sleep(1); 
115
116
	}

117
118
119
    }
}

120
121
122
123
124
125
126

#
# Perl-style touch(1)
#
my $now = time;
utime $now, $now, $lockfile;

127
128
129
130
131
132
133
134
135
#
# We stick the new map entries into the tail file. First zero it out.
#
open(MAP, ">$mapfiletail") || fatal("Couldn't open $mapfiletail\n");
print MAP "\n";
print MAP ";\n";
print MAP "; DO NOT EDIT below this point. Auto generated map entries!\n";
print MAP ";\n";
print MAP "\n";
136
print MAP "\$TTL\t1\n\n";
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
# First create the IA records for those nodes that have a named_root
# defined. We glean the IP for the node from the interfaces table.
#
$db_result =
    DBQueryFatal("select nt.type,nt.isremotenode,n.node_id,i.IP ".
		 "  from nodes as n ".
		 "left join node_types as nt on n.type=nt.type ".
		 "left join interfaces as i on n.node_id=i.node_id and ".
		 "     nt.control_net=i.card ".
		 "where nt.isvirtnode=0 and n.role='testnode' and ".
		 "      nt.isremotenode=1 and i.IP is not null ".
		 "order by nt.type,n.node_id");

if ($db_result->numrows > 0) {
    #
    # Create an IN record for each node. 
    #
    my $oldtype = "";
    
    while (@row = $db_result->fetchrow_array) {
	my $type    = $row[0];
	my $isremote= $row[1];
	my $node_id = $row[2];
	my $IP      = $row[3];

	if ($oldtype ne $type) {
	    print MAP ";\n";
	    print MAP "; $type nodes.\n";
	    print MAP ";\n";
	    
	    $oldtype = $type;
	}

	#
	# Skip local nodes for now since we also need to add reverse map
	# auto generation.
	# 
	if ($isremote) {
	    print MAP "$node_id\tIN\tA\t$IP\n";
	}
    }
}
print MAP "\n";

#
# Figure out the set of experiment nodes we are working on. These are the 
# nodes that have a vname in the reserved table. 
186
#
187
$db_result =
188
189
190
    DBQueryFatal("select r.node_id,pid,eid,vname,n.phys_nodeid ".
		 " from reserved as r ".
		 "left join nodes as n on n.node_id=r.node_id");
191
192
193
194
195
196
197
198
199

if ($db_result->numrows > 0) {
    #
    # Create a CNAME for each reserved node.
    #
    while (@row = $db_result->fetchrow_array) {
	my $node_id = $row[0];
	my $pid     = $row[1];
	my $eid     = $row[2];
200
	my $vname   = $node_id;
201
202
	my $physid  = $row[4];
	my $cname;
203

204
205
206
	if (defined($row[3])) {
	    $vname = $row[3];
	}
207
208

        #
209
210
211
212
        # VIRTNODE HACK: Map cname to underlying physnode, but first
	# spit out a vname for the virtnode name (no point in polluting
	# the map with a zillion cnames for nodes that do not actually
	# exist until they are allocated).
213
214
        #
	if (defined($row[4]) && $row[4] ne $node_id) {
215
216
217
218
	    $cname   = sprintf("%-40s", "$node_id");
	    printf MAP "$cname IN\tCNAME\t$physid\n";
	    
	    $node_id = $physid;
219
	}
220
	    
221
	$cname = sprintf("%-40s", "$vname.$eid.$pid");
222
223
224
225
226
227
228
229
230
231
232
	printf MAP "$cname IN\tCNAME\t$node_id\n";
    }
}

print MAP "\n";
close(MAP);

#
# Concat the head and tail files to create the new map.
#
if (-e $mapfile) {
233
    system("mv -f $mapfile $mapfileback") == 0 or
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
	fatal("Could not back up $mapfile to $mapfileback\n");
}

#
# Generate a warning so that no one tries to edit the file by hand
#
open(MAP, ">$mapfile") || fatal("Couldn't open $mapfile\n");
print MAP
    ";\n".
    "; ******************************************************************\n".
    "; DO NOT EDIT THIS FILE. IT IS A CREATION, A FIGMENT, A CONTRIVANCE!\n".
    ";\n".
    "; Edit the \"head\" file, then run ${TB}bin/named_setup.\n".
    "; ******************************************************************\n".
    ";\n";

#
# Now copy in the head part of the map, looking for the serial
# number so it can be bumped up.
#
open(MAPHEAD, "<$mapfilehead") || fatal("Couldn't open $mapfilehead\n");
while (<MAPHEAD>) {
    if ( /Serial Number/i ) {
	my $serial = `date +%s`;
	chop $serial;

	print MAP "\t\t\t$serial\t; Serial Number -- DO NOT EDIT\n";
    }
    else {
	print MAP "$_";
    }
}
close(MAPHEAD);
close(MAP);

#
# Now the tail of the map.
# 
system("cat $mapfiletail >> $mapfile") == 0 or
    fatal("Failed to concat $mapfiletail to $mapfile\n");

#
# This is better than HUPing the nameserver.
# 
system("named.reload > /dev/null") == 0 or
    fatal("named.reload failed!\n");

exit(0);

sub fatal {
    local($msg) = $_[0];

286
    SENDMAIL($TBOPS, "Named Setup Failed", $msg);
287
288
    die($msg);
}