-
Notifications
You must be signed in to change notification settings - Fork 0
/
Alfred.py
217 lines (180 loc) · 7.95 KB
/
Alfred.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
# -*- coding: utf-8 -*-
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Created on Thu Feb 15 11:10:10 2018
#
# @author: rhamilton
from __future__ import division, print_function, absolute_import
import os
import sys
import time
from ligmos.utils import classes, common, confparsers
from ligmos.workers import connSetup, workerSetup
from dataservants import alfred
# from dataservants import yvette
def defineActions():
"""
"""
# Renaming import to keep line length sensible
# yvetteR = yvette.remote
alfredT = alfred.tasks
# Set up the desired actions using a helpful class to pass things
# to each function/process more clearly.
#
# Note that we need to also update things per-instrument when
# inside the main loop via updateArguments()...it's just helpful to
# do the definitions out here for the constants and for clarity.
act1 = common.processDescription(func=alfredT.actionPing,
name='CheckPing',
timedelay=3.,
maxtime=120,
needSSH=False,
args=[],
kwargs={})
# act2 = common.processDescription(func=yvetteR.actionSpace,
# name='CheckFreeSpace',
# timedelay=3.,
# maxtime=120,
# needSSH=True,
# args=[],
# kwargs={})
# act3 = common.processDescription(func=yvetteR.actionStats,
# name='CheckStats',
# timedelay=3.,
# maxtime=120,
# needSSH=True,
# args=[],
# kwargs={})
# act4 = common.processDescription(func=yvetteR.actionProcess,
# name='CheckProcess',
# timedelay=3.,
# maxtime=120,
# needSSH=True,
# args=[],
# kwargs={})
# actions = [act1, act2, act3, act4]
actions = [act1]
return actions
def updateArguments(actions, iobj, args, baseYcmd, db=None):
"""
"""
# Update the functions with proper arguments.
# (opened SSH connection is added just before calling)
# act1 == pings
actions[0].args = [iobj]
actions[0].kwargs = {'db': db,
'debug': args.debug}
# # act2 == check free space
# actions[1].args = [baseYcmd, iobj]
# actions[1].kwargs = {'db': db,
# 'debug': args.debug}
# # act3 == check target CPU/RAM stats
# actions[2].args = [baseYcmd, iobj]
# actions[2].kwargs = {'db': db,
# 'debug': args.debug}
# # act4 == Check on process health
# actions[3].args = [baseYcmd, iobj]
# actions[3].kwargs = {'db': db,
# 'procName': iobj.procmon,
# 'debug': args.debug}
return actions
def main():
"""
"""
# Define the default files we'll use/look for. These are passed to
# the worker constructor (toServeMan).
conf = './config/alfred.conf'
passes = './config/passwords.conf'
logfile = '/tmp/alfred.log'
desc = 'Alfred: The Instrument Monitor'
eargs = alfred.parseargs.extraArguments
conftype = classes.hostTarget
# Note: We need to prepend the PATH setting here because some hosts
# (all recent OSes, really) have a more stringent SSHd config
# that disallows the setting of random environment variables
# at login, and I can't figure out the goddamn pty shell settings
# for Ubuntu (Vishnu) and OS X (xcam)
#
# Also need to make sure to use the relative path (~/) since OS X
# puts stuff in /Users/<username> rather than /home/<username>
# Messy but necessary due to how I'm doing SSH
baseYcmd = 'export PATH="~/miniconda3/bin:$PATH";'
baseYcmd += 'python ~/LIG/DataServants/Yvette.py'
baseYcmd += ' '
# Interval between successive runs of the instrument polling (seconds)
bigsleep = 60
# Total time for entire set of actions per instrument
alarmtime = 300
# config: dictionary of parsed config file
# comm: common block from config file
# args: parsed options
# runner: class that contains logic to quit nicely
config, comm, args, runner = workerSetup.toServeMan(conf,
passes,
logfile,
desc=desc,
extraargs=eargs,
conftype=conftype,
logfile=True)
# Parse the extra config file, but do it in a bit of a sloppy way
# that just fills out the class with whatever else
# we find in the file.
# REMEMBER there are two returns! The second contains any common
# items, and is just None if searchCommon is False...but it's
# always returned!
epings, _ = confparsers.parseConfig(args.extraPings, conftype,
passfile=None,
searchCommon=False,
enableCheck=True,
debug=args.debug)
# Actually define the function calls/references to functions
actions = defineActions()
# Get this PID for diagnostics
pid = os.getpid()
# Print the preamble of this particular instance
# (helpful to find starts/restarts when scanning thru logs)
common.printPreamble(pid, config)
# Check to see if there are any connections/objects to establish
idbs = connSetup.connIDB(comm)
# Semi-infinite loop
while runner.halt is False:
# This is a common core function that handles the actions and
# looping over each instrument. We keep the main while
# loop out here, though, so we can do stuff with the
# results of the actions from all the instruments.
_ = common.instLooper(config, runner, args,
actions, updateArguments,
baseYcmd,
db=idbs, alarmtime=alarmtime)
# Doing the extra pings as a side job/quickie
# No need to make this into a big to-do
if epings is not None:
for sect in epings:
pobj = epings[sect]
dbtag = pobj.database
db = idbs[dbtag]
res = alfred.tasks.actionPing(pobj, db=db, debug=args.debug)
print(res)
# After all the instruments are done, take a big nap
if runner.halt is False:
print("Starting a big sleep")
# Sleep for bigsleep, but in small chunks to check abort
for _ in range(bigsleep):
time.sleep(0.1)
if runner.halt is True:
print("halt requested while sleeping!")
print("issuing 'break'")
break
else:
print("runner.halt has been triggered!")
# The above loop is exited when someone sends SIGTERM
print("PID %d is now out of here!" % (pid))
# Return STDOUT and STDERR to their system defaults
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
print("STDOUT and STDERR reset.")
if __name__ == "__main__":
main()