1 #!/usr/bin/env /usr/bin/plcsh
3 # Generates static versions of expensive web pages
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2005 The Trustees of Princeton University
17 SCRIPT_PID_FILE= "/var/run/gen-static-content.pid"
19 # where to store the generated files
20 GENERATED_OUTPUT_PATH= '/var/www/html/generated'
22 # this php block, if put at the top of the files,
23 # will enable them to be downloaded without the php
27 if( isset($_GET['disablephp']) )
40 # return a php page that has node and site counts in it
41 def GetCountsFileContent(f):
42 f.write( DISABLE_PHP_BLOCK )
45 node_count = len(all_nodes)
46 f.write( "$node_count= %s;\n" % node_count )
48 site_count= len(all_sites)
49 f.write( "$site_count= %s;\n" % site_count )
54 # generate a plain text file in ~/.ssh/known_hosts format
56 time_generated= time.strftime("%a, %d %b %Y %H:%M:%S")
58 f.write( DISABLE_PHP_BLOCK )
61 f.write( "$node_list_generated_time= '%s';\n" % time_generated )
62 f.write( "header('Content-type: text/plain');\n" )
67 for node in all_nodes:
68 hostname = node['hostname']
69 ssh_rsa_key = node['ssh_rsa_key']
73 f.write( "%s %s\n" % (hostname, ssh_rsa_key) )
75 f.write( "%s %s\n" % (ip, ssh_rsa_key) )
78 # return php content that includes all the node lists
79 def GetNodeListsContent(f):
80 time_generated= time.strftime("%a, %d %b %Y %H:%M:%S")
82 f.write( DISABLE_PHP_BLOCK )
85 f.write( "$node_list_generated_time= '%s';\n" % time_generated )
87 # Nodes with primary IP addresses in boot state
88 nodes_in_boot = filter(lambda node: node['boot_state'] == "boot" and node['ip'],
92 all_hosts = [node['hostname'] for node in nodes_in_boot]
93 f.write( "if( $which_node_list == 'all_hosts' )\n" )
96 f.write( "\n".join(all_hosts) + "\n" )
101 all_ips = [node['ip'] for node in nodes_in_boot]
102 f.write( "elseif( $which_node_list == 'all_ips' )\n" )
105 f.write( "\n".join(all_ips) + "\n" )
110 etc_hosts = [node['ip'] + "\t" + node['hostname'] for node in nodes_in_boot]
111 f.write( "elseif( $which_node_list == 'etc_hosts' )\n" )
114 # Create a localhost entry for convenience
115 f.write( "127.0.0.1\tlocalhost.localdomain localhost\n" )
116 f.write( "\n".join(etc_hosts) + "\n" )
120 for group in ['Alpha', 'Beta']:
121 if not node_group_nodes.has_key(group):
122 node_group_nodes[group] = []
124 # Group nodes with primary IP addresses in boot state
125 group_nodes_in_boot = filter(lambda node: node['boot_state'] == "boot" and node['ip'],
126 node_group_nodes[group])
129 group_hosts = [node['hostname'] for node in group_nodes_in_boot]
130 f.write( "elseif( $which_node_list == '%s_hosts' )\n" % group.lower() )
133 f.write( "\n".join(group_hosts) + "\n" )
138 group_ips = [node['ip'] for node in group_nodes_in_boot]
139 f.write( "elseif( $which_node_list == '%s_ips' )\n" % group.lower() )
142 f.write( "\n".join(group_ips) + "\n" )
146 # All production nodes (nodes not in Alpha or Beta)
147 production_nodes_in_boot = filter(lambda node: node not in node_group_nodes['Alpha'] and \
148 node not in node_group_nodes['Beta'],
151 production_hosts = [node['hostname'] for node in production_nodes_in_boot]
152 f.write( "elseif( $which_node_list == 'production_hosts' )\n" )
155 f.write( "\n".join(production_hosts) + "\n" )
159 production_ips = [node['ip'] for node in production_nodes_in_boot]
160 f.write( "elseif( $which_node_list == 'production_ips' )\n" )
163 f.write( "\n".join(production_ips) + "\n" )
169 def GetPlanetFlowStats(f):
170 if hasattr(config, 'PLANETFLOW_BASE'):
171 url = "http://" + config.PLANETFLOW_BASE
175 # Slices to calculate detailed statistics for
198 socket.setdefaulttimeout(3600)
200 url = url + '/slice.php?csv=1&start_time=2+days+ago'
202 url = url + '&slices[]=' + '&slices[]='.join(slices)
203 stats = urllib2.urlopen(url)
204 fields = ['slice', 'flows', 'packets', 'bytes', 'src_ips',
205 'dst_ips', 'top_dst_ip', 'top_dst_ip_bytes']
206 rows = csv.DictReader(stats, fields)
208 f.write("$planetflow = array(\n")
210 if row.has_key('slice'):
211 f.write("'%s' => array(\n" % row['slice'])
213 if row.has_key(field) and \
214 row[field] is not None and \
216 if type(row[field]) == type(0):
217 f.write("\t'%s' => %d,\n" % (field, int(row[field])))
219 f.write("\t'%s' => '%s',\n" % (field, row[field]))
227 # update the node distribution map
228 datadir = '/var/www/html/plot-latlong'
230 # plot-latlong looks for .mapinfo and .mapimages in $HOME
231 os.environ['HOME'] = datadir
233 if hasattr(config, 'PLC_WWW_MAPIMAGE'):
234 image = config.PLC_WWW_MAPIMAGE
240 os.popen2('perl ' + datadir + os.sep + 'plot-latlong -m "%s" -s 3' % image)
242 for site in all_sites:
243 if site['latitude'] and site['longitude']:
244 child_stdin.write("%f %f\n" % \
245 (site['latitude'], site['longitude']))
248 map = file(GENERATED_OUTPUT_PATH + os.sep + image + '.png', 'w')
249 map.write(child_stdout.read())
254 # which files to generate, and the functions in
255 # this script to call to get the content for
257 ('_gen_counts.php',GetCountsFileContent),
258 ('_gen_node_lists.php',GetNodeListsContent),
259 ('_gen_known_hosts.php',GetHostKeys),
260 ('_gen_planetflow.php',GetPlanetFlowStats),
265 if __name__ == '__main__':
267 # see if we are already running by checking the existance
268 # of a PID file, and if it exists, attempting a test kill
269 # to see if the process really does exist. If both of these
272 if os.access(SCRIPT_PID_FILE, os.R_OK):
273 pid= string.strip(file(SCRIPT_PID_FILE).readline())
275 if os.system("/bin/kill -0 %s > /dev/null 2>&1" % pid) == 0:
278 # write out our process id
279 pidfile= file( SCRIPT_PID_FILE, 'w' )
280 pidfile.write( "%d\n" % os.getpid() )
284 # Get all nodes and sites
286 GetNodes(None, ['node_id', 'hostname', 'boot_state', 'ssh_rsa_key', 'interface_ids'])
287 GetInterfaces(None, ['interface_id', 'ip', 'is_primary'])
288 GetSites(None, ['site_id', 'latitude', 'longitude'])
289 GetNodeGroups(None, ['nodegroup_id', 'tagname', 'node_ids'])
290 (all_nodes, all_nodenetworks, all_sites, all_groups) = commit()
292 all_nodenetworks = dict([(nodenetwork['interface_id'], nodenetwork) \
293 for nodenetwork in all_nodenetworks])
295 # Set primary IP, if any
296 for node in all_nodes:
298 for interface_id in node['interface_ids']:
300 nodenetwork = all_nodenetworks[interface_id]
301 if nodenetwork['is_primary']:
302 node['ip'] = nodenetwork['ip']
304 except IndexError, KeyError:
307 # Get list of nodes in each node group
308 for group in all_groups:
309 nodes_in_group = filter(lambda node: node['node_id'] in group['node_ids'], all_nodes)
310 node_group_nodes[group['tagname']] = nodes_in_group
312 # generate the static content files
313 for (file_name,func) in STATIC_FILE_LIST:
314 if file_name is not None:
316 output_file_path= "%s/%s" % (GENERATED_OUTPUT_PATH,file_name)
317 tmp_output_file_path= output_file_path + '.tmp'
318 tmp_output_file= codecs.open( tmp_output_file_path, encoding = 'utf-8', mode = "w" )
320 print( "Unable to open file %s for writing." % output_file_path )
324 func(tmp_output_file)
325 tmp_output_file.flush()
326 shutil.copyfile( tmp_output_file_path, output_file_path )
328 print "Unable to get content for file: %s" % file_name, e
330 traceback.print_exc()
332 tmp_output_file.close()
333 tmp_output_file= None
334 os.unlink( tmp_output_file_path )
338 # remove the PID file
339 os.unlink( SCRIPT_PID_FILE )