naeural-client 3.1.4__py3-none-any.whl → 3.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- naeural_client/_ver.py +1 -1
- naeural_client/base/generic_session.py +356 -73
- naeural_client/base/instance.py +38 -0
- naeural_client/base/pipeline.py +82 -6
- naeural_client/base_decentra_object.py +4 -2
- naeural_client/bc/base.py +12 -8
- naeural_client/bc/evm.py +10 -1
- naeural_client/cli/cli.py +1 -0
- naeural_client/cli/cli_commands.py +19 -2
- naeural_client/cli/nodes.py +100 -8
- naeural_client/cli/oracles.py +6 -0
- naeural_client/comm/mqtt_wrapper.py +4 -2
- naeural_client/const/base.py +2 -0
- naeural_client/const/payload.py +7 -1
- naeural_client/utils/config.py +64 -75
- naeural_client/utils/oracle_sync/oracle_tester.py +1 -1
- {naeural_client-3.1.4.dist-info → naeural_client-3.2.0.dist-info}/METADATA +4 -4
- {naeural_client-3.1.4.dist-info → naeural_client-3.2.0.dist-info}/RECORD +21 -21
- {naeural_client-3.1.4.dist-info → naeural_client-3.2.0.dist-info}/WHEEL +0 -0
- {naeural_client-3.1.4.dist-info → naeural_client-3.2.0.dist-info}/entry_points.txt +0 -0
- {naeural_client-3.1.4.dist-info → naeural_client-3.2.0.dist-info}/licenses/LICENSE +0 -0
naeural_client/base/instance.py
CHANGED
@@ -49,6 +49,7 @@ class Instance():
|
|
49
49
|
self.log = log
|
50
50
|
self.pipeline = pipeline
|
51
51
|
self.instance_id = instance_id
|
52
|
+
self.last_known_status = None
|
52
53
|
self.signature = signature.upper()
|
53
54
|
self.config = {}
|
54
55
|
self.__debug = debug
|
@@ -673,3 +674,40 @@ class Instance():
|
|
673
674
|
self.temporary_detach(attachment)
|
674
675
|
|
675
676
|
return result_payload
|
677
|
+
|
678
|
+
def get_status(self):
|
679
|
+
"""
|
680
|
+
Get the status of the instance.
|
681
|
+
|
682
|
+
Returns
|
683
|
+
-------
|
684
|
+
dict
|
685
|
+
The status of the instance with keys from `PLUGIN_INFO` class constants
|
686
|
+
|
687
|
+
Example:
|
688
|
+
--------
|
689
|
+
```json
|
690
|
+
{
|
691
|
+
"CURRENT_EXEC_ITERATION": 2147088,
|
692
|
+
"CURRENT_PROCESS_ITERATION": 0,
|
693
|
+
"EXEC_TIMESTAMP": "2025-02-28 07:06:40.612999",
|
694
|
+
"FIRST_ERROR_TIME": null,
|
695
|
+
"FREQUENCY": null,
|
696
|
+
"INFO": null,
|
697
|
+
"INIT_TIMESTAMP": "2025-02-27 10:24:56.622480",
|
698
|
+
"INSTANCE_ID": "RECE01_default",
|
699
|
+
"LAST_CONFIG_TIMESTAMP": "2025-02-27 10:24:56.622340",
|
700
|
+
"LAST_ERROR_TIME": null,
|
701
|
+
"LAST_PAYLOAD_TIME": "2025-02-27 10:24:56",
|
702
|
+
"OUTSIDE_WORKING_HOURS": false,
|
703
|
+
"PROCESS_DELAY": 1,
|
704
|
+
"SIGNATURE": "REST_CUSTOM_EXEC_01",
|
705
|
+
"STREAM_ID": "admin_pipeline",
|
706
|
+
"TOTAL_PAYLOAD_COUNT": 1
|
707
|
+
}
|
708
|
+
```
|
709
|
+
"""
|
710
|
+
result = {} if self.last_known_status is None else self.last_known_status
|
711
|
+
if self.last_known_status is None:
|
712
|
+
self.Pd(f'Instance <{self.instance_id}> has no status yet')
|
713
|
+
return result
|
naeural_client/base/pipeline.py
CHANGED
@@ -40,6 +40,7 @@ class Pipeline(BaseCodeChecker):
|
|
40
40
|
on_notification=None,
|
41
41
|
is_attached=False,
|
42
42
|
existing_config=None,
|
43
|
+
plugins_statuses=None,
|
43
44
|
debug=False,
|
44
45
|
**kwargs
|
45
46
|
) -> None:
|
@@ -118,6 +119,9 @@ class Pipeline(BaseCodeChecker):
|
|
118
119
|
self.proposed_config = self.__pop_ignored_keys_from_config(self.proposed_config)
|
119
120
|
self.__staged_config = None
|
120
121
|
|
122
|
+
|
123
|
+
self.__update_plugins_statuses_data(plugins_statuses)
|
124
|
+
|
121
125
|
self.__was_last_operation_successful = None
|
122
126
|
|
123
127
|
self.proposed_remove_instances = []
|
@@ -172,6 +176,10 @@ class Pipeline(BaseCodeChecker):
|
|
172
176
|
is_attached,
|
173
177
|
debug=False,
|
174
178
|
):
|
179
|
+
"""
|
180
|
+
This method is used to create a new instance of a plugin and add it to the pipeline.
|
181
|
+
|
182
|
+
"""
|
175
183
|
instance_class = None
|
176
184
|
str_signature = None
|
177
185
|
if isinstance(signature, str):
|
@@ -202,8 +210,10 @@ class Pipeline(BaseCodeChecker):
|
|
202
210
|
----------
|
203
211
|
plugins : List | None
|
204
212
|
The list of plugins, as they are found in the pipeline configuration dictionary in the heartbeat.
|
213
|
+
|
205
214
|
is_attached : bool
|
206
215
|
This is used internally to allow the user to create or attach to a pipeline, and then use the same objects in the same way.
|
216
|
+
|
207
217
|
|
208
218
|
"""
|
209
219
|
if plugins is None:
|
@@ -215,10 +225,52 @@ class Pipeline(BaseCodeChecker):
|
|
215
225
|
for dct_instance in instances:
|
216
226
|
config = {k.upper(): v for k, v in dct_instance.items()}
|
217
227
|
instance_id = config.pop('INSTANCE_ID')
|
218
|
-
self.__init_instance(signature, instance_id, config, None, None, is_attached=is_attached)
|
228
|
+
instance_object = self.__init_instance(signature, instance_id, config, None, None, is_attached=is_attached)
|
229
|
+
# now we update the status of the plugin instance with the last known status
|
230
|
+
self._update_plugin_status(instance_object)
|
219
231
|
# end for dct_instance
|
220
232
|
# end for dct_signature_instances
|
221
233
|
return
|
234
|
+
|
235
|
+
def __update_plugins_statuses_data(self, plugins_statuses):
|
236
|
+
if plugins_statuses is not None:
|
237
|
+
self.last_plugins_statuses = plugins_statuses
|
238
|
+
self.last_plugins_statuses_time = time()
|
239
|
+
else:
|
240
|
+
self.last_plugins_statuses = None
|
241
|
+
self.last_plugins_statuses_time = 0
|
242
|
+
return
|
243
|
+
|
244
|
+
|
245
|
+
def __get_recent_plugin_instance_status(self, signature, instance_id):
|
246
|
+
"""
|
247
|
+
Get the most recent status of a plugin instance.
|
248
|
+
"""
|
249
|
+
result = None
|
250
|
+
if self.last_plugins_statuses is not None:
|
251
|
+
for plugin_status in self.last_plugins_statuses:
|
252
|
+
if (
|
253
|
+
plugin_status['SIGNATURE'] == signature and
|
254
|
+
plugin_status['INSTANCE_ID'] == instance_id and
|
255
|
+
plugin_status['STREAM_ID'] == self.name
|
256
|
+
):
|
257
|
+
result = plugin_status
|
258
|
+
break
|
259
|
+
return result
|
260
|
+
|
261
|
+
|
262
|
+
def _update_plugin_status(self, instance_object : Instance):
|
263
|
+
"""
|
264
|
+
Update the status of a plugin instance using any existing last known status.
|
265
|
+
|
266
|
+
"""
|
267
|
+
signature = instance_object.signature
|
268
|
+
instance_id = instance_object.instance_id
|
269
|
+
plugin_status = self.__get_recent_plugin_instance_status(signature, instance_id)
|
270
|
+
if plugin_status is not None:
|
271
|
+
instance_object.last_known_status = plugin_status
|
272
|
+
return
|
273
|
+
|
222
274
|
|
223
275
|
def __get_proposed_pipeline_config(self):
|
224
276
|
"""
|
@@ -464,8 +516,22 @@ class Pipeline(BaseCodeChecker):
|
|
464
516
|
-------
|
465
517
|
dict
|
466
518
|
The configuration dictionary without the ignored keys.
|
519
|
+
|
520
|
+
Observations
|
521
|
+
------------
|
522
|
+
|
523
|
+
Initially the ignored keys were:
|
524
|
+
[
|
525
|
+
"INITIATOR_ADDR",
|
526
|
+
"INITIATOR_ID",
|
527
|
+
"LAST_UPDATE_TIME",
|
528
|
+
"MODIFIED_BY_ADDR",
|
529
|
+
"MODIFIED_BY_ID"
|
530
|
+
]
|
531
|
+
However these keys are essential for the pipeline configuration for app
|
532
|
+
monitoring purposes
|
467
533
|
"""
|
468
|
-
ignored_keys = [
|
534
|
+
ignored_keys = []
|
469
535
|
return {k: v for k, v in config.items() if k not in ignored_keys}
|
470
536
|
|
471
537
|
def __get_instance_object(self, signature, instance_id):
|
@@ -1492,13 +1558,21 @@ class Pipeline(BaseCodeChecker):
|
|
1492
1558
|
**kwargs
|
1493
1559
|
)
|
1494
1560
|
return instance
|
1495
|
-
|
1496
|
-
|
1561
|
+
|
1562
|
+
|
1563
|
+
def _sync_configuration_with_remote(self, config={}, plugins_statuses : list = None):
|
1564
|
+
"""
|
1565
|
+
Given a configuration, update the pipeline configuration and the
|
1566
|
+
instances configuration.
|
1567
|
+
|
1568
|
+
"""
|
1497
1569
|
config.pop('NAME', None)
|
1498
1570
|
config.pop('TYPE', None)
|
1499
1571
|
plugins = config.pop('PLUGINS', {})
|
1500
1572
|
|
1501
1573
|
self.config = {**self.config, **config}
|
1574
|
+
|
1575
|
+
self.__update_plugins_statuses_data(plugins_statuses)
|
1502
1576
|
|
1503
1577
|
active_plugins = []
|
1504
1578
|
for dct_signature_instances in plugins:
|
@@ -1509,9 +1583,11 @@ class Pipeline(BaseCodeChecker):
|
|
1509
1583
|
active_plugins.append((signature, instance_id))
|
1510
1584
|
instance_object = self.__get_instance_object(signature, instance_id)
|
1511
1585
|
if instance_object is None:
|
1512
|
-
self.__init_instance(signature, instance_id, dct_instance, None, None, is_attached=True)
|
1586
|
+
instance_object = self.__init_instance(signature, instance_id, dct_instance, None, None, is_attached=True) # here the plugin status is updated if data is available
|
1513
1587
|
else:
|
1514
|
-
instance_object._sync_configuration_with_remote(dct_instance)
|
1588
|
+
instance_object._sync_configuration_with_remote(dct_instance)
|
1589
|
+
# next we update the plugin status from known plugins statuses
|
1590
|
+
self._update_plugin_status(instance_object)
|
1515
1591
|
# end for dct_instance
|
1516
1592
|
# end for dct_signature_instances
|
1517
1593
|
|
@@ -91,9 +91,11 @@ class BaseDecentrAIObject(object):
|
|
91
91
|
_r = self.log.P(msg, show_time=t, color=color, **kwargs)
|
92
92
|
return _r
|
93
93
|
|
94
|
-
def D(self, s, t=False, color=None, prefix=False, **kwargs):
|
94
|
+
def D(self, s, t=False, color=None, prefix=False, forced_debug=False, **kwargs):
|
95
95
|
_r = -1
|
96
|
-
if self.DEBUG:
|
96
|
+
if self.DEBUG or forced_debug:
|
97
|
+
if color is None:
|
98
|
+
color = 'd'
|
97
99
|
if self.show_prefixes:
|
98
100
|
msg = "[DEBUG] {}: {}".format(self.__name__, s)
|
99
101
|
else:
|
naeural_client/bc/base.py
CHANGED
@@ -7,7 +7,7 @@ import datetime
|
|
7
7
|
import uuid
|
8
8
|
import requests
|
9
9
|
|
10
|
-
|
10
|
+
from collections import defaultdict
|
11
11
|
from hashlib import sha256, md5
|
12
12
|
from threading import Lock
|
13
13
|
from copy import deepcopy
|
@@ -309,6 +309,9 @@ class BaseBlockEngine(_EVMMixin):
|
|
309
309
|
assert log is not None, "Logger object was not provided!"
|
310
310
|
|
311
311
|
self.log = log
|
312
|
+
|
313
|
+
self._first_checks_done = defaultdict(lambda: False) # used to store the first check results
|
314
|
+
|
312
315
|
self.__private_key = None
|
313
316
|
self.__verbosity = verbosity
|
314
317
|
self.__public_key = None
|
@@ -325,7 +328,7 @@ class BaseBlockEngine(_EVMMixin):
|
|
325
328
|
pem_name = config.get(BCct.K_PEM_FILE, BCct.DEFAULT_PEM_FILE)
|
326
329
|
pem_folder = config.get(BCct.K_PEM_LOCATION, BCct.DEFAULT_PEM_LOCATION)
|
327
330
|
pem_fn = os.path.join(log.get_target_folder(pem_folder), pem_name)
|
328
|
-
#endif pem is defined in ~/.
|
331
|
+
#endif pem is defined in ~/.ratio1/ or in the data folder of the _local_cache
|
329
332
|
self.__pem_file = pem_fn
|
330
333
|
self._init()
|
331
334
|
return
|
@@ -413,7 +416,7 @@ class BaseBlockEngine(_EVMMixin):
|
|
413
416
|
### end Ethereum
|
414
417
|
if self.__eth_enabled:
|
415
418
|
self.P(
|
416
|
-
"
|
419
|
+
"{} / ETH: {} ({})".format(self.address, self.eth_address, self.evm_network), boxed=True, verbosity=1,
|
417
420
|
color='g'
|
418
421
|
)
|
419
422
|
else:
|
@@ -1407,8 +1410,9 @@ class BaseBlockEngine(_EVMMixin):
|
|
1407
1410
|
the status is still 200, an empty dictionary will be returned).
|
1408
1411
|
"""
|
1409
1412
|
if EE_VPN_IMPL:
|
1410
|
-
return
|
1413
|
+
return None # must return None not empty dict for VPNs
|
1411
1414
|
#endif EE_VPN_IMPL
|
1415
|
+
|
1412
1416
|
from naeural_client._ver import __VER__ as sdk_version
|
1413
1417
|
try:
|
1414
1418
|
from ver import __VER__ as app_version
|
@@ -1444,13 +1448,13 @@ class BaseBlockEngine(_EVMMixin):
|
|
1444
1448
|
url = network_data[dAuth.EvmNetData.DAUTH_URL_KEY]
|
1445
1449
|
#endif not in env
|
1446
1450
|
|
1447
|
-
if isinstance(url, str) and len(url) >
|
1451
|
+
if isinstance(url, str) and len(url) > MIN_LEN:
|
1448
1452
|
# Valid URL
|
1449
1453
|
if dauth_endp is None:
|
1450
1454
|
if in_env:
|
1451
|
-
self.P("Found dAuth URL in environment: '{}'".format(url)
|
1455
|
+
self.P("Found dAuth URL in environment: '{}'".format(url))
|
1452
1456
|
else:
|
1453
|
-
self.P("Using default dAuth URL: '{}'".format(url)
|
1457
|
+
self.P("Using default dAuth URL: '{}'".format(url))
|
1454
1458
|
eth_short = self.eth_address[:6] + '...' + self.eth_address[-4:]
|
1455
1459
|
while not done:
|
1456
1460
|
self.P(f"<{eth_short}> ({network}) dAuth with `{url}`... (try {tries + 1} / {max_tries})")
|
@@ -1550,7 +1554,7 @@ class BaseBlockEngine(_EVMMixin):
|
|
1550
1554
|
#end while
|
1551
1555
|
else:
|
1552
1556
|
# Invalid URL, thus dct_env will remain None
|
1553
|
-
self.P(f"dAuth URL is not
|
1557
|
+
self.P(f"dAuth URL is not valid: {url}", color='r')
|
1554
1558
|
#end if url is valid
|
1555
1559
|
if return_full_data:
|
1556
1560
|
return dct_response
|
naeural_client/bc/evm.py
CHANGED
@@ -191,8 +191,17 @@ class _EVMMixin:
|
|
191
191
|
|
192
192
|
"""
|
193
193
|
if EE_VPN_IMPL:
|
194
|
-
return "VPN"
|
194
|
+
return "VPN"
|
195
195
|
network = os.environ.get(dAuth.DAUTH_NET_ENV_KEY, dAuth.DAUTH_SDK_NET_DEFAULT)
|
196
|
+
|
197
|
+
if not self._first_checks_done[dAuth.DAUTH_NET_ENV_KEY]:
|
198
|
+
if dAuth.DAUTH_NET_ENV_KEY not in os.environ:
|
199
|
+
self.P(f"Using default {network=}...", verbosity=2)
|
200
|
+
else:
|
201
|
+
self.P(f"Using {network=} from `{dAuth.DAUTH_NET_ENV_KEY}` env key...", verbosity=2)
|
202
|
+
self._first_checks_done[dAuth.DAUTH_NET_ENV_KEY] = True
|
203
|
+
# done first checks
|
204
|
+
|
196
205
|
if not hasattr(self, "current_evm_network") or self.current_evm_network != network:
|
197
206
|
self.current_evm_network = network
|
198
207
|
network_data = self.get_network_data(network)
|
naeural_client/cli/cli.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
from naeural_client.cli.nodes import (
|
2
2
|
get_nodes, get_supervisors,
|
3
3
|
restart_node, shutdown_node,
|
4
|
+
get_apps
|
4
5
|
)
|
5
6
|
from naeural_client.cli.oracles import get_availability
|
6
7
|
from naeural_client.utils.config import (
|
7
8
|
show_config, reset_config, show_address, get_set_network,
|
8
|
-
|
9
|
+
get_networks, get_set_alias, get_eth_addr
|
9
10
|
)
|
10
11
|
|
11
12
|
# Define the available commands
|
@@ -27,6 +28,13 @@ CLI_COMMANDS = {
|
|
27
28
|
"supervisors": {
|
28
29
|
"func": get_supervisors, # DONE
|
29
30
|
},
|
31
|
+
"eth" : {
|
32
|
+
"func": get_eth_addr,
|
33
|
+
"description": "Get the ETH address given a node address",
|
34
|
+
"params": {
|
35
|
+
"node": "The node address to get the ETH address for"
|
36
|
+
}
|
37
|
+
},
|
30
38
|
"avail": {
|
31
39
|
"func": get_availability,
|
32
40
|
"params": {
|
@@ -43,7 +51,8 @@ CLI_COMMANDS = {
|
|
43
51
|
"func": get_apps,
|
44
52
|
"description": "Get the apps running on a given node, if the client is allowed on that node.",
|
45
53
|
"params": {
|
46
|
-
"node": "The ETH address or the specific address of the node to get the apps from",
|
54
|
+
"--node": "The ETH address or the specific address of the node to get the apps from",
|
55
|
+
"--owner" : "Get the apps for a particular owner/initiator",
|
47
56
|
"--full": "Include admin apps (flag)",
|
48
57
|
"--json": "Output the entire JSON config of applications (flag)",
|
49
58
|
}
|
@@ -80,6 +89,14 @@ CLI_COMMANDS = {
|
|
80
89
|
"--set": "The network to set either 'mainnet' or 'testnet' (same as --new)",
|
81
90
|
}
|
82
91
|
},
|
92
|
+
|
93
|
+
"alias" :{
|
94
|
+
"func": get_set_alias, # DONE
|
95
|
+
"description": "Show and sets the current client alias",
|
96
|
+
"params": {
|
97
|
+
"--set": "The alias to set for this SDK client",
|
98
|
+
}
|
99
|
+
}
|
83
100
|
},
|
84
101
|
"restart": {
|
85
102
|
"func": restart_node, # TODO
|
naeural_client/cli/nodes.py
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
import os
|
2
|
+
import json
|
3
|
+
|
2
4
|
from time import time
|
3
5
|
from naeural_client.utils.config import log_with_color
|
4
6
|
from naeural_client.const import SESSION_CT, COMMANDS, BASE_CT
|
7
|
+
from naeural_client._ver import __VER__ as version
|
8
|
+
|
9
|
+
from pandas import DataFrame
|
10
|
+
from datetime import datetime
|
5
11
|
|
6
12
|
|
7
13
|
def _get_netstats(
|
@@ -53,32 +59,41 @@ def get_nodes(args):
|
|
53
59
|
4. Get the active nodes union via Session and display the nodes marking those peered vs non-peered.
|
54
60
|
"""
|
55
61
|
supervisor_addr = args.supervisor
|
62
|
+
online = args.online
|
63
|
+
online = True # always online, flag deprecated
|
56
64
|
wide = args.wide
|
57
65
|
if args.verbose:
|
58
66
|
log_with_color(f"Getting nodes from supervisor <{supervisor_addr}>...", color='b')
|
59
67
|
|
60
68
|
res = _get_netstats(
|
61
69
|
silent=not args.verbose,
|
62
|
-
online_only=
|
70
|
+
online_only=online or args.peered,
|
63
71
|
allowed_only=args.peered,
|
64
72
|
supervisor=supervisor_addr,
|
65
73
|
eth=args.eth,
|
66
74
|
all_info=wide,
|
75
|
+
return_session=True,
|
67
76
|
)
|
68
|
-
df, supervisor, super_alias, nr_supers, elapsed = res
|
77
|
+
df, supervisor, super_alias, nr_supers, elapsed, sess = res
|
69
78
|
if args.online:
|
70
79
|
FILTERED = ['State']
|
71
80
|
df = df[[c for c in df.columns if c not in FILTERED]]
|
72
81
|
|
73
|
-
prefix = "Online n" if (
|
74
|
-
network = os.environ.get(BASE_CT.dAuth.DAUTH_NET_ENV_KEY, BASE_CT.dAuth.DAUTH_SDK_NET_DEFAULT)
|
82
|
+
prefix = "Online n" if (online or args.peered) else "N"
|
83
|
+
# network = os.environ.get(BASE_CT.dAuth.DAUTH_NET_ENV_KEY, BASE_CT.dAuth.DAUTH_SDK_NET_DEFAULT)
|
84
|
+
network = sess.bc_engine.evm_network
|
75
85
|
if supervisor == "ERROR":
|
76
86
|
log_with_color(f"No supervisors or no comms available in {elapsed:.1f}s. Please check your settings.", color='r')
|
77
87
|
else:
|
78
|
-
log_with_color(f"
|
88
|
+
log_with_color(f"Ratio1 client v{version}:\n", color='b')
|
89
|
+
log_with_color(
|
90
|
+
"{}odes on '{}' reported by <{}> '{}' in {:.1f}s ({} supervisors seen):".format(
|
91
|
+
prefix, network, supervisor, super_alias, elapsed, nr_supers),
|
92
|
+
color='b'
|
93
|
+
)
|
79
94
|
import pandas as pd
|
80
95
|
pd.set_option('display.float_format', '{:.4f}'.format)
|
81
|
-
log_with_color(f"{df}")
|
96
|
+
log_with_color(f"{df}\n")
|
82
97
|
return
|
83
98
|
|
84
99
|
|
@@ -93,18 +108,95 @@ def get_supervisors(args):
|
|
93
108
|
silent=not args.verbose,
|
94
109
|
online_only=True,
|
95
110
|
supervisors_only=True,
|
111
|
+
return_session=True,
|
96
112
|
)
|
97
|
-
df, supervisor, super_alias, nr_supers, elapsed = res
|
113
|
+
df, supervisor, super_alias, nr_supers, elapsed, sess = res
|
98
114
|
FILTERED = ['Oracle', 'State']
|
99
115
|
df = df[[c for c in df.columns if c not in FILTERED]]
|
100
116
|
|
101
117
|
if supervisor == "ERROR":
|
102
118
|
log_with_color(f"No supervisors or no comms available in {elapsed:.1f}s. Please check your settings.", color='r')
|
103
119
|
else:
|
104
|
-
log_with_color(
|
120
|
+
log_with_color(
|
121
|
+
"Supervisors on '{}' reported by <{}> '{}' in {:.1f}s".format(
|
122
|
+
sess.bc_engine.evm_network, supervisor, super_alias, elapsed),
|
123
|
+
color='b'
|
124
|
+
)
|
105
125
|
log_with_color(f"{df}")
|
106
126
|
return
|
107
127
|
|
128
|
+
|
129
|
+
def get_apps(args):
|
130
|
+
"""
|
131
|
+
Shows the apps running on a given node, if the client is allowed on that node.
|
132
|
+
Parameters
|
133
|
+
----------
|
134
|
+
args : argparse.Namespace
|
135
|
+
Arguments passed to the function.
|
136
|
+
|
137
|
+
"""
|
138
|
+
verbose = args.verbose
|
139
|
+
node = args.node
|
140
|
+
show_full = args.full
|
141
|
+
as_json = args.json
|
142
|
+
owner = args.owner
|
143
|
+
|
144
|
+
# 1. Init session
|
145
|
+
from naeural_client import Session
|
146
|
+
sess = Session(
|
147
|
+
silent=not verbose
|
148
|
+
)
|
149
|
+
|
150
|
+
res = sess.get_nodes_apps(
|
151
|
+
node=node, owner=owner, show_full=show_full,
|
152
|
+
as_json=as_json, as_df=not as_json
|
153
|
+
)
|
154
|
+
if res is not None:
|
155
|
+
network = sess.bc_engine.evm_network
|
156
|
+
node_alias = sess.get_node_alias(node) if node else None
|
157
|
+
if as_json:
|
158
|
+
log_with_color(json.dumps(res, indent=2))
|
159
|
+
else:
|
160
|
+
df_apps = res
|
161
|
+
if df_apps.shape[0] == 0:
|
162
|
+
log_with_color(
|
163
|
+
"No user apps found on node <{}> '{}' of network '{}'".format(
|
164
|
+
node, node_alias, network
|
165
|
+
),
|
166
|
+
color='r'
|
167
|
+
)
|
168
|
+
return
|
169
|
+
# remove Node column
|
170
|
+
if node is not None and owner is None:
|
171
|
+
df_apps.drop(columns=['Node'], inplace=True)
|
172
|
+
|
173
|
+
if node is None and owner is not None:
|
174
|
+
df_apps.drop(columns=['Owner'], inplace=True)
|
175
|
+
|
176
|
+
if node is not None:
|
177
|
+
last_seen = sess.get_last_seen_time(node)
|
178
|
+
last_seen_str = datetime.fromtimestamp(last_seen).strftime('%Y-%m-%d %H:%M:%S') if last_seen else None
|
179
|
+
is_online = sess.check_node_online(node)
|
180
|
+
node_status = 'Online' if is_online else 'Offline'
|
181
|
+
else:
|
182
|
+
last_seen_str = "N/A"
|
183
|
+
node_status = "N/A"
|
184
|
+
#end if node
|
185
|
+
if node == None:
|
186
|
+
node = "[All available]"
|
187
|
+
by_owner = f" by owner <{owner}>" if owner else ""
|
188
|
+
log_with_color(f"Ratio1 client v{version}:\n", color='b')
|
189
|
+
log_with_color(
|
190
|
+
"Apps on <{}> ({}) [Status: {}| Last seen: {}]{}:".format(
|
191
|
+
node, network, node_status, last_seen_str, by_owner
|
192
|
+
),
|
193
|
+
color='b'
|
194
|
+
)
|
195
|
+
log_with_color(f"{df_apps}\n")
|
196
|
+
#end if as_json
|
197
|
+
#end if res is not None
|
198
|
+
return
|
199
|
+
|
108
200
|
def _send_command_to_node(args, command, ignore_not_found=False):
|
109
201
|
node = args.node
|
110
202
|
silent = not args.verbose
|
naeural_client/cli/oracles.py
CHANGED
@@ -133,11 +133,17 @@ def get_availability(args):
|
|
133
133
|
# endif full
|
134
134
|
|
135
135
|
tester = oracle_tester_init()
|
136
|
+
|
137
|
+
if not tester.bc.is_valid_eth_address(node):
|
138
|
+
node = tester.bc.node_address_to_eth_address(node)
|
139
|
+
|
136
140
|
log_with_color("Checking {}availability of node <{}> from {} to {}.".format(
|
137
141
|
"(DEBUG MODE) " if rounds > 1 else "", node, start,
|
138
142
|
end if end else "last epoch"
|
139
143
|
), color='b'
|
140
144
|
)
|
145
|
+
|
146
|
+
|
141
147
|
res = tester.execute_command(
|
142
148
|
node_eth_addr=node,
|
143
149
|
start=start,
|
@@ -41,11 +41,11 @@ class MQTTWrapper(object):
|
|
41
41
|
self._config = config
|
42
42
|
self._recv_buff = recv_buff
|
43
43
|
self._mqttc = None
|
44
|
-
self.debug_errors = debug_errors
|
44
|
+
self.debug_errors = debug_errors if verbosity <=1 else True
|
45
45
|
self._thread_name = None
|
46
46
|
self.connected = False
|
47
47
|
self.disconnected = False
|
48
|
-
self.__verbosity = verbosity
|
48
|
+
self.__verbosity = verbosity
|
49
49
|
self._send_to = None
|
50
50
|
self._nr_full_retries = 0
|
51
51
|
self.__nr_dropped_messages = 0
|
@@ -240,6 +240,8 @@ class MQTTWrapper(object):
|
|
240
240
|
return
|
241
241
|
|
242
242
|
def __create_mqttc_object(self, comtype, client_uid):
|
243
|
+
if self.__verbosity > 1:
|
244
|
+
self.P(f"Creating MQTT client: {self._connection_name} - {comtype} - {client_uid}")
|
243
245
|
client_id = self._connection_name + '_' + comtype + '_' + client_uid
|
244
246
|
if mqtt_version.startswith('2'):
|
245
247
|
mqttc = mqtt.Client(
|
naeural_client/const/base.py
CHANGED
naeural_client/const/payload.py
CHANGED
@@ -209,6 +209,8 @@ class PAYLOAD_DATA:
|
|
209
209
|
NETMON_NODE_SECURED = 'secured'
|
210
210
|
NETMON_NODE_VERSION = 'version'
|
211
211
|
|
212
|
+
|
213
|
+
|
212
214
|
|
213
215
|
class NET_CONFIG:
|
214
216
|
STORE_COMMAND = "SET_CONFIG"
|
@@ -216,4 +218,8 @@ class NET_CONFIG:
|
|
216
218
|
NET_CONFIG_DATA = 'NET_CONFIG_DATA'
|
217
219
|
OPERATION = 'OP'
|
218
220
|
DESTINATION = 'DEST'
|
219
|
-
DATA = 'DATA'
|
221
|
+
DATA = 'DATA'
|
222
|
+
|
223
|
+
PIPELINES = "PIPELINES"
|
224
|
+
PLUGINS_STATUSES = "PLUGIN_STATUSES"
|
225
|
+
|