1717import glob
1818import tempfile
1919
20-
2120# protocol 1_0_0 should have accounts.toml
2221# All other protocols should have chainspec.toml, config.toml and NOT accounts.toml
2322# Protocols are shipped with config-example.toml to make config.toml
@@ -42,8 +41,9 @@ class NodeUtil:
4241 DB_PATH = Path ("/var/lib/casper/casper-node" )
4342 NET_CONFIG_PATH = CONFIG_PATH / "network_configs"
4443 PLATFORM_PATH = CONFIG_PATH / "PLATFORM"
45- SCRIPT_NAME = "node_util.py "
44+ SCRIPT_NAME = "casper-casper-node-util "
4645 NODE_IP = "127.0.0.1"
46+ VERSION = "1.0.7"
4747
4848 def __init__ (self ):
4949 self ._network_name = None
@@ -56,9 +56,8 @@ def __init__(self):
5656 try :
5757 usage_docs .append (f" { function } - { getattr (self , function ).__doc__ .strip ()} " )
5858 except AttributeError :
59- raise Exception (
60- f"Error creating usage docs, expecting { function } to be root function and have doc comment."
61- f" Lead with underscore if not." )
59+ raise Exception (f"Error creating usage docs, expecting { function } to be root function and have doc comment."
60+ f" Lead with underscore if not." )
6261 commands .append (function )
6362 usage_docs .append (" " )
6463
@@ -69,6 +68,7 @@ def __init__(self):
6968 usage = "\n " .join (usage_docs ))
7069 parser .add_argument ("command" , help = "Subcommand to run." , choices = commands )
7170 args = parser .parse_args (sys .argv [1 :2 ])
71+
7272 getattr (self , args .command )()
7373
7474 @staticmethod
@@ -82,6 +82,10 @@ def _rpc_call(method: str, server: str, params: list, port: int = 7777, timeout:
8282 json_data = json .loads (r .read ())
8383 return json_data ["result" ]
8484
85+ def version (self ):
86+ """ Get current version of casper-node-util """
87+ print (self .VERSION )
88+
8589 @staticmethod
8690 def _rpc_get_block (server : str , block_height = None , port : int = 7777 , timeout : int = 5 ):
8791 """
@@ -214,22 +218,8 @@ def _pull_protocol_version(self, protocol_version, platform="deb"):
214218 print (f"Error: expected config file location { NodeUtil .CONFIG_PATH } not found." )
215219 exit (1 )
216220
217- # Expectation is one config.tar.gz but multiple bin*.tar.gz
218- # bin.tar.gz is mainnet bin and debian
219- # bin_new.tar.gz is post 1.4.0 launch and debian
220- # bin_rpm.tar.gz is mainnet bin and RHEL (_arch will be used for others in the future)
221- # bin_rpm_new.tar.gz is post 1.4.0 launch and RHEL
222-
223- bin_file = "bin"
224- if platform != "deb" :
225- # Handle alternative builds
226- bin_file += f"_{ platform } "
227- if self ._bin_mode != "mainnet" :
228- # Handle non mainnet for post 1.4.0 launched networks
229- bin_file += "_new"
230- bin_file += ".tar.gz"
221+ bin_file = "bin.tar.gz"
231222 config_file = "config.tar.gz"
232- print (f"Using bin mode file of { bin_file } " )
233223
234224 etc_full_path = NodeUtil .CONFIG_PATH / protocol_version
235225 bin_full_path = NodeUtil .BIN_PATH / protocol_version
@@ -355,6 +345,8 @@ def _replace_config_values(config_data, replace_file):
355345 new_output .append (f"{ name } = { new_value } " )
356346 else :
357347 new_output .append (line )
348+ # Make trailing new line
349+ new_output .append ("" )
358350 return "\n " .join (new_output )
359351
360352 def _config_from_example (self , protocol_version , ip = None , replace_toml = None ):
@@ -394,7 +386,7 @@ def _config_from_example(self, protocol_version, ip=None, replace_toml=None):
394386 config_text = NodeUtil ._replace_config_values (config_text , replace_toml )
395387
396388 outfile .write_text (config_text .replace ("<IP ADDRESS>" , ip ))
397-
389+
398390 return True
399391
400392 def config_from_example (self ):
@@ -624,7 +616,7 @@ def force_run_version(self):
624616 self ._verify_root_user ()
625617 state_path = self .CONFIG_PATH / "casper-node-launcher-state.toml"
626618 lines = ["mode = 'RunNodeAsValidator'" ,
627- f"version = '{ version .replace ('_' , '.' )} '" ,
619+ f"version = '{ version .replace ('_' ,'.' )} '" ,
628620 f"binary_path = '/var/lib/casper/bin/{ version } /casper-node'" ,
629621 f"config_path = '/etc/casper/{ version } /config.toml'" ]
630622 state_path .write_text ("\n " .join (lines ))
@@ -837,9 +829,6 @@ def get_trusted_hash(self):
837829 help = "Protocol version for chainspec to verify same network" ,
838830 required = False ,
839831 default = "1_0_0" )
840- parser .add_argument ("--block" ,
841- help = "Block number to use (latest if omitted)" ,
842- required = False )
843832
844833 args = parser .parse_args (sys .argv [2 :])
845834
@@ -866,25 +855,87 @@ def get_trusted_hash(self):
866855 if last_added_block_info is None :
867856 print (f"No last_added_block_info in { args .ip } status. Node is not in sync and will not be used." )
868857 exit (1 )
869- # If no block, getting latest so store now
870858 block_hash = last_added_block_info ["hash" ]
871- if args .block :
872- try :
873- block = self ._rpc_get_block (server = args .ip , block_height = args .block )
874- block_hash = block ["block" ]["hash" ]
875- except Exception as e :
876- if "timed out" in str (e ):
877- print (f"RPC call timed out, either { args .ip } has RPC port blocked or is not in sync." )
878- else :
879- print (f"Error calling RPC for { args .ip } ." )
880- exit (1 )
881859 print (f"{ block_hash } " )
882860
883861 def get_ip (self ):
884862 """ Get external IP of node. Can be used to test code used for automatically filling IP
885863 or to check if you need to update the IP in your config.toml file. """
886864 print (self ._get_external_ip ())
887865
866+ def node_log (self ):
867+ """ Get nodes current logs. Same as 'cat /var/log/casper-node.log` with grep added if using arguments
868+ and tail if following. """
869+ parser = argparse .ArgumentParser (description = self .node_log .__doc__ ,
870+ usage = f"{ self .SCRIPT_NAME } node_log [--err] [--warn] [--follow]" )
871+ parser .add_argument ("--err" ,
872+ help = "Return log lines with level ERR" ,
873+ action = 'store_true' ,
874+ required = False )
875+ parser .add_argument ("--warn" ,
876+ help = "Return log lines with level WARN" ,
877+ action = 'store_true' ,
878+ required = False )
879+ parser .add_argument ("--follow" ,
880+ help = "Follow log file as lines are added" ,
881+ action = 'store_true' ,
882+ required = False )
883+ args = parser .parse_args (sys .argv [2 :])
884+
885+ grep_args = ""
886+ grep_args += " -e '\" level\" :\" ERR\" '" if args .err else ""
887+ grep_args += " -e '\" level\" :\" WARN\" '" if args .warn else ""
888+
889+ grep = f" | grep { grep_args } " if len (grep_args ) > 0 else ""
890+
891+ main_cmd = "tail -f" if args .follow else "cat"
892+
893+ os .system (f"{ main_cmd } /var/log/casper/casper-node.log { grep } " )
894+
895+ @staticmethod
896+ def node_error_log ():
897+ """ Get nodes current teardown error log. Same as 'cat /var/log/casper-node.stderr.log` """
898+ os .system ("cat /var/log/casper/casper-node.stderr.log" )
899+
900+ @staticmethod
901+ def sidecar_status ():
902+ """ Get systemd status of casper-sidecar. Same as `systemctl status casper-sidecar` """
903+ # using op.popen to stop hanging return to terminate
904+ result = os .popen ("systemctl status casper-sidecar" )
905+ print (result .read ())
906+
907+ def sidecar_log (self ):
908+ """ Get log from casper-sidecar. Same as `journalctl -u casper-sidecar --no-pager` """
909+ parser = argparse .ArgumentParser (description = self .sidecar_log .__doc__ ,
910+ usage = f"{ self .SCRIPT_NAME } sidecar_log [--follow]" )
911+ parser .add_argument ("--follow" ,
912+ help = "Follow log file as lines are added" ,
913+ action = 'store_true' ,
914+ required = False )
915+
916+ args = parser .parse_args (sys .argv [2 :])
917+ follow = "--follow" if args .follow else ""
918+ os .system (f"journalctl -u casper-sidecar --no-pager { follow } " )
919+
920+ def sidecar_stop (self ):
921+ """ Stop casper-sidecar. Use 'sudo'.
922+ Same as `sudo systemctl stop casper-sidecar` """
923+ self ._verify_root_user ()
924+ os .system ("sudo systemctl stop casper-sidecar" )
925+
926+ def sidecar_start (self ):
927+ """ Start casper-sidecar. Use 'sudo'.
928+ Same as `sudo systemctl start casper-sidecar` """
929+ self ._verify_root_user ()
930+ os .system ("sudo systemctl start casper-sidecar" )
931+
932+ def sidecar_restart (self ):
933+ """ Restart casper-sidecar. Use 'sudo'. """
934+ self ._verify_root_user ()
935+ self .sidecar_stop ()
936+ time .sleep (0.5 )
937+ self .sidecar_start ()
938+
888939
889940if __name__ == '__main__' :
890941 NodeUtil ()
0 commit comments