Licensing information
[deliverable/lttng-ivc.git] / lttng_ivc / utils / utils.py
1 # Copyright (c) 2017 Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # of this software and associated documentation files (the "Software"), to deal
5 # in the Software without restriction, including without limitation the rights
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # copies of the Software, and to permit persons to whom the Software is
8 # furnished to do so, subject to the following conditions:
9 #
10 # The above copyright notice and this permission notice shall be included in all
11 # copies or substantial portions of the Software.
12 #
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 # SOFTWARE.
20
21 import signal
22 import hashlib
23 import os
24 import time
25 import socket
26
27 from lxml import etree
28 from contextlib import closing
29
30
31 def line_count(file_path):
32 line_count = 0
33 with open(file_path) as f:
34 for line in f:
35 line_count += 1
36 return line_count
37
38
39 def sha256_checksum(filename, block_size=65536):
40 sha256 = hashlib.sha256()
41 with open(filename, 'rb') as f:
42 for block in iter(lambda: f.read(block_size), b''):
43 sha256.update(block)
44 return sha256.hexdigest()
45
46
47 # TODO: timeout as a parameter or Settings
48 # TODO: Custom exception
49 def wait_for_file(path):
50 i = 0
51 timeout = 60
52 while not os.path.exists(path):
53 time.sleep(1)
54 i = i + 1
55 if i > timeout:
56 raise Exception("File still does not exists. Timeout expired")
57
58
59 # TODO: find better exception
60 def create_empty_file(path):
61 if os.path.exists(path):
62 raise Exception("Path already exist")
63 open(path, 'w').close()
64
65
66 def __dummy_sigusr1_handler():
67 pass
68
69
70 def sessiond_spawn(runtime, opt_args=""):
71 agent_port = find_free_port()
72 previous_handler = signal.signal(signal.SIGUSR1, __dummy_sigusr1_handler)
73 cmd = "lttng-sessiond -vvv --verbose-consumer -S --agent-tcp-port {}".format(agent_port)
74 cmd = " ".join([cmd, opt_args])
75 sessiond = runtime.spawn_subprocess(cmd)
76 signal.sigtimedwait({signal.SIGUSR1}, 60)
77 previous_handler = signal.signal(signal.SIGUSR1, previous_handler)
78 return sessiond
79
80
81 def relayd_spawn(runtime, url="localhost"):
82 """
83 Return a tuple (relayd_uuid, ctrl_port, data_port, live_port)
84 """
85 ports = find_multiple_free_port(3)
86 data_port = ports.pop()
87 ctrl_port = ports.pop()
88 live_port = ports.pop()
89
90 base_cmd = "lttng-relayd -vvv"
91 data_string = "-D tcp://{}:{}".format(url, data_port)
92 ctrl_string = "-C tcp://{}:{}".format(url, ctrl_port)
93 live_string = "-L tcp://{}:{}".format(url, live_port)
94
95 cmd = " ".join([base_cmd, data_string, ctrl_string, live_string])
96 relayd = runtime.spawn_subprocess(cmd)
97
98 # Synchronization based on verbosity since no -S is available for
99 # lttng-relayd yet.
100 log_path = runtime.get_subprocess_stderr_path(relayd)
101
102 # TODO: Move to settings.
103 ready_cue = "Listener accepting live viewers connections"
104 # TODO: Move to settings.
105 timeout = 60
106 ready = False
107 for i in range(timeout):
108 if file_contains(log_path, ready_cue):
109 ready = True
110 break
111 time.sleep(1)
112
113 if not ready:
114 # Cleanup is performed by runtime
115 raise Exception("Relayd readyness timeout expired")
116
117 return (relayd, ctrl_port, data_port, live_port)
118
119
120 def find_free_port():
121 # There is no guarantee that the port will be free at runtime but should be
122 # good enough
123 with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
124 s.bind(('', 0))
125 return s.getsockname()[1]
126
127
128 def find_multiple_free_port(number):
129 """
130 Return a list of supposedly free port
131 """
132 assert(number >= 0)
133 ports = []
134 while(len(ports) != number):
135 port = find_free_port()
136 if port in ports:
137 continue
138 ports.append(port)
139 return ports
140
141
142 def file_contains(file_path, list_of_string):
143 with open(file_path, 'r') as f:
144 for line in f:
145 for s in list_of_string:
146 if s in line:
147 return True
148
149
150 def find_dir(root, name):
151 """
152 Returns the absolute path or None.
153 """
154 abs_path = None
155 for base, dirs, files in os.walk(root):
156 for tmp in dirs:
157 if tmp.endswith(name):
158 abs_path = os.path.abspath(os.path.join(base, tmp))
159 return abs_path
160
161
162 def find_file(root, name):
163 """
164 Returns the absolute path or None.
165 """
166 abs_path = None
167 for base, dirs, files in os.walk(root):
168 for tmp in files:
169 if tmp.endswith(name):
170 abs_path = os.path.abspath(os.path.join(base, tmp))
171 return abs_path
172
173
174 def validate(xml_path, xsd_path):
175
176 xmlschema_doc = etree.parse(xsd_path)
177 xmlschema = etree.XMLSchema(xmlschema_doc)
178
179 xml_doc = etree.parse(xml_path)
180 result = xmlschema.validate(xml_doc)
181
182 return result
183
184 def xpath_query(xml_file, xpath):
185 """
186 Return a list of xml node corresponding to the xpath. The list can be of lenght
187 zero.
188 """
189 with open(xml_file, 'r') as f:
190 tree = etree.parse(f)
191 root = tree.getroot()
192 # Remove all namespace
193 # https://stackoverflow.com/questions/18159221/remove-namespace-and-prefix-from-xml-in-python-using-lxml
194 for elem in root.getiterator():
195 if not hasattr(elem.tag, 'find'):
196 continue
197 i = elem.tag.find('}')
198 if i >= 0:
199 elem.tag = elem.tag[i+1:]
200
201 return root.xpath(xpath)
This page took 0.034054 seconds and 5 git commands to generate.