forked from instana/python-sensor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfsm.py
135 lines (110 loc) · 4.01 KB
/
fsm.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
import subprocess
import os
import psutil
import threading as t
import fysom as f
import instana.log as l
import instana.agent_const as a
class Discovery(object):
pid = 0
name = None
args = None
def __init__(self, **kwds):
self.__dict__.update(kwds)
def to_dict(self):
kvs = dict()
kvs['pid'] = self.pid
kvs['name'] = self.name
kvs['args'] = self.args
return kvs
class Fsm(object):
RETRY_PERIOD = 30
agent = None
fsm = None
timer = None
def __init__(self, agent):
l.info("Stan is on the scene. Starting Instana instrumentation.")
l.debug("initializing fsm")
self.agent = agent
self.fsm = f.Fysom({
"initial": "lostandalone",
"events": [
("startup", "*", "lostandalone"),
("lookup", "lostandalone", "found"),
("announce", "found", "announced"),
("ready", "announced", "good2go")],
"callbacks": {
"onlookup": self.lookup_agent_host,
"onannounce": self.announce_sensor,
"onchangestate": self.printstatechange}})
def printstatechange(self, e):
l.debug('========= (%i#%s) FSM event: %s, src: %s, dst: %s ==========' % \
(os.getpid(), t.current_thread().name, e.event, e.src, e.dst))
def reset(self):
self.fsm.lookup()
def lookup_agent_host(self, e):
if self.agent.sensor.options.agent_host != "":
host = self.agent.sensor.options.agent_host
else:
host = a.AGENT_DEFAULT_HOST
h = self.check_host(host)
if h == a.AGENT_HEADER:
self.agent.set_host(host)
self.fsm.announce()
else:
host = self.get_default_gateway()
if host:
self.check_host(host)
if h == a.AGENT_HEADER:
self.agent.set_host(host)
self.fsm.announce()
else:
l.error("Cannot lookup agent host. Scheduling retry.")
self.schedule_retry(self.lookup_agent_host, e, "agent_lookup")
return False
return True
def get_default_gateway(self):
l.debug("checking default gateway")
try:
proc = subprocess.Popen(
"/sbin/ip route | awk '/default/ { print $3 }'", stdout=subprocess.PIPE)
return proc.stdout.read()
except Exception as e:
l.error(e)
return None
def check_host(self, host):
l.debug("checking host", host)
(_, h) = self.agent.request_header(
self.agent.make_host_url(host, "/"), "GET", "Server")
return h
def announce_sensor(self, e):
l.debug("announcing sensor to the agent")
p = psutil.Process(os.getpid())
d = Discovery(pid=p.pid,
name=p.cmdline()[0],
args=p.cmdline()[1:])
(b, _) = self.agent.request_response(
self.agent.make_url(a.AGENT_DISCOVERY_URL), "PUT", d)
if not b:
l.error("Cannot announce sensor. Scheduling retry.")
self.schedule_retry(self.announce_sensor, e, "announce")
return False
else:
self.agent.set_from(b)
self.fsm.ready()
l.warn("Host agent available. We're in business. (Announced pid: %i)" % p.pid)
return True
def schedule_retry(self, fun, e, name):
l.debug("Scheduling: " + name)
self.timer = t.Timer(self.RETRY_PERIOD, fun, [e])
self.timer.daemon = True
self.timer.name = name
self.timer.start()
l.debug('Threadlist: %s', str(t.enumerate()))
def test_agent(self, e):
l.debug("testing communication with the agent")
(b, _) = self.agent.head(self.agent.make_url(a.AGENT_DATA_URL))
if not b:
self.schedule_retry(self.test_agent, e, "agent test")
else:
self.fsm.test()