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
14 import urllib.request, urllib.error, urllib.parse
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 = [node for node in all_nodes if node['boot_state'] == "boot" and node['ip']]
91 all_hosts = [node['hostname'] for node in nodes_in_boot]
92 f.write( "if( $which_node_list == 'all_hosts' )\n" )
95 f.write( "\n".join(all_hosts) + "\n" )
100 all_ips = [node['ip'] for node in nodes_in_boot]
101 f.write( "elseif( $which_node_list == 'all_ips' )\n" )
104 f.write( "\n".join(all_ips) + "\n" )
109 etc_hosts = [node['ip'] + "\t" + node['hostname'] for node in nodes_in_boot]
110 f.write( "elseif( $which_node_list == 'etc_hosts' )\n" )
113 # Create a localhost entry for convenience
114 f.write( "127.0.0.1\tlocalhost.localdomain localhost\n" )
115 f.write( "\n".join(etc_hosts) + "\n" )
119 for group in ['Alpha', 'Beta']:
120 if group not in node_group_nodes:
121 node_group_nodes[group] = []
123 # Group nodes with primary IP addresses in boot state
124 group_nodes_in_boot = [node for node in node_group_nodes[group] if node['boot_state'] == "boot" and node['ip']]
127 group_hosts = [node['hostname'] for node in group_nodes_in_boot]
128 f.write( "elseif( $which_node_list == '%s_hosts' )\n" % group.lower() )
131 f.write( "\n".join(group_hosts) + "\n" )
136 group_ips = [node['ip'] for node in group_nodes_in_boot]
137 f.write( "elseif( $which_node_list == '%s_ips' )\n" % group.lower() )
140 f.write( "\n".join(group_ips) + "\n" )
144 # All production nodes (nodes not in Alpha or Beta)
145 production_nodes_in_boot = [node for node in nodes_in_boot if node not in node_group_nodes['Alpha'] and \
146 node not in node_group_nodes['Beta']]
148 production_hosts = [node['hostname'] for node in production_nodes_in_boot]
149 f.write( "elseif( $which_node_list == 'production_hosts' )\n" )
152 f.write( "\n".join(production_hosts) + "\n" )
156 production_ips = [node['ip'] for node in production_nodes_in_boot]
157 f.write( "elseif( $which_node_list == 'production_ips' )\n" )
160 f.write( "\n".join(production_ips) + "\n" )
166 def GetPlanetFlowStats(f):
167 if hasattr(config, 'PLANETFLOW_BASE'):
168 url = "http://" + config.PLANETFLOW_BASE
172 # Slices to calculate detailed statistics for
195 socket.setdefaulttimeout(3600)
197 url = url + '/slice.php?csv=1&start_time=2+days+ago'
199 url = url + '&slices[]=' + '&slices[]='.join(slices)
200 stats = urllib.request.urlopen(url)
201 fields = ['slice', 'flows', 'packets', 'bytes', 'src_ips',
202 'dst_ips', 'top_dst_ip', 'top_dst_ip_bytes']
203 rows = csv.DictReader(stats, fields)
205 f.write("$planetflow = array(\n")
208 f.write("'%s' => array(\n" % row['slice'])
210 if field in row and \
211 row[field] is not None and \
213 if type(row[field]) == type(0):
214 f.write("\t'%s' => %d,\n" % (field, int(row[field])))
216 f.write("\t'%s' => '%s',\n" % (field, row[field]))
224 # update the node distribution map
225 datadir = '/var/www/html/plot-latlong'
227 # plot-latlong looks for .mapinfo and .mapimages in $HOME
228 os.environ['HOME'] = datadir
230 if hasattr(config, 'PLC_WWW_MAPIMAGE'):
231 image = config.PLC_WWW_MAPIMAGE
237 os.popen2('perl ' + datadir + os.sep + 'plot-latlong -m "%s" -s 3' % image)
239 for site in all_sites:
240 if site['latitude'] and site['longitude']:
241 child_stdin.write("%f %f\n" % \
242 (site['latitude'], site['longitude']))
245 map = file(GENERATED_OUTPUT_PATH + os.sep + image + '.png', 'w')
246 map.write(child_stdout.read())
251 # which files to generate, and the functions in
252 # this script to call to get the content for
254 ('_gen_counts.php',GetCountsFileContent),
255 ('_gen_node_lists.php',GetNodeListsContent),
256 ('_gen_known_hosts.php',GetHostKeys),
257 ('_gen_planetflow.php',GetPlanetFlowStats),
262 if __name__ == '__main__':
264 # see if we are already running by checking the existance
265 # of a PID file, and if it exists, attempting a test kill
266 # to see if the process really does exist. If both of these
269 if os.access(SCRIPT_PID_FILE, os.R_OK):
270 pid= string.strip(file(SCRIPT_PID_FILE).readline())
272 if os.system("/bin/kill -0 %s > /dev/null 2>&1" % pid) == 0:
275 # write out our process id
276 pidfile= file( SCRIPT_PID_FILE, 'w' )
277 pidfile.write( "%d\n" % os.getpid() )
281 # Get all nodes and sites
283 GetNodes(None, ['node_id', 'hostname', 'boot_state', 'ssh_rsa_key', 'interface_ids'])
284 GetInterfaces(None, ['interface_id', 'ip', 'is_primary'])
285 GetSites(None, ['site_id', 'latitude', 'longitude'])
286 GetNodeGroups(None, ['nodegroup_id', 'tagname', 'node_ids'])
287 (all_nodes, all_nodenetworks, all_sites, all_groups) = commit()
289 all_nodenetworks = dict([(nodenetwork['interface_id'], nodenetwork) \
290 for nodenetwork in all_nodenetworks])
292 # Set primary IP, if any
293 for node in all_nodes:
295 for interface_id in node['interface_ids']:
297 nodenetwork = all_nodenetworks[interface_id]
298 if nodenetwork['is_primary']:
299 node['ip'] = nodenetwork['ip']
301 except IndexError as KeyError:
304 # Get list of nodes in each node group
305 for group in all_groups:
306 nodes_in_group = [node for node in all_nodes if node['node_id'] in group['node_ids']]
307 node_group_nodes[group['tagname']] = nodes_in_group
309 # generate the static content files
310 for (file_name,func) in STATIC_FILE_LIST:
311 if file_name is not None:
313 output_file_path= "%s/%s" % (GENERATED_OUTPUT_PATH,file_name)
314 tmp_output_file_path= output_file_path + '.tmp'
315 tmp_output_file= codecs.open( tmp_output_file_path, encoding = 'utf-8', mode = "w" )
316 except IOError as err:
317 print(( "Unable to open file %s for writing." % output_file_path ))
321 func(tmp_output_file)
322 tmp_output_file.flush()
323 shutil.copyfile( tmp_output_file_path, output_file_path )
324 except Exception as e:
325 print("Unable to get content for file: %s" % file_name, e)
327 traceback.print_exc()
329 tmp_output_file.close()
330 tmp_output_file= None
331 os.unlink( tmp_output_file_path )
335 # remove the PID file
336 os.unlink( SCRIPT_PID_FILE )