apache-ignite
211 строк · 6.4 Кб
1# Licensed to the Apache Software Foundation (ASF) under one or more
2# contributor license agreements. See the NOTICE file distributed with
3# this work for additional information regarding copyright ownership.
4# The ASF licenses this file to You under the Apache License, Version 2.0
5# (the "License"); you may not use this file except in compliance with
6# the License. You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""
17This module contains JMX Console client and different utilities and mixins to retrieve ignite node parameters
18and attributes.
19"""
20import os
21import re
22
23from ignitetest.services.utils.decorators import memoize
24from ignitetest.services.utils.jvm_utils import java_version, java_major_version
25
26
27def ignite_jmx_mixin(node, service):
28"""
29Dynamically mixin JMX attributes to Ignite service node.
30:param node: Ignite service node.
31:param service: Ignite service.
32"""
33setattr(node, 'pids', service.pids(node, service.main_java_class))
34setattr(node, 'install_root', service.install_root)
35base_cls = node.__class__
36base_cls_name = node.__class__.__name__
37node.__class__ = type(base_cls_name, (base_cls, IgniteJmxMixin), {})
38
39
40class JmxMBean:
41"""
42Dynamically exposes JMX MBean attributes.
43"""
44def __init__(self, client, name):
45self.client = client
46self.name = name
47
48def __getattr__(self, attr):
49"""
50Retrieves through JMX client MBean attributes.
51:param attr: Attribute name.
52:return: Attribute value.
53"""
54return self.client.mbean_attribute(self.name, attr)
55
56
57class JmxClient:
58"""JMX client, invokes jmxterm on node locally.
59"""
60def __init__(self, node):
61self.node = node
62self.install_root = node.install_root
63self.pid = node.pids[0]
64self.java_major = java_major_version(java_version(self.node))
65
66@property
67def jmx_util_cmd(self):
68"""
69:return: jmxterm prepared command line invocation.
70"""
71extra_flag = "--add-exports jdk.jconsole/sun.tools.jconsole=ALL-UNNAMED" if self.java_major >= 15 else ""
72
73return os.path.join(f"java {extra_flag} -jar {self.install_root}/jmxterm.jar -v silent -n")
74
75@memoize
76def find_mbean(self, pattern, negative_pattern=None, domain='org.apache'):
77"""
78Find mbean by specified pattern and domain on node.
79:param pattern: MBean name pattern.
80:param negative_pattern: if passed used to filter out some MBeans
81:param domain: Domain of MBean
82:return: JmxMBean instance
83"""
84cmd = "echo $'open %s\\n beans -d %s \\n close' | %s | grep -E -o '%s'" \
85% (self.pid, domain, self.jmx_util_cmd, pattern)
86
87if negative_pattern:
88cmd += " | grep -E -v '%s'" % negative_pattern
89
90name = next(self.__run_cmd(cmd)).strip()
91
92return JmxMBean(self, name)
93
94def mbean_attribute(self, mbean, attr):
95"""
96Get MBean attribute.
97:param mbean: MBean name
98:param attr: Attribute name
99:return: Attribute value
100"""
101cmd = "echo $'open %s\\n get -b %s %s \\n close' | %s | sed 's/%s = \\(.*\\);/\\1/'" \
102% (self.pid, mbean, attr, self.jmx_util_cmd, attr)
103
104return iter(s.strip() for s in self.__run_cmd(cmd))
105
106def __run_cmd(self, cmd):
107return self.node.account.ssh_capture(cmd, allow_fail=False, callback=str, combine_stderr=False)
108
109
110class DiscoveryInfo:
111""" Ignite service node discovery info, obtained from DiscoverySpi mbean.
112"""
113def __init__(self, coordinator, local_raw):
114self._local_raw = local_raw
115self._coordinator = coordinator
116
117@property
118def node_id(self):
119"""
120:return: Local node id.
121"""
122return self.__find__("id=([^\\s]+),")
123
124@property
125def coordinator(self):
126"""
127:return: Coordinator node id.
128"""
129return self._coordinator
130
131@property
132def consistent_id(self):
133"""
134:return: Node consistent id, if presents (only in TcpDiscovery).
135"""
136return self.__find__("consistentId=([^\\s]+),")
137
138@property
139def is_client(self):
140"""
141:return: True if node is client.
142"""
143return self.__find__("isClient=([^\\s]+),") == "true"
144
145@property
146def order(self):
147"""
148:return: Topology order.
149"""
150val = self.__find__("order=(\\d+),")
151return int(val) if val else -1
152
153@property
154def int_order(self):
155"""
156:return: Internal order (TcpDiscovery).
157"""
158val = self.__find__("intOrder=(\\d+),")
159return int(val) if val else -1
160
161def __find__(self, pattern):
162res = re.search(pattern, self._local_raw)
163return res.group(1) if res else None
164
165
166class IgniteJmxMixin:
167"""
168Mixin to IgniteService node, exposing useful properties, obtained from JMX.
169"""
170@memoize
171def jmx_client(self):
172"""
173:return: JmxClient instance.
174"""
175# noinspection PyTypeChecker
176return JmxClient(self)
177
178@memoize
179def node_id(self):
180"""
181:return: Local node id.
182"""
183return next(self.kernal_mbean().LocalNodeId).strip()
184
185def discovery_info(self):
186"""
187:return: DiscoveryInfo instance.
188"""
189disco_mbean = self.disco_mbean()
190crd = next(disco_mbean.Coordinator).strip()
191local = next(disco_mbean.LocalNodeFormatted).strip()
192
193return DiscoveryInfo(crd, local)
194
195def kernal_mbean(self):
196"""
197:return: IgniteKernal MBean.
198"""
199return self.jmx_client().find_mbean('.*group=Kernal.*name=IgniteKernal')
200
201@memoize
202def disco_mbean(self):
203"""
204:return: DiscoverySpi MBean.
205"""
206disco_spi = next(self.kernal_mbean().DiscoverySpiFormatted).strip()
207
208if 'ZookeeperDiscoverySpi' in disco_spi:
209return self.jmx_client().find_mbean('.*group=SPIs.*name=ZookeeperDiscoverySpi')
210
211return self.jmx_client().find_mbean('.*group=SPIs.*name=TcpDiscoverySpi')
212