2 # Copyright (c) 2014 Yusuke Shinyama
4 # Permission is hereby granted, free of charge, to any person obtaining a copy
5 # of this software and associated documentation files (the "Software"), to deal
6 # in the Software without restriction, including without limitation the rights
7 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 # copies of the Software, and to permit persons to whom the Software is
9 # furnished to do so, subject to the following conditions:
11 # The above copyright notice and this permission notice shall be included in
12 # all copies or substantial portions of the Software.
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 from __future__ import print_function
26 class NetstringParser(object):
28 Decodes a netstring to a list of Python strings.
30 >>> parser = NetstringParser()
31 >>> parser.feed('3:456,')
34 >>> NetstringParser.parse('3:abc,4:defg,')
46 self._parse = self._parse_len
55 def _parse_len(self, s, i):
58 if c < '0' or '9' < c:
59 self._parse = self._parse_sep
62 self._length += ord(c)-48
66 def _parse_sep(self, s, i):
67 if s[i] != ':': raise SyntaxError(i)
68 self._parse = self._parse_data
71 def _parse_data(self, s, i):
72 n = min(self._length, len(s)-i)
73 self._data += s[i:i+n]
76 self._parse = self._parse_end
79 def _parse_end(self, s, i):
80 if s[i] != ',': raise SyntaxError(i)
81 self.add_data(self._data)
85 def add_data(self, data):
86 self.results.append(data)
96 # Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)
98 # This program is free software; you can redistribute it and/or
99 # modify it under the terms of the GNU General Public License
100 # as published by the Free Software Foundation; either version 2
101 # of the License, or (at your option) any later version.
103 # This program is distributed in the hope that it will be useful,
104 # but WITHOUT ANY WARRANTY; without even the implied warranty of
105 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
106 # GNU General Public License for more details.
108 # You should have received a copy of the GNU General Public License
109 # along with this program; if not, write to the Free Software Foundation
110 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
112 import socket, ssl, sys, json, os, hashlib, time
115 print(*objs, file=sys.stderr)
117 if len(sys.argv) < 2:
118 warning("Syntax: %s <host> [<port>]" % (sys.argv[0]))
122 if len(sys.argv) > 2:
123 port = int(sys.argv[2])
127 agentpki = "@CMAKE_INSTALL_FULL_SYSCONFDIR@/icinga2/pki/agent"
128 keyfile = agentpki + "/agent.key"
129 certfile = agentpki + "/agent.crt"
130 cafile = agentpki + "/ca.crt"
132 if not os.path.isfile(certfile):
133 warning("Certificate file (" + certfile + ") not found.")
134 warning("Make sure the agent certificates are set up properly.")
137 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
139 # require a certificate from the server
140 ssl_sock = ssl.wrap_socket(s,
144 cert_reqs=ssl.CERT_REQUIRED)
146 ssl_sock.connect((host, port))
150 subject = ssl_sock.getpeercert()["subject"]
154 if rdn[0] == "commonName":
158 warning("Agent certificate does not have a commonName:", repr(subject))
161 ssl_sock.write('20:{"method":"get_crs"},')
163 nsp = NetstringParser()
165 data = ssl_sock.read()
172 if len(nsp.results) != 1:
173 warning("Agent returned invalid response: ", repr(nsp.results))
176 response = json.loads(nsp.results[0])
177 method = response['method']
179 if method != "push_crs":
180 warning("Agent did not return any check results. Make sure you're using the master certificate.")
183 params = response["params"]
184 params["seen"] = time.time()
186 inventory_file = "@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/lib/icinga2/agent/inventory/" + hashlib.sha256(cn).hexdigest()
187 fp = open(inventory_file, "w")
188 inventory_info = { "identity": cn, "params": params }
189 json.dump(inventory_info, fp)
192 peer_file = "@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/lib/icinga2/agent/inventory/" + hashlib.sha256(cn).hexdigest() + ".peer"
193 fp = open(peer_file, "w")
194 peer_info = { "agent_host": host, "agent_port": port }
195 json.dump(peer_info, fp)
198 print("Inventory information has been updated for agent '%s'." % (cn))