Please note that the CVS and issue trackers have moved to GitHub. These Trac pages are no longer kept up-to-date.

root/seattle/trunk/deploymentscripts/missing_seattle_install.py@5637

Revision 2632, 7.6 KB (checked in by konp, 10 years ago)

Added v2 pubkey, and hashes.dict for 0.1l. Minor other changes.

Line 
1"""
2<Program Name>
3  missing_seattle_install.py
4
5<Started>
6  June 2009
7
8<Author>
9  n2k8000@u.washington.edu
10  Konstantin Pik
11
12<Purpose>
13  This file will read in a list file passed into it, and from that list it
14  will install seattle on all of those nodes.  The list file is to be in the
15  file format specified for .LIST files (!user:[username], followed by list of
16  IPs).
17
18<Usage>
19  python missing_seattle_install.py missing.list
20 
21  Note: missing.list is the default file name.
22 
23"""
24
25import thread
26import time
27import sys
28
29# for remote_shellexec
30import deploy_network
31import deploy_threading
32
33# the running thread counter
34thread_counter = 0
35
36# the lock on the thread_counter, just to make sure add/sub is atomic
37thread_lock = thread.allocate_lock()
38
39
40
41def get_remote_hosts_from_file(fname = 'missing.list'):
42  """
43  <Purpose>
44    Returns a list of the IP as read from file specified.
45
46    File format is:
47 
48    !user:[username]
49    [IPs]
50
51    [username] is the username that will be used until a new $username is
52      specified in the same format. NOTE: Username is case sensitive.
53    [IPs] are a list of IPs/hostname (one per line) associated with that
54      username
55
56  <Arguments>
57    fname:
58      Optional. The filename containing the IPs of the remote machines.  File
59      must be in the same directory as this script.
60   
61  <Exceptions>
62    Catches a thrown exception if the IP file is not found.
63
64  <Side Effects>
65    None.
66
67  <Returns>
68    Returns a list of tuples with (username, ip) on success, False on failure
69  """
70
71  # IP file must be in the same dir as this script
72  try:
73    file_of_ips = open(fname, 'r')
74  except Exception, e:
75    print 'Error: Are you missing your list of remote hosts? ('+str(e)+')'
76    file_of_ips.close()
77    return False
78  else:
79    # flag on whether we have any remote hosts (there are users, and comments
80    # in the file as well
81    have_one_ip = False
82
83    # initialize dict   
84    users_ip_tuple_list = []
85
86    current_username = ''
87
88    # Python docs suggest doing this instead of reading in whole file into mem:
89    for line in file_of_ips:
90
91      # if first chars match what we want ('!user:' is 6 chars long)
92      if line[0:6].lower() == '!user:':
93        # grab everything after the '!user:' string
94        # -1 so we drop the \n and leading/trailing spaces
95        current_username = line[6:-1].strip()
96      else:
97        # ignore blank lines and spaces
98        if line.strip('\n '):
99          # and ignore comments (lines starting with #)
100          if line.strip('\n ')[0] != '#':
101            # if we get here, then we have an IP so we need to  check that
102            # user is not empty.. log err if it is and complain.
103            if not current_username:
104              print 'Critical Error: No username specified for remote host group!'
105              file_of_ips.close()
106              return False
107
108            # add (username, remote_host) pair
109            users_ip_tuple_list.append((current_username, line.rstrip('\n ')))
110            # set flag that we have at least one ip
111            have_one_ip = True
112
113    # return true only if we have at least ONE ip that we added to the list
114    # and not just a bunch of users
115    if have_one_ip:
116      # lets make the list a set, which is a cheap way of getting rid of
117      # duplicates, then cast back to list.
118      finalized_list = list(set(users_ip_tuple_list))
119      print "Found "+str(len(finalized_list))+" unique hosts to connect to."
120      file_of_ips.close()
121      return finalized_list
122    file_of_ips.close()
123    return False
124
125 
126
127def format_print(out, err):
128  """
129  <Purpose>
130    Will print out the non-empty out/err strings once they're properly
131    formatted. Intended to format stdout and stderr. Also will print to
132    missing.log
133
134  <Arguments>
135    out:
136      stdout
137    err:
138      std error
139
140  <Exceptions>
141    None.
142
143  <Side Effects>
144    None.
145
146  <Returns>
147    None.
148  """
149  try:
150    out = out.strip('\n\r ')
151    err = err.strip('\n\r ')
152   
153    logfilehandle = open('missing.log', 'a')
154   
155    if out:
156      print out
157      logfilehandle.write(out+'\n')
158    if err:
159      print err
160      logfilehandle.write(err+'\n')
161     
162    logfilehandle.close()
163  except Exception, e:
164    print 'Error while writing file and/or formatting data'
165    print e
166   
167  return
168
169def worker(cmd, username, host):
170  """
171  <Purpose>
172    Worker thread that makes calls to remote_shellexec and increments
173    the running thread counter until the thread has finished.
174
175  <Arguments>
176    cmd:
177      the command string to execute on the machine
178    username:
179      the username to log in as
180    host:
181      the remote hostname/ip to install on.
182
183  <Exceptions>
184    None.
185
186  <Side Effects>
187    None.
188
189  <Returns>
190    None.
191  """
192 
193  global thread_counter, thread_lock
194  # do an atomic add on the number of threads running
195  thread_lock.acquire()
196  thread_counter += 1
197  thread_lock.release()
198 
199  out, err, retcode = deploy_network.remote_shellexec(cmd, username, host)
200 
201  format_print('|\n\n Log from node: '+host+'\n'+out, err)
202 
203  # do an atomic subtract on the number of threads running
204  thread_lock.acquire()
205  thread_counter -= 1
206  thread_lock.release()
207
208 
209 
210def main():
211  """
212  <Purpose>
213    Entry point into the program.  Reads the hosts that need installing
214    from file and then starts the threads that will take care of downloading
215    and installing seattle.  Then waits for all threads to finish.  This takes
216    a while as an RSA key needs to be generated during each install.
217
218  <Arguments>
219    None
220
221  <Exceptions>
222    Possible exception when launching new threads.
223
224  <Side Effects>
225    None.
226
227  <Returns>
228    None.
229  """
230 
231  # start the timeout monitor thread
232  deploy_threading.init()
233 
234  # the fn of the file that contains the list of nodes we'll be using
235  nodelist_fn = ''
236 
237  # did we get a parameter passed in? if so that's our fn
238  if len(sys.argv) > 1:
239    nodelist_fn = sys.argv[1]
240    print 'Using '+nodelist_fn+' filename to read in hostnames'
241  else:
242    print 'Using default missing.list filename to read in hostnames'
243   
244  # get hosts from file
245  if nodelist_fn:
246    hosts = get_remote_hosts_from_file(nodelist_fn)
247  else: # use default fn
248    hosts = get_remote_hosts_from_file()
249 
250  # if we have hostnames
251  if hosts:
252    # build up a command string that'll download and install seattle
253    cmd_list = []
254   
255    # try to uninstall seattle_repy, then remove dir
256    cmd_list.append('cd seattle_repy; ./stop_seattle.sh; ./uninstall.sh')
257    # 1. Remove old file, and download the file
258    cmd_list.append('cd ~; rm -rf seattle_linux.tgz; rm -rf seattle_repy')
259   
260    cmd_list.append('wget https://seattlegeni.cs.washington.edu/geni/download/flibble/seattle_linux.tgz')
261   
262   
263    # 2. Untar
264    cmd_list.append('tar -xf seattle_linux.tgz')
265   
266    # 3. Change into seattle_repy directory and execute python install.py and start seattle
267    cmd_list.append('cd seattle_repy; python install.py; ./start_seattle.sh ')
268   
269    # merge into a command string
270    cmd_str = '; '.join(cmd_list)
271   
272    while hosts:
273      # 8 is the number of threads we'll launch
274      while thread_counter < 8:
275        # grab a tuple from hosts array
276        host = hosts.pop()
277       
278        # separate it out for clarity
279        user = host[0]
280        machine = host[1]
281       
282        print 'Starting on '+str(machine)
283         
284        try:
285          # start thread and then give it some time to boot up
286          thread.start_new_thread(worker, (cmd_str, user, machine,))
287          time.sleep(.2)
288        except Exception, e:
289          print "Exception while trying to start worker thread"
290          print e
291          return
292     
293    # wait until we're done...
294    while thread_counter > 0:
295      time.sleep(1)
296     
297     
298     
299if __name__ == "__main__":
300  main()
Note: See TracBrowser for help on using the browser.