-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathupdate_crontab_entry.py
220 lines (163 loc) · 6.05 KB
/
update_crontab_entry.py
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
"""
<Program Name>
update_crontab_entry.py
<Started>
October 2, 2009
<Author>
Zachary Boka
<Purpose>
Modifies the current crontab entry to reflect the new 2009 seattle crontab
entry which uses the "@reboot" directive which will use cron to start seattle
only upon machine boot. If there is currently no entry for seattle in the
crontab, then this function does not add nor modify the crontab.
"""
# Python modules
import subprocess
import os
import tempfile
# Seattle modules
import nonportable
import servicelogger
SEATTLE_FILES_DIR = os.path.realpath(".")
def find_mount_point_of_seattle_dir():
"""
<Purpose>
Find the mount point of the directory in which seattle is currently being
installed.
<Arguments>
None.
<Excpetions>
None.
<Side Effects>
None.
<Return>
The mount point for the directory in which seattle is currently being
installed.
"""
potential_mount_point = SEATTLE_FILES_DIR
# To prevent a potential, yet unlikely, infinite loop from occuring, exit the
# while loop if the current potential mount point is the same as
# os.path.dirname(potential_mount_point).
while not os.path.ismount(potential_mount_point) \
and potential_mount_point != os.path.dirname(potential_mount_point):
potential_mount_point = os.path.dirname(potential_mount_point)
return potential_mount_point
def modify_seattle_crontab_entry():
"""
<Purpose>
Replaces the current seattle crontab entry, if it exists, with the updated
entry which uses the directive @reboot to specify that cron should only
start seattle at machine boot.
<Arguments>
None.
<Exceptions>
OSError if cron is not installed on this system?
IOError if there is a problem creating or writing to the temporary file?
<Side Effects>
Modifies the seattle crontab entry, should it exist.
<Returns>
True if modification succeeded,
False otherwise.
"""
try:
crontab_contents = subprocess.Popen(["crontab","-l"],stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
crontab_contents_stdout = crontab_contents.stdout
except Exception,e:
# User does not have access to crontab, so do nothing and return.
return False
else:
# Get the service vessel where any cron errors or output for seattle will
# be written.
service_vessel = servicelogger.get_servicevessel()
# Get the mount point for the directory in which seattle is installed.
mount_point = find_mount_point_of_seattle_dir()
# Create the replacement crontab entry.
seattle_files_dir = os.path.realpath(".")
cron_line_entry = '@reboot if [ -e "' + SEATTLE_FILES_DIR + os.sep \
+ 'start_seattle.sh" ]; then "' + SEATTLE_FILES_DIR + os.sep \
+ 'start_seattle.sh" >> "' + SEATTLE_FILES_DIR + os.sep \
+ service_vessel + '/cronlog.txt" 2>&1; elif [ "`mount | ' \
+ 'grep -e \'[ ]' + mount_point + '[/]*[ ]\'`" = "" ]; then ' \
+ 'while [ "`mount | grep -e \'[ ]' + mount_point \
+ '[/]*[ ]\'`" = ""]; do sleep 60s; done && "' + SEATTLE_FILES_DIR \
+ os.sep + 'start_seattle.sh" >> "' + SEATTLE_FILES_DIR \
+ os.sep + service_vessel + '/cronlog.txt" 2>&1; else ' \
+ 'modifiedCrontab=`mktemp -t tempcrontab.XXXXX` && crontab -l | ' \
+ 'sed \'/start_seattle.sh/d\' > ${modifiedCrontab} && ' \
+ 'crontab ${modifiedCrontab} && rm -rf ${modifiedCrontab}; fi' \
+ os.linesep
# Generate a temporary crontab file, and only add the new seattle crontab
# entry if there is currently an outdated seattle crontab entry.
temp_crontab_file = tempfile.NamedTemporaryFile()
outdated_seattle_entry_existed = False
for line in crontab_contents_stdout:
if "start_seattle.sh" in line:
line = cron_line_entry
outdated_seattle_entry_existed = True
temp_crontab_file.write(line)
temp_crontab_file.flush()
# If there was no outdated seattle entry, close the temporary file and
# return.
if not outdated_seattle_entry_existed:
temp_crontab_file.close()
return
# Now, replace the crontab with that temp file and remove(close) the
# tempfile.
replace_crontab = subprocess.Popen(["crontab",temp_crontab_file.name],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
replace_crontab.wait()
temp_crontab_file.close()
# Lastly, check that the modificaiton succeeded.
return check_modification_succeeded()
def check_modification_succeeded():
"""
<Purpose>
Checks that the modified crontab entry for the 2009 installer succeeded.
<Arguments>
None.
<Exceptions>
OSError if cron is not installed on this system?
IOError if there is a problem creating or writing to the temporary file?
<Side Effects>
None.
<Returns>
True if modification succeeded,
False otherwise.
"""
try:
modified_crontab_contents = \
subprocess.Popen(["crontab","-l"],stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
modified_crontab_contents_stdout = modified_crontab_contents.stdout
except Exception,e:
# User does not have access to crontab, so return False.
return False
else:
for line in modified_crontab_contents_stdout:
if "@reboot" in line and "start_seattle.sh" in line:
return True
# Reaching this point means that the keywords in the updated seattle crontab
# entry were not found, meaning the current crontab entry was not updated.
return False
def main():
"""
<Purpose>
Test the operating system. If this a Linux or Darwin machine, change the
seattle crontab entry if it exists.
<Arguments>
None.
<Exceptions>
None.
<Side Effects>
Modifies the seattle crontab entry if it exists.
<Returns>
None.
"""
if not nonportable.ostype == "Linux" and not nonportable.ostype == "Darwin":
return
else:
modified_crontab = modify_seattle_crontab_entry()
if __name__ == "__main__":
main()