├── docs ├── CHANGES.md ├── scenario_1.rst ├── scenario_2.rst ├── scenario_3.rst ├── images │ ├── .directory │ ├── star_button.png │ ├── start_button.png │ ├── stop_button.png │ ├── crashed_running.png │ ├── refresh_button.png │ ├── restart_button.png │ ├── shutdown_button.png │ ├── supvisors_flask.png │ ├── supvisors_menu.png │ ├── standard_running.png │ ├── autorefresh_button.png │ ├── supvisors_gathering.png │ ├── supvisors_main_page.png │ ├── supvisors_scenario_1.png │ ├── supvisors_scenario_2.png │ ├── supvisors_scenario_3.png │ ├── supvisors_flask_example.png │ ├── supvisors_application_page.png │ ├── supvisors_conciliation_page.png │ ├── supvisors_address_host_section.png │ ├── supvisors_main_page_user_sync.png │ ├── supvisors_address_process_section.png │ └── supvisors_conflict_application_page.png ├── requirements.txt ├── Makefile ├── index.rst ├── common.rst ├── conf.py └── faq.rst ├── supvisors ├── client │ ├── __init__.py │ ├── java │ │ ├── org │ │ │ └── supvisors │ │ │ │ └── common │ │ │ │ ├── SupvisorsAnyInfo.java │ │ │ │ ├── StartingFailureStrategy.java │ │ │ │ ├── DistributionRule.java │ │ │ │ ├── SupvisorsFailureStrategies.java │ │ │ │ ├── ConciliationStrategy.java │ │ │ │ ├── StartingStrategy.java │ │ │ │ ├── RunningFailureStrategy.java │ │ │ │ ├── LoggerLevels.java │ │ │ │ ├── SupvisorsInstanceState.java │ │ │ │ ├── SupvisorsState.java │ │ │ │ ├── ProcessState.java │ │ │ │ ├── SupervisorFaults.java │ │ │ │ ├── SupervisorLogResult.java │ │ │ │ ├── SupervisorState.java │ │ │ │ ├── SupvisorsStateModes.java │ │ │ │ ├── SupervisorConfigUpdates.java │ │ │ │ └── SupvisorsStatus.java │ │ └── build.xml │ └── clientutils.py ├── tools │ ├── __init__.py │ ├── apis │ │ ├── __init__.py │ │ ├── system_namespace.py │ │ └── utils.py │ └── supvisorsflask.py ├── web │ ├── __init__.py │ └── viewmaintail.py ├── internal_com │ └── __init__.py ├── version.txt ├── test │ ├── scripts │ │ ├── __init__.py │ │ ├── java_client.sh │ │ ├── stop_all.sh │ │ ├── start_all.sh │ │ ├── start_all_mc.sh │ │ ├── evt_listener.py │ │ ├── supervisorctl_test.sh │ │ └── process_app.py │ ├── etc │ │ ├── supvisors01.cliche.bzh │ │ ├── supvisors02.cliche.bzh │ │ ├── common │ │ │ ├── player │ │ │ │ ├── group_player.ini │ │ │ │ ├── program_movie_player.ini │ │ │ │ └── program_test_reader.ini │ │ │ ├── web_movies │ │ │ │ ├── group_web_movies.ini │ │ │ │ └── program_web_browser.ini │ │ │ ├── database │ │ │ │ ├── group_database.ini │ │ │ │ ├── program_register_movies.ini │ │ │ │ └── program_movie_server.ini │ │ │ ├── import_database │ │ │ │ ├── group_import_database.ini │ │ │ │ ├── program_mount_disk.ini │ │ │ │ └── program_copy_error.ini │ │ │ └── my_movies │ │ │ │ ├── group_my_movies.ini │ │ │ │ ├── program_error_disk_writer.ini │ │ │ │ ├── program_error_disk_reader.ini │ │ │ │ ├── program_hmi.ini │ │ │ │ ├── program_manager.ini │ │ │ │ ├── program_web_server.ini │ │ │ │ ├── program_converter.ini │ │ │ │ ├── program_restart_application.ini │ │ │ │ └── program_restart_process.ini │ │ ├── rocky52 │ │ │ ├── group_service.ini │ │ │ ├── program_disk_handler.ini │ │ │ └── program_disk_writer.ini │ │ ├── rocky51 │ │ │ ├── service │ │ │ │ ├── group_service.ini │ │ │ │ ├── program_flask.ini │ │ │ │ ├── program_evt_listener.ini │ │ │ │ ├── program_disk_reader.ini │ │ │ │ └── program_disk_writer.ini │ │ │ └── test │ │ │ │ ├── group_test.ini │ │ │ │ ├── program_check_flask.ini │ │ │ │ ├── program_check_start_sequence.ini │ │ │ │ ├── program_check_stop_sequence.ini │ │ │ │ ├── program_check_running_strategy.ini │ │ │ │ ├── program_check_starting_strategy.ini │ │ │ │ └── program_check_conciliation_strategy.ini │ │ ├── supv-03 │ │ │ └── program_disk_handler.ini │ │ ├── my_movies_test.xml │ │ ├── supervisord_alt_mc.conf │ │ ├── supervisord_alt.conf │ │ ├── supervisord_mc.conf │ │ └── supervisord.conf │ ├── use_cases │ │ ├── gathering │ │ │ ├── bin │ │ │ │ ├── scen1 │ │ │ │ ├── scen2 │ │ │ │ └── scen3 │ │ │ ├── etc │ │ │ │ ├── scenario_1 │ │ │ │ ├── scenario_2 │ │ │ │ ├── scenario_3 │ │ │ │ ├── supervisord_server_localhost.conf │ │ │ │ ├── supervisord_server_mc.conf │ │ │ │ ├── supervisord_console_mc.conf │ │ │ │ ├── supervisord_console_localhost.conf │ │ │ │ ├── supervisord_server.conf │ │ │ │ └── supervisord_console.conf │ │ │ ├── start_localhost_mc.sh │ │ │ ├── start_localhost.sh │ │ │ ├── start.sh │ │ │ ├── start_mc.sh │ │ │ └── configure.sh │ │ ├── scenario_1 │ │ │ ├── etc │ │ │ │ ├── supvisors01.cliche.bzh │ │ │ │ ├── supvisors02.cliche.bzh │ │ │ │ ├── supvisors03.cliche.bzh │ │ │ │ ├── rocky52 │ │ │ │ │ ├── group_rocky52.ini │ │ │ │ │ ├── wait_nfs_mount.ini │ │ │ │ │ └── programs_rocky52.ini │ │ │ │ ├── rocky53 │ │ │ │ │ ├── group_rocky53.ini │ │ │ │ │ ├── wait_nfs_mount.ini │ │ │ │ │ └── programs_rocky53.ini │ │ │ │ ├── rocky51 │ │ │ │ │ ├── group_rocky51.ini │ │ │ │ │ ├── wait_nfs_mount.ini │ │ │ │ │ └── programs_rocky51.ini │ │ │ │ ├── localhost │ │ │ │ │ └── group_localhost.ini │ │ │ │ ├── supervisord_localhost.conf │ │ │ │ ├── supervisord_distributed.conf │ │ │ │ ├── supervisord_distributed_mc.conf │ │ │ │ └── supvisors_rules.xml │ │ │ ├── bin │ │ │ │ └── scen1 │ │ │ │ │ ├── wait_nfs_mount.sh │ │ │ │ │ ├── common.sh │ │ │ │ │ ├── hci.sh │ │ │ │ │ ├── config_manager.sh │ │ │ │ │ ├── data_processing.sh │ │ │ │ │ ├── data_recorder.sh │ │ │ │ │ ├── external_interface.sh │ │ │ │ │ ├── sensor_acquisition.sh │ │ │ │ │ └── sensor_processing.sh │ │ │ ├── start_localhost.sh │ │ │ ├── start.sh │ │ │ └── start_mc.sh │ │ ├── scenario_2 │ │ │ ├── bin │ │ │ │ └── scen2 │ │ │ │ │ ├── check_internal_data_bus.sh │ │ │ │ │ ├── common.sh │ │ │ │ │ ├── chart_view.sh │ │ │ │ │ ├── sensor_view.sh │ │ │ │ │ ├── config_manager.sh │ │ │ │ │ ├── data_processing.sh │ │ │ │ │ ├── sensor_control.sh │ │ │ │ │ ├── common_bus_interface.sh │ │ │ │ │ ├── internal_data_bus.sh │ │ │ │ │ ├── sensor_acquisition.sh │ │ │ │ │ └── check_common_data_bus.sh │ │ │ ├── etc │ │ │ │ ├── console │ │ │ │ │ ├── group_scen2_hci_01.ini │ │ │ │ │ ├── group_scen2_hci_02.ini │ │ │ │ │ ├── group_scen2_hci_03.ini │ │ │ │ │ └── programs_console.ini │ │ │ │ ├── server │ │ │ │ │ ├── group_scen2_srv_01.ini │ │ │ │ │ ├── group_scen2_srv_02.ini │ │ │ │ │ ├── group_scen2_srv_03.ini │ │ │ │ │ └── programs_server.ini │ │ │ │ ├── common │ │ │ │ │ └── programs_services.ini │ │ │ │ ├── supervisord_server_mc.conf │ │ │ │ ├── supervisord_console_mc.conf │ │ │ │ ├── supervisord_server.conf │ │ │ │ ├── supervisord_console.conf │ │ │ │ ├── supvisors_rules_mc.xml │ │ │ │ └── supvisors_rules.xml │ │ │ ├── template_etc │ │ │ │ ├── console │ │ │ │ │ ├── group_console.ini │ │ │ │ │ └── programs_console.ini │ │ │ │ └── server │ │ │ │ │ ├── group_server.ini │ │ │ │ │ └── programs_server.ini │ │ │ ├── start.sh │ │ │ └── start_mc.sh │ │ └── scenario_3 │ │ │ ├── bin │ │ │ └── scen3 │ │ │ │ ├── common.sh │ │ │ │ ├── chart_view.sh │ │ │ │ ├── item_control.sh │ │ │ │ ├── item_manager.sh │ │ │ │ ├── system_health.sh │ │ │ │ ├── track_manager.sh │ │ │ │ ├── common_bus_interface.sh │ │ │ │ ├── internal_data_bus.sh │ │ │ │ ├── check_common_data_bus.sh │ │ │ │ └── check_internal_data_bus.sh │ │ │ ├── template_etc │ │ │ └── console │ │ │ │ ├── group_console.ini │ │ │ │ └── programs_console.ini │ │ │ ├── etc │ │ │ ├── console │ │ │ │ ├── console_1 │ │ │ │ │ └── group_scen3_hci_01.ini │ │ │ │ ├── console_2 │ │ │ │ │ └── group_scen3_hci_02.ini │ │ │ │ ├── console_3 │ │ │ │ │ └── group_scen3_hci_03.ini │ │ │ │ ├── console_4 │ │ │ │ │ └── group_scen3_hci_04.ini │ │ │ │ ├── console_5 │ │ │ │ │ └── group_scen3_hci_05.ini │ │ │ │ └── programs_console.ini │ │ │ ├── common │ │ │ │ └── group_services.ini │ │ │ ├── supervisord_server_mc.conf │ │ │ ├── supervisord_server.conf │ │ │ ├── supervisord_console.conf │ │ │ ├── supervisord_console_mc.conf │ │ │ ├── server │ │ │ │ └── group_server.ini │ │ │ ├── supvisors_rules_mc.xml │ │ │ └── supvisors_rules.xml │ │ │ ├── configure.sh │ │ │ ├── start.sh │ │ │ └── start_mc.sh │ ├── test_supervisor_177 │ │ ├── bin │ │ │ └── evt_listener.py │ │ └── etc │ │ │ └── supervisord.conf │ └── ui │ │ └── test.css ├── tests │ ├── __init__.py │ ├── test_clientutils.py │ └── test_plot.py ├── ui │ ├── img │ │ ├── icon.png │ │ ├── erro_20.png │ │ ├── info_20.png │ │ ├── stop_40.png │ │ ├── warn_20.png │ │ ├── reload_30.png │ │ ├── restart_40.png │ │ ├── start_40.png │ │ ├── supvisors.png │ │ ├── leds_red_30.png │ │ ├── red_light_30.png │ │ ├── shutdown_40.png │ │ ├── arrow-orange_12.png │ │ ├── auto_reload_30.png │ │ ├── leds_empty_30.png │ │ ├── leds_green_30.png │ │ ├── leds_yellow_30.png │ │ └── model │ │ │ ├── supvisors_icon.xcf │ │ │ └── supvisors_logo.xcf │ ├── fonts │ │ ├── Kingthings_Calligraphica_2-webfont.eot │ │ ├── Kingthings_Calligraphica_2-webfont.ttf │ │ └── Kingthings_Calligraphica_2-webfont.woff │ └── css │ │ ├── proc_instance.css │ │ ├── instance.css │ │ ├── conciliation.css │ │ ├── card.css │ │ ├── application.css │ │ ├── index.css │ │ ├── message.css │ │ ├── button.css │ │ ├── header.css │ │ └── process_table.css ├── external_com │ └── __init__.py └── __init__.py ├── setup.cfg ├── MANIFEST.in ├── .coveragerc ├── .gitignore ├── .readthedocs.yaml ├── tox.ini └── .github └── workflows └── ci.yml /docs/CHANGES.md: -------------------------------------------------------------------------------- 1 | ../CHANGES.md -------------------------------------------------------------------------------- /supvisors/client/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /supvisors/tools/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /supvisors/web/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /supvisors/internal_com/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /supvisors/version.txt: -------------------------------------------------------------------------------- 1 | version=0.19 2 | -------------------------------------------------------------------------------- /supvisors/test/scripts/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /supvisors/test/etc/supvisors01.cliche.bzh: -------------------------------------------------------------------------------- 1 | rocky51 -------------------------------------------------------------------------------- /supvisors/test/etc/supvisors02.cliche.bzh: -------------------------------------------------------------------------------- 1 | rocky52 -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description_file = README.md 3 | -------------------------------------------------------------------------------- /docs/scenario_1.rst: -------------------------------------------------------------------------------- 1 | ../supvisors/test/use_cases/scenario_1/scenario_1.rst -------------------------------------------------------------------------------- /docs/scenario_2.rst: -------------------------------------------------------------------------------- 1 | ../supvisors/test/use_cases/scenario_2/scenario_2.rst -------------------------------------------------------------------------------- /docs/scenario_3.rst: -------------------------------------------------------------------------------- 1 | ../supvisors/test/use_cases/scenario_3/scenario_3.rst -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/bin/scen1: -------------------------------------------------------------------------------- 1 | ../../scenario_1/bin/scen1 -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/bin/scen2: -------------------------------------------------------------------------------- 1 | ../../scenario_2/bin/scen2 -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/bin/scen3: -------------------------------------------------------------------------------- 1 | ../../scenario_3/bin/scen3 -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/etc/scenario_1: -------------------------------------------------------------------------------- 1 | ../../scenario_1/etc -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/etc/scenario_2: -------------------------------------------------------------------------------- 1 | ../../scenario_2/etc -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/etc/scenario_3: -------------------------------------------------------------------------------- 1 | ../../scenario_3/etc -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/supvisors01.cliche.bzh: -------------------------------------------------------------------------------- 1 | rocky51 -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/supvisors02.cliche.bzh: -------------------------------------------------------------------------------- 1 | rocky52 -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/supvisors03.cliche.bzh: -------------------------------------------------------------------------------- 1 | rocky53 -------------------------------------------------------------------------------- /supvisors/test/test_supervisor_177/bin/evt_listener.py: -------------------------------------------------------------------------------- 1 | ../../scripts/evt_listener.py -------------------------------------------------------------------------------- /supvisors/tests/__init__.py: -------------------------------------------------------------------------------- 1 | __import__('pkg_resources').declare_namespace(__name__) 2 | -------------------------------------------------------------------------------- /supvisors/test/ui/test.css: -------------------------------------------------------------------------------- 1 | footer p:last-of-type { 2 | color: var(--crash-color); 3 | } -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/bin/scen1/wait_nfs_mount.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 5 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/bin/scen1/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | zenity --info --text=$1 3 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/check_internal_data_bus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 5 3 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | zenity --info --text=$1 3 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/bin/scen3/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | zenity --info --text=$1 3 | -------------------------------------------------------------------------------- /docs/images/.directory: -------------------------------------------------------------------------------- 1 | [Dolphin] 2 | PreviewsShown=true 3 | Timestamp=2017,8,10,18,24,35 4 | Version=3 5 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/player/group_player.ini: -------------------------------------------------------------------------------- 1 | [group:player] 2 | programs=test_reader,movie_player 3 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/web_movies/group_web_movies.ini: -------------------------------------------------------------------------------- 1 | [group:web_movies] 2 | programs=web_browser 3 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky52/group_service.ini: -------------------------------------------------------------------------------- 1 | [group:service] 2 | programs=disk_handler,disk_writer_82 3 | -------------------------------------------------------------------------------- /supvisors/ui/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/icon.png -------------------------------------------------------------------------------- /docs/images/star_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/star_button.png -------------------------------------------------------------------------------- /docs/images/start_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/start_button.png -------------------------------------------------------------------------------- /docs/images/stop_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/stop_button.png -------------------------------------------------------------------------------- /supvisors/ui/img/erro_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/erro_20.png -------------------------------------------------------------------------------- /supvisors/ui/img/info_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/info_20.png -------------------------------------------------------------------------------- /supvisors/ui/img/stop_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/stop_40.png -------------------------------------------------------------------------------- /supvisors/ui/img/warn_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/warn_20.png -------------------------------------------------------------------------------- /docs/images/crashed_running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/crashed_running.png -------------------------------------------------------------------------------- /docs/images/refresh_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/refresh_button.png -------------------------------------------------------------------------------- /docs/images/restart_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/restart_button.png -------------------------------------------------------------------------------- /docs/images/shutdown_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/shutdown_button.png -------------------------------------------------------------------------------- /docs/images/supvisors_flask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_flask.png -------------------------------------------------------------------------------- /docs/images/supvisors_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_menu.png -------------------------------------------------------------------------------- /supvisors/test/etc/common/database/group_database.ini: -------------------------------------------------------------------------------- 1 | [group:database] 2 | programs=movie_server,register_movies 3 | -------------------------------------------------------------------------------- /supvisors/ui/img/reload_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/reload_30.png -------------------------------------------------------------------------------- /supvisors/ui/img/restart_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/restart_40.png -------------------------------------------------------------------------------- /supvisors/ui/img/start_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/start_40.png -------------------------------------------------------------------------------- /supvisors/ui/img/supvisors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/supvisors.png -------------------------------------------------------------------------------- /docs/images/standard_running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/standard_running.png -------------------------------------------------------------------------------- /supvisors/ui/img/leds_red_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/leds_red_30.png -------------------------------------------------------------------------------- /supvisors/ui/img/red_light_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/red_light_30.png -------------------------------------------------------------------------------- /supvisors/ui/img/shutdown_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/shutdown_40.png -------------------------------------------------------------------------------- /docs/images/autorefresh_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/autorefresh_button.png -------------------------------------------------------------------------------- /docs/images/supvisors_gathering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_gathering.png -------------------------------------------------------------------------------- /docs/images/supvisors_main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_main_page.png -------------------------------------------------------------------------------- /docs/images/supvisors_scenario_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_scenario_1.png -------------------------------------------------------------------------------- /docs/images/supvisors_scenario_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_scenario_2.png -------------------------------------------------------------------------------- /docs/images/supvisors_scenario_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_scenario_3.png -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/service/group_service.ini: -------------------------------------------------------------------------------- 1 | [group:service] 2 | programs=disk_handler,disk_writer_81,supvisorsflask 3 | -------------------------------------------------------------------------------- /supvisors/ui/img/arrow-orange_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/arrow-orange_12.png -------------------------------------------------------------------------------- /supvisors/ui/img/auto_reload_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/auto_reload_30.png -------------------------------------------------------------------------------- /supvisors/ui/img/leds_empty_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/leds_empty_30.png -------------------------------------------------------------------------------- /supvisors/ui/img/leds_green_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/leds_green_30.png -------------------------------------------------------------------------------- /supvisors/ui/img/leds_yellow_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/leds_yellow_30.png -------------------------------------------------------------------------------- /supvisors/test/etc/common/import_database/group_import_database.ini: -------------------------------------------------------------------------------- 1 | [group:import_database] 2 | programs=mount_disk,copy_error 3 | -------------------------------------------------------------------------------- /docs/images/supvisors_flask_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_flask_example.png -------------------------------------------------------------------------------- /supvisors/ui/img/model/supvisors_icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/model/supvisors_icon.xcf -------------------------------------------------------------------------------- /supvisors/ui/img/model/supvisors_logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/img/model/supvisors_logo.xcf -------------------------------------------------------------------------------- /docs/images/supvisors_application_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_application_page.png -------------------------------------------------------------------------------- /docs/images/supvisors_conciliation_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_conciliation_page.png -------------------------------------------------------------------------------- /docs/images/supvisors_address_host_section.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_address_host_section.png -------------------------------------------------------------------------------- /docs/images/supvisors_main_page_user_sync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_main_page_user_sync.png -------------------------------------------------------------------------------- /docs/images/supvisors_address_process_section.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_address_process_section.png -------------------------------------------------------------------------------- /docs/images/supvisors_conflict_application_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/docs/images/supvisors_conflict_application_page.png -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==7.2.6 2 | renku-sphinx-theme==0.4.0 3 | myst-parser==2.0.0 4 | supervisor==4.2.5 5 | websockets==11.0.3 6 | pyzmq==25.1.1 7 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/rocky52/group_rocky52.ini: -------------------------------------------------------------------------------- 1 | [group:scen1] 2 | programs=scen1_wait_nfs_mount_2,scen1_sensor_acquisition_1,scen1_sensor_processing_1 3 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/rocky53/group_rocky53.ini: -------------------------------------------------------------------------------- 1 | [group:scen1] 2 | programs=scen1_wait_nfs_mount_3,scen1_sensor_acquisition_2,scen1_sensor_processing_2 3 | -------------------------------------------------------------------------------- /supvisors/ui/fonts/Kingthings_Calligraphica_2-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/fonts/Kingthings_Calligraphica_2-webfont.eot -------------------------------------------------------------------------------- /supvisors/ui/fonts/Kingthings_Calligraphica_2-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/fonts/Kingthings_Calligraphica_2-webfont.ttf -------------------------------------------------------------------------------- /supvisors/ui/fonts/Kingthings_Calligraphica_2-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julien6387/supvisors/HEAD/supvisors/ui/fonts/Kingthings_Calligraphica_2-webfont.woff -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/bin/scen1/hci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/template_etc/console/group_console.ini: -------------------------------------------------------------------------------- 1 | [group:scen3_hci] 2 | programs=scen3_chart_view,scen3_item_control,scen3_check_internal_data_bus 3 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/chart_view.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/sensor_view.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/bin/scen3/chart_view.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/bin/scen1/config_manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/bin/scen1/data_processing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/bin/scen1/data_recorder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/config_manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/data_processing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/sensor_control.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/bin/scen3/item_control.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/bin/scen3/item_manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/bin/scen3/system_health.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/bin/scen3/track_manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/bin/scen1/external_interface.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/bin/scen1/sensor_acquisition.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/bin/scen1/sensor_processing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/common_bus_interface.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/internal_data_bus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/sensor_acquisition.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/bin/scen3/common_bus_interface.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/bin/scen3/internal_data_bus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_dir=$(dirname "$(readlink -f "$0")") 4 | 5 | $test_dir/common.sh ${SUPERVISOR_PROCESS_NAME} 6 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/console/console_1/group_scen3_hci_01.ini: -------------------------------------------------------------------------------- 1 | [group:scen3_hci_01] 2 | programs = scen3_chart_view,scen3_item_control,scen3_check_internal_data_bus 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/console/console_2/group_scen3_hci_02.ini: -------------------------------------------------------------------------------- 1 | [group:scen3_hci_02] 2 | programs = scen3_chart_view,scen3_item_control,scen3_check_internal_data_bus 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/console/console_3/group_scen3_hci_03.ini: -------------------------------------------------------------------------------- 1 | [group:scen3_hci_03] 2 | programs = scen3_chart_view,scen3_item_control,scen3_check_internal_data_bus 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/console/console_4/group_scen3_hci_04.ini: -------------------------------------------------------------------------------- 1 | [group:scen3_hci_04] 2 | programs = scen3_chart_view,scen3_item_control,scen3_check_internal_data_bus 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/console/console_5/group_scen3_hci_05.ini: -------------------------------------------------------------------------------- 1 | [group:scen3_hci_05] 2 | programs = scen3_chart_view,scen3_item_control,scen3_check_internal_data_bus 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/my_movies/group_my_movies.ini: -------------------------------------------------------------------------------- 1 | [group:my_movies] 2 | programs=manager,web_server,hmi,error_disk_reader,error_disk_writer,converter,restart_process,restart_application 3 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include CHANGES.md 2 | include LICENSE 3 | include supvisors/version.txt 4 | include supvisors/rules.xsd 5 | graft supvisors/doc 6 | graft supvisors/ui 7 | prune supvisors/ui/img/model 8 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/test/group_test.ini: -------------------------------------------------------------------------------- 1 | [group:test] 2 | programs=check_start_sequence,check_stop_sequence,check_conciliation_strategy,check_starting_strategy,check_running_strategy,check_flask 3 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/rocky51/group_rocky51.ini: -------------------------------------------------------------------------------- 1 | [group:scen1] 2 | programs=scen1_wait_nfs_mount_1,scen1_hci,scen1_config_manager,scen1_data_processing,scen1_external_interface,scen1_data_recorder 3 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/console/group_scen2_hci_01.ini: -------------------------------------------------------------------------------- 1 | [group:scen2_hci_01] 2 | programs = scen2_chart_view,scen2_sensor_control,scen2_sensor_view,scen2_check_internal_data_bus,scen2_internal_data_bus 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/console/group_scen2_hci_02.ini: -------------------------------------------------------------------------------- 1 | [group:scen2_hci_02] 2 | programs = scen2_chart_view,scen2_sensor_control,scen2_sensor_view,scen2_check_internal_data_bus,scen2_internal_data_bus 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/console/group_scen2_hci_03.ini: -------------------------------------------------------------------------------- 1 | [group:scen2_hci_03] 2 | programs = scen2_chart_view,scen2_sensor_control,scen2_sensor_view,scen2_check_internal_data_bus,scen2_internal_data_bus 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/template_etc/console/group_console.ini: -------------------------------------------------------------------------------- 1 | [group:scen2_hci] 2 | programs=scen2_chart_view,scen2_sensor_control,scen2_sensor_view,scen2_check_internal_data_bus,scen2_internal_data_bus 3 | 4 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | supvisors/__init__.py 4 | supvisors/tests/__init__.py 5 | supvisors/tools/__init__.py 6 | 7 | [report] 8 | exclude_also = 9 | if __name__ == .__main__.: 10 | def test_.*_deprecated.*: 11 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/server/group_scen2_srv_01.ini: -------------------------------------------------------------------------------- 1 | [group:scen2_srv_01] 2 | programs = scen2_config_manager,scen2_common_bus_interface,scen2_check_common_data_bus,scen2_check_internal_data_bus,scen2_internal_data_bus,scen2_data_processing,scen2_sensor_acquisition 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/server/group_scen2_srv_02.ini: -------------------------------------------------------------------------------- 1 | [group:scen2_srv_02] 2 | programs = scen2_config_manager,scen2_common_bus_interface,scen2_check_common_data_bus,scen2_check_internal_data_bus,scen2_internal_data_bus,scen2_data_processing,scen2_sensor_acquisition 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/server/group_scen2_srv_03.ini: -------------------------------------------------------------------------------- 1 | [group:scen2_srv_03] 2 | programs = scen2_config_manager,scen2_common_bus_interface,scen2_check_common_data_bus,scen2_check_internal_data_bus,scen2_internal_data_bus,scen2_data_processing,scen2_sensor_acquisition 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/template_etc/server/group_server.ini: -------------------------------------------------------------------------------- 1 | [group:scen2_srv] 2 | programs=scen2_config_manager,scen2_common_bus_interface,scen2_check_common_data_bus,scen2_check_internal_data_bus,scen2_internal_data_bus,scen2_data_processing,scen2_sensor_acquisition 3 | 4 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/localhost/group_localhost.ini: -------------------------------------------------------------------------------- 1 | [group:scen1] 2 | programs=scen1_hci,scen1_config_manager,scen1_data_processing,scen1_external_interface,scen1_data_recorder,scen1_sensor_acquisition_1,scen1_sensor_processing_1,scen1_sensor_acquisition_2,scen1_sensor_processing_2 3 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/rocky51/wait_nfs_mount.ini: -------------------------------------------------------------------------------- 1 | [program:scen1_wait_nfs_mount_1] 2 | command=bin/scen1/wait_nfs_mount.sh 3 | autostart=false 4 | killasgroup=true 5 | stopasgroup=true 6 | redirect_stderr=true 7 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 8 | stdout_logfile_backups=5 9 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/rocky52/wait_nfs_mount.ini: -------------------------------------------------------------------------------- 1 | [program:scen1_wait_nfs_mount_2] 2 | command=bin/scen1/wait_nfs_mount.sh 3 | autostart=false 4 | killasgroup=true 5 | stopasgroup=true 6 | redirect_stderr=true 7 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 8 | stdout_logfile_backups=5 9 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/rocky53/wait_nfs_mount.ini: -------------------------------------------------------------------------------- 1 | [program:scen1_wait_nfs_mount_3] 2 | command=bin/scen1/wait_nfs_mount.sh 3 | autostart=false 4 | killasgroup=true 5 | stopasgroup=true 6 | redirect_stderr=true 7 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 8 | stdout_logfile_backups=5 9 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/common/programs_services.ini: -------------------------------------------------------------------------------- 1 | [program:common_data_bus] 2 | command = zenity --info --text=%(program_name)s 3 | startsecs = 40 4 | killasgroup = true 5 | stopasgroup = true 6 | redirect_stderr = true 7 | stdout_logfile = log/%(program_name)s_%(host_node_name)s.log 8 | stdout_logfile_backups = 5 9 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/my_movies/program_error_disk_writer.ini: -------------------------------------------------------------------------------- 1 | [program:error_disk_writer] 2 | command=python ./scripts/process_app.py -n %(program_name)s -x 2 3 | autostart=false 4 | autorestart=false 5 | startsecs=5 6 | startretries=1 7 | exitcodes=1 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | stdout_logfile=NONE 11 | stderr_logfile=OFF 12 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/player/program_movie_player.ini: -------------------------------------------------------------------------------- 1 | [program:movie_player] 2 | command=python ./scripts/process_app.py -n %(program_name)s 3 | autostart=false 4 | autorestart=false 5 | startretries=0 6 | redirect_stderr=true 7 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 8 | stdout_logfile_maxbytes=1MB 9 | stdout_logfile_backups=1 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .directory/ 2 | *.pyc 3 | *.pyo 4 | *.orig 5 | *.bak 6 | *.rej 7 | *.class 8 | *.jar 9 | *~ 10 | build/ 11 | .build/ 12 | .eggs/ 13 | .idea/ 14 | .settings/ 15 | dist/ 16 | cur/ 17 | htmlcov/ 18 | log/ 19 | tmp/ 20 | venv/ 21 | __pycache__/ 22 | *.DS_Store 23 | *.log 24 | *.coverage 25 | *.egg-info 26 | .project 27 | coverage.xml 28 | nosetests.xml 29 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/service/program_flask.ini: -------------------------------------------------------------------------------- 1 | [program:supvisorsflask] 2 | command=supvisorsflask -u http://supv01:30000 3 | autostart=true 4 | autorestart=unexpected 5 | startsecs=2 6 | startretries=0 7 | redirect_stderr=true 8 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s_out.log 9 | stdout_logfile_maxbytes=10KB 10 | stdout_logfile_backups=1 11 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/web_movies/program_web_browser.ini: -------------------------------------------------------------------------------- 1 | [program:web_browser] 2 | command=firefox --new-instance http://localhost:60000 3 | autostart=false 4 | autorestart=unexpected 5 | startsecs=5 6 | startretries=0 7 | redirect_stderr=true 8 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 9 | stdout_logfile_maxbytes=1MB 10 | stdout_logfile_backups=1 11 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/my_movies/program_error_disk_reader.ini: -------------------------------------------------------------------------------- 1 | [program:error_disk_reader] 2 | command=python ./scripts/process_app.py -n %(program_name)s -x 10 ; exit 11 3 | autostart=false 4 | autorestart=false 5 | startsecs=2 6 | startretries=3 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | redirect_stderr=True 11 | stdout_logfile=NONE 12 | stderr_logfile=OFF 13 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/service/program_evt_listener.ini: -------------------------------------------------------------------------------- 1 | [eventlistener:evt_listener] 2 | command=python ./scripts/evt_listener.py 3 | process_name=evt_listener_%(process_num)02d 4 | events=EVENT 5 | buffer_size=50 6 | autostart=true 7 | autorestart=false 8 | startsecs=1 9 | startretries=0 10 | stderr_logfile=./log/%(program_name)s_%(process_num)02d_%(host_node_name)s_err.log 11 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/test/program_check_flask.ini: -------------------------------------------------------------------------------- 1 | [program:check_flask] 2 | command=./scripts/supvisorsflask_test.sh 3 | autostart=false 4 | autorestart=false 5 | startsecs=0 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | redirect_stderr=true 11 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 12 | stdout_logfile_maxbytes=1MB 13 | stdout_logfile_backups=1 14 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/import_database/program_mount_disk.ini: -------------------------------------------------------------------------------- 1 | [program:mount_disk] 2 | command=python ./scripts/process_app.py -n %(program_name)s 3 | process_name=mount_disk_%(process_num)02d 4 | numprocs=2 5 | autostart=false 6 | autorestart=false 7 | startsecs=0 8 | redirect_stderr=true 9 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 10 | stdout_logfile_maxbytes=1MB 11 | stdout_logfile_backups=1 12 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/my_movies/program_hmi.ini: -------------------------------------------------------------------------------- 1 | [program:hmi] 2 | command=python ./scripts/process_app.py -n %(program_name)s 3 | autostart=false 4 | autorestart=unexpected 5 | startsecs=2 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | stdout_logfile=None 11 | stderr_logfile=./log/%(program_name)s_%(host_node_name)s_err.log 12 | stderr_logfile_maxbytes=10KB 13 | stderr_logfile_backups=1 14 | -------------------------------------------------------------------------------- /supvisors/test/scripts/java_client.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | ANT_FILE=../client/java/build.xml 4 | 5 | # test JAVA supvisors events 6 | ant -f $ANT_FILE run_supvisors_evt 7 | 8 | # test JAVA system XML-RPC 9 | ant -f $ANT_FILE run_system_rpc 10 | 11 | # test JAVA supervisor XML-RPC 12 | ant -f $ANT_FILE run_supervisor_rpc 13 | 14 | sleep 100 15 | 16 | # test JAVA supvisors XML-RPC 17 | ant -f $ANT_FILE run_supvisors_rpc 18 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/my_movies/program_manager.ini: -------------------------------------------------------------------------------- 1 | [program:manager] 2 | command=python ./scripts/process_app.py -n %(program_name)s 3 | autostart=false 4 | autorestart=unexpected 5 | startsecs=0 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s_out.log 11 | stdout_logfile_maxbytes=10KB 12 | stdout_logfile_backups=1 13 | stderr_logfile=off 14 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/player/program_test_reader.ini: -------------------------------------------------------------------------------- 1 | ; test a process that exits with an unexpected exit code 2 | [program:test_reader] 3 | command=python ./scripts/process_app.py -n %(program_name)s -x 2 4 | autostart=false 5 | autorestart=false 6 | startretries=0 7 | exitcodes=5 8 | redirect_stderr=true 9 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 10 | stdout_logfile_maxbytes=1MB 11 | stdout_logfile_backups=1 12 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/test/program_check_start_sequence.ini: -------------------------------------------------------------------------------- 1 | [program:check_start_sequence] 2 | command=python -m unittest scripts.check_start_sequence 3 | autostart=false 4 | autorestart=false 5 | startsecs=40 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | redirect_stderr=true 11 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 12 | stdout_logfile_maxbytes=1MB 13 | stdout_logfile_backups=1 14 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/test/program_check_stop_sequence.ini: -------------------------------------------------------------------------------- 1 | [program:check_stop_sequence] 2 | command=python -m unittest -c scripts.check_stop_sequence 3 | autostart=false 4 | autorestart=false 5 | startsecs=0 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=INT 9 | stopwaitsecs=10 10 | redirect_stderr=true 11 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 12 | stdout_logfile_maxbytes=1MB 13 | stdout_logfile_backups=1 14 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/test/program_check_running_strategy.ini: -------------------------------------------------------------------------------- 1 | [program:check_running_strategy] 2 | command=python -m unittest scripts.check_running_strategy 3 | autostart=false 4 | autorestart=false 5 | startsecs=0 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | redirect_stderr=true 11 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 12 | stdout_logfile_maxbytes=1MB 13 | stdout_logfile_backups=1 14 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/bin/scen2/check_common_data_bus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function common_data_bus_running() { 4 | local result=`supervisorctl -s http://localhost:61000 status common_data_bus | awk '{print $2}'` 5 | echo $result 6 | } 7 | 8 | while [ $(common_data_bus_running) != "RUNNING" ] 9 | do 10 | echo "Waiting for common_data_bus to be RUNNING" 11 | sleep 1 12 | done 13 | 14 | echo "common_data_bus is RUNNING" 15 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/bin/scen3/check_common_data_bus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function common_data_bus_running() { 4 | local result=`supervisorctl -s http://localhost:61000 status common_data_bus | awk '{print $2}'` 5 | echo $result 6 | } 7 | 8 | while [ $(common_data_bus_running) != "RUNNING" ] 9 | do 10 | echo "Waiting for common_data_bus to be RUNNING" 11 | sleep 1 12 | done 13 | 14 | echo "common_data_bus is RUNNING" 15 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/import_database/program_copy_error.ini: -------------------------------------------------------------------------------- 1 | ; test a process that exits before its RUNNING state is reached 2 | [program:copy_error] 3 | command=python ./scripts/process_app.py -n %(program_name)s -x 10 4 | autostart=false 5 | autorestart=false 6 | startsecs=15 7 | startretries=0 8 | redirect_stderr=true 9 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 10 | stdout_logfile_maxbytes=1MB 11 | stdout_logfile_backups=1 12 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/test/program_check_starting_strategy.ini: -------------------------------------------------------------------------------- 1 | [program:check_starting_strategy] 2 | command=python -m unittest scripts.check_starting_strategy 3 | autostart=false 4 | autorestart=false 5 | startsecs=0 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | redirect_stderr=true 11 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 12 | stdout_logfile_maxbytes=1MB 13 | stdout_logfile_backups=1 14 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/my_movies/program_web_server.ini: -------------------------------------------------------------------------------- 1 | [program:web_server] 2 | command=python ./scripts/process_app.py -n %(program_name)s 3 | autostart=false 4 | startsecs=5 5 | startretries=0 6 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s_out.log 7 | stdout_logfile_maxbytes=10KB 8 | stdout_logfile_backups=1 9 | stderr_logfile=./log/%(program_name)s_%(host_node_name)s_err.log 10 | stderr_logfile_maxbytes=10KB 11 | stderr_logfile_backups=1 12 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/test/program_check_conciliation_strategy.ini: -------------------------------------------------------------------------------- 1 | [program:check_conciliation_strategy] 2 | command=python -m unittest scripts.check_conciliation_strategy 3 | autostart=false 4 | autorestart=false 5 | startsecs=0 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | redirect_stderr=true 11 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 12 | stdout_logfile_maxbytes=1MB 13 | stdout_logfile_backups=1 14 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky52/program_disk_handler.ini: -------------------------------------------------------------------------------- 1 | [program:disk_handler] 2 | command=python ./scripts/process_app.py -n %(program_name)s 3 | autostart=true 4 | autorestart=false 5 | startsecs=2 6 | startretries=0 7 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s_out.log 8 | stdout_logfile_maxbytes=10KB 9 | stdout_logfile_backups=1 10 | stderr_logfile=./log/%(program_name)s_%(host_node_name)s_err.log 11 | stderr_logfile_maxbytes=10KB 12 | stderr_logfile_backups=1 13 | -------------------------------------------------------------------------------- /supvisors/test/etc/supv-03/program_disk_handler.ini: -------------------------------------------------------------------------------- 1 | [program:disk_handler] 2 | command=python ./scripts/process_app.py -n %(program_name)s 3 | autostart=true 4 | autorestart=false 5 | startsecs=2 6 | startretries=0 7 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s_out.log 8 | stdout_logfile_maxbytes=10KB 9 | stdout_logfile_backups=1 10 | stderr_logfile=./log/%(program_name)s_%(host_node_name)s_err.log 11 | stderr_logfile_maxbytes=10KB 12 | stderr_logfile_backups=1 13 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/service/program_disk_reader.ini: -------------------------------------------------------------------------------- 1 | [program:disk_handler] 2 | command=python ./scripts/process_app.py -n %(program_name)s 3 | autostart=true 4 | autorestart=false 5 | startsecs=2 6 | startretries=0 7 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s_out.log 8 | stdout_logfile_maxbytes=10KB 9 | stdout_logfile_backups=1 10 | stderr_logfile=./log/%(program_name)s_%(host_node_name)s_err.log 11 | stderr_logfile_maxbytes=10KB 12 | stderr_logfile_backups=1 13 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/bin/scen3/check_internal_data_bus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function internal_data_bus_running() { 4 | local result=`supvisorsctl -s ${SUPERVISOR_SERVER_URL} sstatus scen3_internal_data_bus | tail -1 | awk '{print $3}'` 5 | echo $result 6 | } 7 | 8 | while [ $(internal_data_bus_running) != "RUNNING" ] 9 | do 10 | echo "Waiting for scen3_internal_data_bus to be RUNNING" 11 | sleep 1 12 | done 13 | 14 | echo "scen3_internal_data_bus is RUNNING" 15 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/my_movies/program_converter.ini: -------------------------------------------------------------------------------- 1 | [program:converter] 2 | command=python ./scripts/process_app.py -n %(program_name)s -x 60 3 | process_name=converter_%(process_num)02d 4 | numprocs=15 5 | autostart=false 6 | autorestart=false 7 | startsecs=2 8 | startretries=0 9 | exitcodes=0 10 | stopsignal=TERM 11 | stopwaitsecs=10 12 | redirect_stderr=true 13 | stdout_logfile=./log/%(program_name)s_%(process_num)02d_%(host_node_name)s_out.log 14 | stdout_logfile_maxbytes=10KB 15 | stdout_logfile_backups=1 16 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/database/program_register_movies.ini: -------------------------------------------------------------------------------- 1 | [program:register_movies] 2 | command=python ./scripts/process_app.py -n %(program_name)s -x 5 3 | process_name=register_movies_%(process_num)02d 4 | numprocs=3 5 | numprocs_start=1 6 | autostart=false 7 | autorestart=false 8 | startsecs=1 9 | startretries=0 10 | exitcodes=0 11 | stopsignal=TERM 12 | stopwaitsecs=10 13 | redirect_stderr=true 14 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s.log 15 | stdout_logfile_maxbytes=1MB 16 | stdout_logfile_backups=1 17 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky52/program_disk_writer.ini: -------------------------------------------------------------------------------- 1 | [program:disk_writer_82] 2 | command=python ./scripts/process_app.py -n %(program_name)s -x 30 3 | autostart=false 4 | autorestart=false 5 | startsecs=5 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s_out.log 11 | stdout_logfile_maxbytes=10KB 12 | stdout_logfile_backups=1 13 | stderr_logfile=./log/%(program_name)s_%(host_node_name)s_err.log 14 | stderr_logfile_maxbytes=10KB 15 | stderr_logfile_backups=1 16 | -------------------------------------------------------------------------------- /supvisors/test/etc/rocky51/service/program_disk_writer.ini: -------------------------------------------------------------------------------- 1 | [program:disk_writer_81] 2 | command=python ./scripts/process_app.py -n %(program_name)s -x 30 3 | autostart=false 4 | autorestart=false 5 | startsecs=5 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s_out.log 11 | stdout_logfile_maxbytes=10KB 12 | stdout_logfile_backups=1 13 | stderr_logfile=./log/%(program_name)s_%(host_node_name)s_err.log 14 | stderr_logfile_maxbytes=10KB 15 | stderr_logfile_backups=1 16 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/database/program_movie_server.ini: -------------------------------------------------------------------------------- 1 | [program:movie_server] 2 | command=python ./scripts/process_app.py -n %(program_name)s_%(process_num)02d 3 | process_name=movie_server_%(process_num)02d 4 | numprocs=3 5 | numprocs_start=1 6 | autostart=false 7 | autorestart=false 8 | startsecs=1 9 | startretries=0 10 | exitcodes=0 11 | stopsignal=TERM 12 | stopwaitsecs=10 13 | redirect_stderr=true 14 | stdout_logfile=./log/%(program_name)s_%(process_num)02d_%(host_node_name)s.log 15 | stdout_logfile_maxbytes=1MB 16 | stdout_logfile_backups=1 17 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/start_localhost.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | cd $test_dir 6 | 7 | # clear log folder 8 | rm -rf log 9 | mkdir log 10 | 11 | # environmental variables for log file names 12 | export CUR_DATE=`date +'%y%m%d'` 13 | export CUR_TIME=`date +'%H%M%S'` 14 | 15 | # start firefox to get the Web UI 16 | firefox http://localhost:61000 & 17 | 18 | # start non-daemonized supervisor 19 | echo "start Supvisors on" `hostname` 20 | supervisord -c etc/supervisord_localhost.conf -n 21 | -------------------------------------------------------------------------------- /supvisors/test/scripts/stop_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # directories 4 | SCRIPT_DIR=`dirname $(readlink -e $0)` 5 | TEST_DIR=`readlink -e $SCRIPT_DIR/..` 6 | 7 | # change working directory 8 | pushd . 9 | cd $TEST_DIR 10 | 11 | # stop all instances 12 | # multicast version not needed as supervisorctl is independent from that 13 | for host in ${@:-rocky51 rocky52} 14 | do 15 | echo "stop Supervisor on host" $host 16 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $TEST_DIR 17 | supervisorctl shutdown 18 | supervisorctl -c etc/supervisord_alt.conf shutdown" 19 | done 20 | 21 | # back to ref directory 22 | popd 23 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/rocky53/programs_rocky53.ini: -------------------------------------------------------------------------------- 1 | [program:scen1_sensor_acquisition_2] 2 | command=bin/scen1/sensor_acquisition.sh 3 | autostart=false 4 | killasgroup=true 5 | stopasgroup=true 6 | redirect_stderr=true 7 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 8 | stdout_logfile_backups=5 9 | 10 | [program:scen1_sensor_processing_2] 11 | command=bin/scen1/sensor_processing.sh 12 | autostart=false 13 | killasgroup=true 14 | stopasgroup=true 15 | redirect_stderr=true 16 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 17 | stdout_logfile_backups=5 18 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/rocky52/programs_rocky52.ini: -------------------------------------------------------------------------------- 1 | [program:scen1_sensor_acquisition_1] 2 | command=bin/scen1/sensor_acquisition.sh 3 | autostart=false 4 | killasgroup=true 5 | stopasgroup=true 6 | redirect_stderr=true 7 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 8 | stdout_logfile_backups=5 9 | 10 | [program:scen1_sensor_processing_1] 11 | command=bin/scen1/sensor_processing.sh 12 | autostart=false 13 | killasgroup=true 14 | stopasgroup=true 15 | redirect_stderr=true 16 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 17 | stdout_logfile_backups=5 18 | 19 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/common/group_services.ini: -------------------------------------------------------------------------------- 1 | [program:common_data_bus] 2 | command=zenity --info --text=%(program_name)s 3 | startsecs=10 4 | killasgroup=true 5 | stopasgroup=true 6 | redirect_stderr=true 7 | stdout_syslog=True 8 | stdout_logfile=log/%(program_name)s_%(host_node_name)s.log 9 | stdout_logfile_backups=5 10 | 11 | [program:scen3_internal_data_bus] 12 | command=zenity --info --text=%(program_name)s 13 | startsecs=10 14 | killasgroup=true 15 | stopasgroup=true 16 | redirect_stderr=true 17 | stdout_syslog=True 18 | stdout_logfile=log/%(program_name)s_%(host_node_name)s.log 19 | stdout_logfile_backups=5 20 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/my_movies/program_restart_application.ini: -------------------------------------------------------------------------------- 1 | [program:restart_application] 2 | command=bash -c 'python ./scripts/process_app.py -n %(program_name)s -x 25 && supvisorsctl -s http://localhost:60000 restart_application CONFIG %(group_name)s' 3 | autostart=false 4 | autorestart=unexpected 5 | startsecs=2 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s_out.log 11 | stdout_logfile_maxbytes=10KB 12 | stdout_logfile_backups=1 13 | stderr_logfile=./log/%(program_name)s_%(host_node_name)s_err.log 14 | stderr_logfile_maxbytes=10KB 15 | stderr_logfile_backups=1 16 | -------------------------------------------------------------------------------- /supvisors/test/etc/common/my_movies/program_restart_process.ini: -------------------------------------------------------------------------------- 1 | [program:restart_process] 2 | command=bash -c 'python ./scripts/process_app.py -n %(program_name)s -x 15 && supvisorsctl -s http://localhost:60000 restart_process CONFIG %(group_name)s:%(program_name)s' 3 | autostart=false 4 | autorestart=false 5 | startsecs=2 6 | startretries=0 7 | exitcodes=0 8 | stopsignal=TERM 9 | stopwaitsecs=10 10 | stdout_logfile=./log/%(program_name)s_%(host_node_name)s_out.log 11 | stdout_logfile_maxbytes=10KB 12 | stdout_logfile_backups=1 13 | stderr_logfile=./log/%(program_name)s_%(host_node_name)s_err.log 14 | stderr_logfile_maxbytes=10KB 15 | stderr_logfile_backups=1 16 | -------------------------------------------------------------------------------- /supvisors/test/etc/my_movies_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1 6 | 0 7 | 8 | 9 | supv-01 10 | 1 11 | 12 | 13 | supv-01 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = Supvisors 8 | SOURCEDIR = . 9 | BUILDDIR = .build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | 6 | # environmental variables for log file names 7 | export CUR_DATE=`date +'%y%m%d'` 8 | export CUR_TIME=`date +'%H%M%S'` 9 | 10 | # start supervisor on remote machines 11 | for i in rocky51 rocky52 rocky53 12 | do 13 | echo "start Supvisors on" $i 14 | ssh $i "export DISPLAY=:0 ; cd $test_dir ; rm -rf log ; mkdir log 15 | export CUR_DATE=$CUR_DATE 16 | export CUR_TIME=$CUR_TIME 17 | supervisord -c etc/supervisord_distributed.conf" 18 | done 19 | 20 | # start firefox to get the Web UI 21 | firefox http://localhost:61000 & 22 | 23 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/start_mc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | 6 | # environmental variables for log file names 7 | export CUR_DATE=`date +'%y%m%d'` 8 | export CUR_TIME=`date +'%H%M%S'` 9 | 10 | # start supervisor on remote machines 11 | for i in rocky51 rocky52 rocky53 12 | do 13 | echo "start Supvisors on" $i 14 | ssh $i "export DISPLAY=:0 ; cd $test_dir ; rm -rf log ; mkdir log 15 | export CUR_DATE=$CUR_DATE 16 | export CUR_TIME=$CUR_TIME 17 | supervisord -c etc/supervisord_distributed_mc.conf -i $i" 18 | done 19 | 20 | # start firefox to get the Web UI 21 | firefox http://localhost:61000/?auto=True & 22 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-lts-latest 11 | tools: 12 | python: "3.11" 13 | 14 | # Build documentation in the docs/ directory with Sphinx 15 | sphinx: 16 | configuration: docs/conf.py 17 | 18 | formats: 19 | - pdf 20 | 21 | # We recommend specifying your dependencies to enable reproducible builds: 22 | # https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 23 | python: 24 | install: 25 | - requirements: docs/requirements.txt 26 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/supervisord_localhost.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:61000 3 | 4 | [supervisord] 5 | logfile=log/supervisord.log 6 | logfile_backups=10 7 | loglevel=info 8 | pidfile=/tmp/supervisord.pid 9 | nodaemon=false 10 | umask=002 11 | 12 | [rpcinterface:supervisor] 13 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 14 | 15 | [supervisorctl] 16 | serverurl=http://localhost:61000 17 | 18 | [include] 19 | files = */programs_*.ini localhost/group_localhost.ini 20 | 21 | [rpcinterface:supvisors] 22 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 23 | rules_files = etc/supvisors_rules.xml 24 | 25 | [ctlplugin:supvisors] 26 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 27 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/supervisord_distributed.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:61000 3 | 4 | [supervisord] 5 | logfile=log/supervisord.log 6 | logfile_backups=10 7 | loglevel=info 8 | pidfile=/tmp/supervisord.pid 9 | nodaemon=false 10 | umask=002 11 | 12 | [rpcinterface:supervisor] 13 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 14 | 15 | [supervisorctl] 16 | serverurl=http://localhost:61000 17 | 18 | [include] 19 | files = %(host_node_name)s/*.ini 20 | 21 | [rpcinterface:supvisors] 22 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 23 | supvisors_list = supv01,supv02,supv03 24 | rules_files = etc/supvisors_rules.xml 25 | 26 | [ctlplugin:supvisors] 27 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 28 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/supervisord_server_mc.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:61000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_server.log 6 | pidfile=/tmp/supervisord_server.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:61000 13 | 14 | [include] 15 | files = common/*.ini server/*.ini 16 | 17 | [rpcinterface:supvisors] 18 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 19 | stereotypes = @SERVER 20 | multicast_group = 239.0.0.1:60001 21 | multicast_ttl = 1 22 | rules_files = etc/supvisors_rules_mc.xml 23 | core_identifiers = @SERVER 24 | 25 | [ctlplugin:supvisors] 26 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 27 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/supervisord_console_mc.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:62000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_console.log 6 | pidfile=/tmp/supervisord_console.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:62000 13 | 14 | [include] 15 | files = common/*.ini console/*.ini 16 | 17 | [rpcinterface:supvisors] 18 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 19 | stereotypes = @CONSOLE 20 | multicast_group = 239.0.0.1:60001 21 | multicast_ttl = 1 22 | rules_files = etc/supvisors_rules_mc.xml 23 | core_identifiers = @SERVER 24 | 25 | [ctlplugin:supvisors] 26 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 27 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/supervisord_distributed_mc.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:61000 3 | 4 | [supervisord] 5 | logfile=log/supervisord.log 6 | logfile_backups=10 7 | loglevel=info 8 | pidfile=/tmp/supervisord.pid 9 | nodaemon=false 10 | umask=002 11 | 12 | [rpcinterface:supervisor] 13 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 14 | 15 | [supervisorctl] 16 | serverurl=http://localhost:61000 17 | 18 | [include] 19 | files = %(host_node_name)s/*.ini 20 | 21 | [rpcinterface:supvisors] 22 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 23 | multicast_group = 239.0.0.1:61001 24 | rules_files = etc/supvisors_rules.xml 25 | auto_fence = True 26 | 27 | [ctlplugin:supvisors] 28 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 29 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/template_etc/console/programs_console.ini: -------------------------------------------------------------------------------- 1 | [program:scen3_chart_view] 2 | command=./bin/scen3/chart_view.sh 3 | autostart=false 4 | killasgroup=true 5 | stopasgroup=true 6 | redirect_stderr=true 7 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 8 | stdout_logfile_backups=5 9 | 10 | [program:scen3_item_control] 11 | command=./bin/scen3/item_control.sh 12 | autostart=false 13 | killasgroup=true 14 | stopasgroup=true 15 | redirect_stderr=true 16 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 17 | stdout_logfile_backups=5 18 | 19 | [program:scen3_check_internal_data_bus] 20 | command=./bin/scen3/check_internal_data_bus.sh 21 | autostart=false 22 | startsecs=0 23 | killasgroup=true 24 | stopasgroup=true 25 | redirect_stderr=true 26 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 27 | stdout_logfile_backups=5 28 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/configure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # get consoles from Supvisors rules file 4 | RULES_FILE=etc/supvisors_rules.xml 5 | 6 | PY_ALIAS="from xml.etree.ElementTree import parse 7 | root = parse('$RULES_FILE').getroot() 8 | consoles = root.findtext('./alias[@name=\"consoles\"]') 9 | print(consoles.replace(',', ' ')) 10 | " 11 | 12 | CONSOLES=`python3 -c "$PY_ALIAS"` 13 | NB_CONSOLES=`echo $CONSOLES | wc -w` 14 | 15 | # duplicate Scenario 3 HCI applications iaw the number of consoles 16 | # option -x is used to separate the definitions 17 | supvisors_breed -d etc -t template_etc -b scen3_hci=$NB_CONSOLES -x -v 18 | 19 | # assign one HCI application per console 20 | for console in $CONSOLES 21 | do 22 | mkdir -p etc/console/$console 23 | FIRST=`ls etc/console/group*.ini | head -1` 24 | mv -f $FIRST etc/console/$console 25 | done 26 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/start_localhost_mc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | 6 | # environmental variables for log file names 7 | export CUR_DATE=`date +'%y%m%d'` 8 | export CUR_TIME=`date +'%H%M%S'` 9 | export DISPLAY=:0 10 | 11 | # set default hosts if not provided in command line 12 | HOST=`hostname` 13 | 14 | # clear logs / start server + console on each host 15 | cd $test_dir 16 | rm -rf log ; mkdir log 17 | 18 | echo "start Supvisors on $HOST as server_1" 19 | export IDENTIFIER=server_1 20 | supervisord -c etc/supervisord_server_mc.conf -i $IDENTIFIER 21 | 22 | echo "start Supvisors on $HOST as console_1" 23 | export IDENTIFIER=console_1 24 | supervisord -c etc/supervisord_console_mc.conf -i $IDENTIFIER 25 | 26 | # start firefox to get the Web UI 27 | firefox http://localhost:61000?auto=true & 28 | -------------------------------------------------------------------------------- /supvisors/ui/css/proc_instance.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | /* 18 | * Supvisors Process Instance page style 19 | */ 20 | 21 | /* process table bottom has 2 lines */ 22 | .process_table tfoot>tr:nth-child(1) th { 23 | bottom: 20px; 24 | } 25 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/start_localhost.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | 6 | # environmental variables for log file names 7 | export CUR_DATE=`date +'%y%m%d'` 8 | export CUR_TIME=`date +'%H%M%S'` 9 | export DISPLAY=:0 10 | 11 | # set default hosts if not provided in command line 12 | HOST=`hostname` 13 | 14 | # clear logs / start server + console on each host 15 | cd $test_dir 16 | rm -rf log ; mkdir log 17 | 18 | echo "start Supvisors on $HOST as server_1" 19 | export IDENTIFIER=server_1 20 | supervisord -c etc/supervisord_server_localhost.conf -i $IDENTIFIER 21 | 22 | echo "start Supvisors on $HOST as console_1" 23 | export IDENTIFIER=console_1 24 | supervisord -c etc/supervisord_console_localhost.conf -i $IDENTIFIER 25 | 26 | # start firefox to get the Web UI 27 | firefox http://localhost:61000?auto=true & 28 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/supervisord_server_mc.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:61000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_server.log 6 | pidfile=/tmp/supervisord_server.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:61000 13 | 14 | [include] 15 | files = common/*.ini server/*.ini 16 | 17 | [rpcinterface:supvisors] 18 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 19 | stereotypes = @SERVER 20 | multicast_group = 239.0.0.1:60001 21 | multicast_ttl = 1 22 | rules_files = etc/supvisors_rules_mc.xml 23 | core_identifiers = @SERVER 24 | synchro_timeout = 60 25 | stats_periods = 10,100 26 | 27 | [ctlplugin:supvisors] 28 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 29 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/console/programs_console.ini: -------------------------------------------------------------------------------- 1 | [program:scen3_chart_view] 2 | command = ./bin/scen3/chart_view.sh 3 | autostart = false 4 | killasgroup = true 5 | stopasgroup = true 6 | redirect_stderr = true 7 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 8 | stdout_logfile_backups = 5 9 | 10 | [program:scen3_item_control] 11 | command = ./bin/scen3/item_control.sh 12 | autostart = false 13 | killasgroup = true 14 | stopasgroup = true 15 | redirect_stderr = true 16 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 17 | stdout_logfile_backups = 5 18 | 19 | [program:scen3_check_internal_data_bus] 20 | command = ./bin/scen3/check_internal_data_bus.sh 21 | autostart = false 22 | startsecs = 0 23 | killasgroup = true 24 | stopasgroup = true 25 | redirect_stderr = true 26 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 27 | stdout_logfile_backups = 5 28 | 29 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/supervisord_server.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:61000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_server.log 6 | pidfile=/tmp/supervisord_server.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:61000 13 | 14 | [include] 15 | files = common/*.ini server/*.ini 16 | 17 | [rpcinterface:supvisors] 18 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 19 | supvisors_list = supv01:61000,supv02:61000,supv03:61000,supv01:62000,supv02:62000,supv03:62000 20 | rules_files = etc/supvisors_rules.xml 21 | core_identifiers = server_1,server_2,server_3 22 | 23 | [ctlplugin:supvisors] 24 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 25 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/supervisord_console.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:62000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_console.log 6 | pidfile=/tmp/supervisord_console.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:62000 13 | 14 | [include] 15 | files = common/*.ini console/*.ini 16 | 17 | [rpcinterface:supvisors] 18 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 19 | supvisors_list = supv01:61000,supv02:61000,supv03:61000,supv01:62000,supv02:62000,supv03:62000 20 | rules_files = etc/supvisors_rules.xml 21 | core_identifiers = server_1,server_2,server_3 22 | 23 | [ctlplugin:supvisors] 24 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 25 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | 6 | # set default hosts if not provided in command line 7 | HOSTS=${@:-rocky51 rocky52 rocky53} 8 | 9 | # clear logs / configure / start server + console on each host 10 | for host in $HOSTS 11 | do 12 | x=`echo "$host" | tail -c 2` 13 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $test_dir 14 | rm -rf log ; mkdir log 15 | ./configure.sh 16 | export DISPLAY=:0 17 | echo \"start Supvisors on $host as server_$x\" 18 | export IDENTIFIER=server_$x 19 | supervisord -c etc/supervisord_server.conf -i \$IDENTIFIER 20 | echo \"start Supvisors on $host as console_$x\" 21 | export IDENTIFIER=console_$x 22 | supervisord -c etc/supervisord_console.conf -i \$IDENTIFIER" 23 | done 24 | 25 | # start firefox to get the Web UI 26 | firefox http://localhost:61000?auto=True & 27 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/start_mc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | 6 | # set default hosts if not provided in command line 7 | HOSTS=${@:-rocky51 rocky52 rocky53} 8 | 9 | # clear logs / configure / start server + console on each host 10 | for host in $HOSTS 11 | do 12 | x=`echo "$host" | tail -c 2` 13 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $test_dir 14 | rm -rf log ; mkdir log 15 | ./configure.sh 16 | export DISPLAY=:0 17 | echo \"start Supvisors on $host as server_$x\" 18 | export IDENTIFIER=server_$x 19 | supervisord -c etc/supervisord_server_mc.conf -i \$IDENTIFIER 20 | echo \"start Supvisors on $host as console_$x\" 21 | export IDENTIFIER=console_$x 22 | supervisord -c etc/supervisord_console_mc.conf -i \$IDENTIFIER" 23 | done 24 | 25 | # start firefox to get the Web UI 26 | firefox http://localhost:61000?auto=True & 27 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | |Supvisors|: A Control System for Distributed Applications 2 | ========================================================== 3 | 4 | |Supvisors| is a Control System for Distributed Applications, based on multiple instances of |Supervisor|. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :caption: Contents 9 | 10 | introduction.rst 11 | configuration.rst 12 | dashboard.rst 13 | xml_rpc.rst 14 | flask.rst 15 | supervisorctl.rst 16 | event_interface.rst 17 | special.rst 18 | troubleshooting.rst 19 | faq.rst 20 | 21 | .. toctree:: 22 | :maxdepth: 2 23 | :caption: Use Cases 24 | 25 | scenario_1.rst 26 | scenario_2.rst 27 | scenario_3.rst 28 | 29 | .. toctree:: 30 | :maxdepth: 3 31 | :caption: Release History 32 | 33 | CHANGES.md 34 | 35 | 36 | Indices and tables 37 | ------------------ 38 | 39 | * :ref:`genindex` 40 | * :ref:`modindex` 41 | * :ref:`search` 42 | 43 | .. include:: common.rst 44 | -------------------------------------------------------------------------------- /supvisors/external_com/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # ====================================================================== 5 | # Copyright 2023 Julien LE CLEACH 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # ====================================================================== 19 | 20 | # expose the useful structure 21 | from .eventinterface import create_external_publisher, EventPublisherInterface 22 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/supvisors_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2 6 | true 7 | 2 8 | 9 | 10 | 11 | 12 | 1 13 | CONTINUE 14 | 15 | 16 | 17 | model_scenario_1 18 | 19 | 20 | 21 | model_scenario_1 22 | 1 23 | true 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/supervisord_server.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:61000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_server.log 6 | pidfile=/tmp/supervisord_server.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:61000 13 | 14 | [include] 15 | files = common/*.ini server/*.ini 16 | 17 | [rpcinterface:supvisors] 18 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 19 | supvisors_list = supv01:61000,supv02:61000,supv03:61000,supv01:62000,supv02:62000,supv03:62000 20 | rules_files = etc/supvisors_rules.xml 21 | core_identifiers = server_1,server_2,server_3 22 | synchro_options=USER,TIMEOUT 23 | synchro_timeout=60 24 | stats_periods = 10,100 25 | 26 | [ctlplugin:supvisors] 27 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 28 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/supervisord_console.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:62000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_console.log 6 | pidfile=/tmp/supervisord_console.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:62000 13 | 14 | [include] 15 | files = common/*.ini console/*.ini 16 | console/%(ENV_IDENTIFIER)s/*.ini 17 | 18 | [rpcinterface:supvisors] 19 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 20 | supvisors_list = supv01:61000,supv02:61000,supv03:61000,supv01:62000,supv02:62000,supv03:62000 21 | rules_files = etc/supvisors_rules.xml 22 | core_identifiers = server_1,server_2,server_3 23 | synchro_options=USER 24 | synchro_timeout=60 25 | 26 | [ctlplugin:supvisors] 27 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 28 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/supervisord_console_mc.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:62000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_console.log 6 | pidfile=/tmp/supervisord_console.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:62000 13 | 14 | [include] 15 | files = common/*.ini console/*.ini 16 | console/%(ENV_IDENTIFIER)s/*.ini 17 | 18 | [rpcinterface:supvisors] 19 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 20 | software_name = Scenario 3 SW 21 | software_icon = ../../../ui/img/icon.png 22 | stereotypes = @CONSOLE 23 | multicast_group = 239.0.0.1:60001 24 | multicast_ttl = 1 25 | rules_files = etc/supvisors_rules_mc.xml 26 | core_identifiers = @SERVER 27 | synchro_options=USER,TIMEOUT 28 | synchro_timeout=60 29 | 30 | [ctlplugin:supvisors] 31 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 32 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/etc/supervisord_server_localhost.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:61000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_server.log 6 | pidfile=/tmp/supervisord_server.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:61000 13 | 14 | [include] 15 | files = scen*1/*/prog* scen*1/localhost/* scen*2/server/prog* scen*2/server/group*01* scen*3/common/* scen*3/server/* 16 | 17 | [rpcinterface:supvisors] 18 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 19 | supvisors_list = supv01:61000,supv01:62000 20 | rules_files = etc/scenario_1/supvisors_rules.xml 21 | etc/scenario_2/supvisors_rules.xml 22 | etc/scenario_3/supvisors_rules.xml 23 | core_identifiers = server_1 24 | stats_periods = 10,60,3600 25 | 26 | [ctlplugin:supvisors] 27 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 28 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = 3 | cover,py39,py310,py311,py312,py313,docs 4 | 5 | [testenv:common] 6 | deps = 7 | supervisor >= 4.2.4 8 | pyzmq >= 25.1.1 9 | psutil >= 5.9.0 10 | matplotlib >= 3.5.1 11 | lxml >= 4.8.0 12 | pyparsing >= 2.4.7, < 3 13 | pytest 14 | pytest-asyncio < 0.22 15 | pytest-mock 16 | commands = 17 | pytest 18 | 19 | 20 | [testenv] 21 | deps = 22 | {[testenv:common]deps} 23 | flask-restx >= 1.2.0, < 1.3 24 | websockets >= 11.0.3, < 14 25 | commands = {[testenv:common]commands} 26 | 27 | 28 | [testenv:cover] 29 | deps = 30 | {[testenv]deps} 31 | pytest-cov 32 | commands = 33 | pytest --cov=supvisors --cov-report=xml --cov-report=term-missing 34 | 35 | 36 | [testenv:docs] 37 | deps = 38 | pyzmq >= 25.1.1 39 | websockets >= 11.0.3, < 14 40 | sphinx == 7.2.6 41 | renku-sphinx-theme == 0.4.0 42 | myst-parser == 2.0.0 43 | allowlist_externals = make 44 | commands = 45 | make -C docs html BUILDDIR={envtmpdir} "SPHINXOPTS=-W -E" 46 | -------------------------------------------------------------------------------- /supvisors/test/scripts/start_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # directories 4 | SCRIPTS_DIR=`dirname $(readlink -e $0)` 5 | TEST_DIR=`readlink -e $SCRIPTS_DIR/..` 6 | 7 | # start all instances 8 | for host in ${@:-rocky51 rocky52} 9 | do 10 | if [ "$host" == "rocky51" ] 11 | then 12 | echo "start Supervisor supv-01 on $host" 13 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $TEST_DIR ; rm -rf log/* 14 | export DISPLAY=:0 15 | export IDENTIFIER=supv-01 16 | supervisord -i supv-01" 17 | echo "start Supervisor supv-03 on $host" 18 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $TEST_DIR 19 | export DISPLAY=:0 20 | export IDENTIFIER=supv-03 21 | supervisord -c etc/supervisord_alt.conf" 22 | else 23 | echo "start Supervisor on $host" 24 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $TEST_DIR ; rm -rf log/* 25 | export DISPLAY=:0 26 | supervisord" 27 | fi 28 | done 29 | 30 | cd $TEST_DIR 31 | pwd 32 | sleep 1 33 | tail -f -n +1 log/supervisord.log 34 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/etc/supervisord_server_mc.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:61000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_server.log 6 | pidfile=/tmp/supervisord_server.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:61000 13 | 14 | [include] 15 | files = scen*1/%(host_node_name)s/* 16 | scen*2/server/* 17 | scen*3/common/* scen*3/server/* 18 | 19 | [rpcinterface:supvisors] 20 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 21 | stereotypes = @SERVER 22 | multicast_group = 239.0.0.1:61500 23 | multicast_ttl = 1 24 | rules_files = etc/scenario_1/supvisors_rules.xml 25 | etc/scenario_2/supvisors_rules_mc.xml 26 | etc/scenario_3/supvisors_rules_mc.xml 27 | core_identifiers = @SERVER 28 | synchro_options=USER,TIMEOUT 29 | synchro_timeout=60 30 | 31 | [ctlplugin:supvisors] 32 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 33 | -------------------------------------------------------------------------------- /supvisors/__init__.py: -------------------------------------------------------------------------------- 1 | # ====================================================================== 2 | # Copyright 2023 Julien LE CLEACH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # 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 | 17 | import os 18 | 19 | # get Supvisors version from file 20 | here = os.path.abspath(os.path.dirname(__file__)) 21 | version_txt = os.path.join(here, 'version.txt') 22 | with open(version_txt, 'r') as ver: 23 | supvisors_version = ver.read().split('=')[1].strip() 24 | -------------------------------------------------------------------------------- /supvisors/ui/css/instance.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | /* 18 | * Supvisors Instance pages style 19 | */ 20 | 21 | /* Header status part */ 22 | #instance_status table.status img { 23 | width: 25px; 24 | position: relative; 25 | top: 3px; 26 | } 27 | 28 | #instance_status th span.master { 29 | font-size: 1.6em; 30 | position: relative; 31 | bottom: 0.1em; 32 | } 33 | 34 | .hmode { 35 | font-size: 1.2em; 36 | } 37 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | 6 | # environmental variables for log file names 7 | export CUR_DATE=`date +'%y%m%d'` 8 | export CUR_TIME=`date +'%H%M%S'` 9 | 10 | # set default hosts if not provided in command line 11 | HOSTS=${@:-rocky51 rocky52 rocky53} 12 | 13 | # clear logs / start server + console on each host 14 | for host in $HOSTS 15 | do 16 | x=`echo "$host" | tail -c 2` 17 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $test_dir 18 | rm -rf log ; mkdir log 19 | export DISPLAY=:0 20 | export CUR_DATE=$CUR_DATE 21 | export CUR_TIME=$CUR_TIME 22 | echo \"start Supvisors on $host as server_$x\" 23 | export IDENTIFIER=server_$x 24 | supervisord -c etc/supervisord_server.conf -i \$IDENTIFIER 25 | echo \"start Supvisors on $host as console_$x\" 26 | export IDENTIFIER=console_$x 27 | supervisord -c etc/supervisord_console.conf -i \$IDENTIFIER" 28 | done 29 | 30 | # start firefox to get the Web UI 31 | firefox http://localhost:61000?auto=true & 32 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/etc/supervisord_console_mc.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:62000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_console.log 6 | pidfile=/tmp/supervisord_console.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:62000 13 | 14 | [include] 15 | files = scen*1/%(host_node_name)s/* 16 | scen*2/console/* 17 | scen*3/common/* scen*3/console/* scen*3/console/%(ENV_IDENTIFIER)s/* 18 | 19 | [rpcinterface:supvisors] 20 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 21 | stereotypes = @CONSOLE 22 | multicast_group = 239.0.0.1:61500 23 | multicast_ttl = 1 24 | rules_files = etc/scenario_1/supvisors_rules.xml 25 | etc/scenario_2/supvisors_rules_mc.xml 26 | etc/scenario_3/supvisors_rules_mc.xml 27 | core_identifiers = @SERVER 28 | synchro_options=USER,TIMEOUT 29 | synchro_timeout=60 30 | 31 | [ctlplugin:supvisors] 32 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 33 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/start_mc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | 6 | # environmental variables for log file names 7 | export CUR_DATE=$(date +'%y%m%d') 8 | export CUR_TIME=$(date +'%H%M%S') 9 | 10 | # set default hosts if not provided in command line 11 | HOSTS=${@:-rocky51 rocky52 rocky53} 12 | 13 | # clear logs / start server + console on each host 14 | for host in $HOSTS 15 | do 16 | x=$(echo "$host" | tail -c 2) 17 | ping -c 1 "$host" 2>&1 >/dev/null && ssh "$host" "cd $test_dir 18 | rm -rf log ; mkdir log 19 | export DISPLAY=:0 20 | export CUR_DATE=$CUR_DATE 21 | export CUR_TIME=$CUR_TIME 22 | echo \"start Supvisors on $host as server_$x\" 23 | export IDENTIFIER=server_$x 24 | supervisord -c etc/supervisord_server_mc.conf -i \$IDENTIFIER 25 | echo \"start Supvisors on $host as console_$x\" 26 | export IDENTIFIER=console_$x 27 | supervisord -c etc/supervisord_console_mc.conf -i \$IDENTIFIER" 28 | done 29 | 30 | # start firefox to get the Web UI 31 | firefox http://localhost:61000?auto=True & 32 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/etc/supervisord_console_localhost.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:62000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_console.log 6 | pidfile=/tmp/supervisord_console.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:62000 13 | 14 | [include] 15 | files = scen*1/%(host_node_name)s/* scen*2/console/prog* scen*2/console/group*01* scen*3/common/* scen*3/console/* scen*3/console/console_1/* 16 | 17 | [rpcinterface:supvisors] 18 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 19 | software_name = Gathering 20 | software_icon = ../../../ui/img/icon.png 21 | supvisors_list = supv01:61000,supv01:62000 22 | rules_files = etc/scenario_1/supvisors_rules.xml 23 | etc/scenario_2/supvisors_rules.xml 24 | etc/scenario_3/supvisors_rules.xml 25 | core_identifiers = server_1 26 | 27 | [ctlplugin:supvisors] 28 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 29 | -------------------------------------------------------------------------------- /supvisors/test/scripts/start_all_mc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # directories 4 | SCRIPTS_DIR=`dirname $(readlink -e $0)` 5 | TEST_DIR=`readlink -e $SCRIPTS_DIR/..` 6 | 7 | # start all instances 8 | for host in ${@:-rocky51 rocky52} 9 | do 10 | if [ "$host" == "rocky51" ] 11 | then 12 | echo "start Supervisor supv-01 on $host" 13 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $TEST_DIR ; rm -rf log/* 14 | export DISPLAY=:0 15 | export IDENTIFIER=supv-01 16 | supervisord -i supv-01 -c etc/supervisord_mc.conf" 17 | echo "start Supervisor supv-03 on $host" 18 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $TEST_DIR 19 | export DISPLAY=:0 20 | export IDENTIFIER=supv-03 21 | supervisord -i supv-03 -c etc/supervisord_alt_mc.conf" 22 | else 23 | echo "start Supervisor on $host" 24 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $TEST_DIR ; rm -rf log/* 25 | export DISPLAY=:0 26 | supervisord -c etc/supervisord_mc.conf" 27 | fi 28 | done 29 | 30 | cd $TEST_DIR 31 | pwd 32 | sleep 1 33 | tail -f -n +1 log/supervisord.log 34 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/SupvisorsAnyInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | /** 20 | * The Interface SupvisorsAnyInfo. 21 | * 22 | * It is used to identify a key to sort typed structures into a map. 23 | */ 24 | public interface SupvisorsAnyInfo { 25 | 26 | /** 27 | * The method returns the name to be used as a key map. 28 | * 29 | * @return String: the key. 30 | */ 31 | String getName(); 32 | } 33 | -------------------------------------------------------------------------------- /supvisors/test/etc/supervisord_alt_mc.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:30000 3 | ;username=cliche 4 | ;password=p@$$w0rd 5 | 6 | [supervisord] 7 | logfile=./log/supervisord_alt.log 8 | loglevel=info 9 | pidfile=/tmp/supervisord_alt.pid 10 | 11 | [rpcinterface:supervisor] 12 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 13 | 14 | [supervisorctl] 15 | serverurl=http://localhost:30000 16 | 17 | [include] 18 | files = common/*/*.ini %(ENV_IDENTIFIER)s/*.ini 19 | 20 | [rpcinterface:supvisors] 21 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 22 | multicast_group = 239.0.0.1:60001 23 | multicast_ttl = 1 24 | rules_files = etc/my_movies*.xml 25 | auto_fence = false 26 | synchro_options = LIST,CORE,TIMEOUT,USER 27 | synchro_timeout = 20 28 | inactivity_ticks = 3 29 | starting_strategy = CONFIG 30 | conciliation_strategy = USER 31 | stats_enabled = true 32 | stats_periods = 5,60,600 33 | stats_histo = 100 34 | stats_irix_mode = true 35 | logfile = AUTO 36 | 37 | [ctlplugin:supvisors] 38 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 39 | -------------------------------------------------------------------------------- /supvisors/test/scripts/evt_listener.py: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Adapted from Supervisor documentation 4 | # http://supervisord.org/events.html#example-event-listener-implementation 5 | 6 | import sys 7 | 8 | 9 | def write_stdout(s): 10 | # only eventlistener protocol messages may be sent to stdout 11 | sys.stdout.write(s) 12 | sys.stdout.flush() 13 | 14 | 15 | def write_stderr(s): 16 | sys.stderr.write(s) 17 | sys.stderr.flush() 18 | 19 | 20 | def main(): 21 | while 1: 22 | # transition from ACKNOWLEDGED to READY 23 | write_stdout('READY\n') 24 | # read header line and print it to stderr 25 | line = sys.stdin.readline() 26 | write_stderr(line) 27 | # read event payload and print it to stderr 28 | headers = dict([x.split(':') for x in line.split()]) 29 | data = sys.stdin.read(int(headers['len'])) 30 | if headers['eventname'] != 'REMOTE_COMMUNICATION': 31 | write_stderr(data) 32 | # transition from READY to ACKNOWLEDGED 33 | write_stdout('RESULT 2\nOK') 34 | 35 | 36 | if __name__ == '__main__': 37 | main() 38 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/etc/supervisord_server.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:61000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_server.log 6 | pidfile=/tmp/supervisord_server.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:61000 13 | 14 | [include] 15 | files = scen*1/%(host_node_name)s/* 16 | scen*2/server/* 17 | scen*3/common/* 18 | scen*3/server/* 19 | 20 | [rpcinterface:supvisors] 21 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 22 | supvisors_list = supv01:61000,supv02:61000,supv03:61000,supv01:62000,supv02:62000,supv03:62000 23 | rules_files = etc/scenario_1/supvisors_rules.xml 24 | etc/scenario_2/supvisors_rules.xml 25 | etc/scenario_3/supvisors_rules.xml 26 | core_identifiers = server_1,server_2,server_3 27 | stats_periods = 10,60,3600 28 | stats_irix_mode = true 29 | 30 | [ctlplugin:supvisors] 31 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 32 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | 6 | # set default hosts if not provided in command line 7 | HOSTS=${@:-rocky51 rocky52 rocky53} 8 | 9 | # configure 3 applications 10 | SRV_CONFIG_CMD="supvisors_breed -d etc -t template_etc -p server/*.ini -b scen2_srv=3 -x -v" 11 | HCI_CONFIG_CMD="supvisors_breed -d etc -t template_etc -p console/*ini -b scen2_hci=3 -x -v" 12 | 13 | # clear logs / configure / start server + console on each host 14 | for host in $HOSTS 15 | do 16 | x=`echo "$host" | tail -c 2` 17 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $test_dir 18 | rm -rf log ; mkdir log 19 | $SRV_CONFIG_CMD 20 | $HCI_CONFIG_CMD 21 | export DISPLAY=:0 22 | echo \"start Supvisors on $host as server_$x\" 23 | export IDENTIFIER=server_$x 24 | supervisord -c etc/supervisord_server.conf -i \$IDENTIFIER 25 | echo \"start Supvisors on $host as console_$x\" 26 | export IDENTIFIER=console_$x 27 | supervisord -c etc/supervisord_console.conf -i \$IDENTIFIER" 28 | done 29 | 30 | # start firefox to get the Web UI 31 | firefox http://localhost:61000 & 32 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/start_mc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # go to script folder 4 | test_dir=$(dirname "$(readlink -f "$0")") 5 | 6 | # set default hosts if not provided in command line 7 | HOSTS=${@:-rocky51 rocky52 rocky53} 8 | 9 | # configure 3 applications 10 | SRV_CONFIG_CMD="supvisors_breed -d etc -t template_etc -p server/*.ini -b scen2_srv=3 -x -v" 11 | HCI_CONFIG_CMD="supvisors_breed -d etc -t template_etc -p console/*ini -b scen2_hci=3 -x -v" 12 | 13 | # clear logs / configure / start server + console on each host 14 | for host in $HOSTS 15 | do 16 | x=`echo "$host" | tail -c 2` 17 | ping -c 1 $host 2>&1 >/dev/null && ssh $host "cd $test_dir 18 | rm -rf log ; mkdir log 19 | $SRV_CONFIG_CMD 20 | $HCI_CONFIG_CMD 21 | export DISPLAY=:0 22 | echo \"start Supvisors on $host as server_$x\" 23 | export IDENTIFIER=server_$x 24 | supervisord -c etc/supervisord_server_mc.conf -i \$IDENTIFIER 25 | echo \"start Supvisors on $host as console_$x\" 26 | export IDENTIFIER=console_$x 27 | supervisord -c etc/supervisord_console_mc.conf -i \$IDENTIFIER" 28 | done 29 | 30 | # start firefox to get the Web UI 31 | firefox http://localhost:61000 & 32 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/StartingFailureStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | 20 | /** 21 | * The StartingFailureStrategy enumeration. 22 | */ 23 | public enum StartingFailureStrategy { 24 | ABORT(0), 25 | STOP(1), 26 | CONTINUE(2); 27 | 28 | /** The strategy code. */ 29 | private int strategyCode; 30 | 31 | /** The constructor links the state code to the state name. */ 32 | private StartingFailureStrategy(final int strategyCode) { 33 | this.strategyCode = strategyCode; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/DistributionRule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | 20 | /** 21 | * The DistributionRule enumeration. 22 | */ 23 | public enum DistributionRule { 24 | ALL_INSTANCES(0), 25 | SINGLE_INSTANCE(1), 26 | SINGLE_NODE(2); 27 | 28 | /** The distribution code. */ 29 | private int distributionCode; 30 | 31 | /** The constructor links the state code to the state name. */ 32 | private DistributionRule(final int distributionCode) { 33 | this.distributionCode = distributionCode; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/SupvisorsFailureStrategies.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | 20 | /** 21 | * The SupvisorsFailureStrategies enumeration. 22 | */ 23 | public enum SupvisorsFailureStrategies { 24 | CONTINUE(0), 25 | RESYNC(1), 26 | SHUTDOWN(2); 27 | 28 | /** The strategy code. */ 29 | private int strategyCode; 30 | 31 | /** The constructor links the state code to the state name. */ 32 | private SupvisorsFailureStrategies(final int strategyCode) { 33 | this.strategyCode = strategyCode; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/etc/supervisord_console.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:62000 3 | 4 | [supervisord] 5 | logfile=log/supervisord_console.log 6 | pidfile=/tmp/supervisord_console.pid 7 | 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | 11 | [supervisorctl] 12 | serverurl=http://localhost:62000 13 | 14 | [include] 15 | files = scen*1/%(host_node_name)s/* 16 | scen*2/console/* 17 | scen*3/common/* 18 | scen*3/console/* 19 | scen*3/console/%(ENV_IDENTIFIER)s/* 20 | 21 | [rpcinterface:supvisors] 22 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 23 | software_name = Gathering 24 | software_icon = ../../../ui/img/icon.png 25 | supvisors_list = supv01:61000,supv02:61000,supv03:61000,supv01:62000,supv02:62000,supv03:62000 26 | rules_files = etc/scenario_1/supvisors_rules.xml 27 | etc/scenario_2/supvisors_rules.xml 28 | etc/scenario_3/supvisors_rules.xml 29 | core_identifiers = server_1,server_2,server_3 30 | 31 | [ctlplugin:supvisors] 32 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 33 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/ConciliationStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | 20 | /** 21 | * The ConciliationStrategy enumeration. 22 | */ 23 | public enum ConciliationStrategy { 24 | SENICIDE(0), 25 | INFANTICIDE(1), 26 | USER(2), 27 | STOP(3), 28 | RESTART(4), 29 | RUNNING_FAILURE(5); 30 | 31 | /** The strategy code. */ 32 | private int strategyCode; 33 | 34 | /** The constructor links the state code to the state name. */ 35 | private ConciliationStrategy(final int strategyCode) { 36 | this.strategyCode = strategyCode; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/StartingStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | 20 | /** 21 | * The StartingStrategy enumeration. 22 | */ 23 | public enum StartingStrategy { 24 | CONFIG(0), 25 | LESS_LOADED(1), 26 | MOST_LOADED(2), 27 | LOCAL(3), 28 | LESS_LOADED_NODE(4), 29 | MOST_LOADED_NODE(5); 30 | 31 | /** The strategy code. */ 32 | private int strategyCode; 33 | 34 | /** The constructor links the strategy code to the strategy name. */ 35 | private StartingStrategy(final int strategyCode) { 36 | this.strategyCode = strategyCode; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/RunningFailureStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | 20 | /** 21 | * The RunningFailureStrategy enumeration. 22 | */ 23 | public enum RunningFailureStrategy { 24 | CONTINUE(0), 25 | RESTART_PROCESS(1), 26 | STOP_APPLICATION(2), 27 | RESTART_APPLICATION(3), 28 | SHUTDOWN(4), 29 | RESTART(5); 30 | 31 | /** The strategy code. */ 32 | private int strategyCode; 33 | 34 | /** The constructor links the state code to the state name. */ 35 | private RunningFailureStrategy(final int strategyCode) { 36 | this.strategyCode = strategyCode; 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /supvisors/test/etc/supervisord_alt.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:30000 3 | ;username=cliche 4 | ;password=p@$$w0rd 5 | 6 | [supervisord] 7 | logfile=./log/supervisord_alt.log 8 | loglevel=info 9 | pidfile=/tmp/supervisord_alt.pid 10 | 11 | [rpcinterface:supervisor] 12 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 13 | 14 | [supervisorctl] 15 | serverurl=http://localhost:30000 16 | 17 | [include] 18 | files = common/*/*.ini 19 | %(ENV_IDENTIFIER)s/*.ini 20 | 21 | [rpcinterface:supvisors] 22 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 23 | supvisors_list = 17.0.1.11:60000,supv02:60000,192.168.1.70 24 | stereotypes = third 25 | rules_files = etc/my_movies*.xml 26 | auto_fence = false 27 | synchro_options = LIST,CORE,TIMEOUT,USER 28 | synchro_timeout = 30 29 | inactivity_ticks = 3 30 | core_identifiers = supv-01,supv-03 31 | starting_strategy = CONFIG 32 | conciliation_strategy = USER 33 | stats_enabled = true 34 | stats_periods = 5,60,600 35 | stats_histo = 100 36 | stats_irix_mode = false 37 | logfile = AUTO 38 | ;logfile = ./log/supvisors_alt.log 39 | ;logfile_maxbytes = 50MB 40 | ;logfile_backups = 10 41 | ;loglevel = debug 42 | 43 | [ctlplugin:supvisors] 44 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 45 | -------------------------------------------------------------------------------- /supvisors/ui/css/conciliation.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | /* 18 | * Supvisors Conciliation page 19 | */ 20 | 21 | /* Contents part */ 22 | #index_contents { 23 | display: flex; 24 | flex: 1; 25 | overflow: auto; 26 | padding: 10px; 27 | } 28 | 29 | /* update the background of the global strategies box */ 30 | div.strategies { 31 | background-image: linear-gradient(180deg, var(--light2-color), var(--light1-color)); 32 | } 33 | 34 | div.strategies div.button_group { 35 | background-image: none; 36 | } 37 | 38 | div.strategies div.button_group:not(:first-child) { 39 | padding-top: 0; 40 | } 41 | 42 | /* update the area of the local strategies box */ 43 | div.local_strategies div { 44 | padding: 1px 3px; 45 | } 46 | -------------------------------------------------------------------------------- /docs/common.rst: -------------------------------------------------------------------------------- 1 | .. |Supvisors| replace:: **Supvisors** 2 | .. |Supervisor| replace:: Supervisor_ 3 | .. |psutil| replace:: psutil_ 4 | .. |lxml| replace:: lxml_ 5 | .. |Flask-RESTX| replace:: Flask-RESTX_ 6 | .. |Flask| replace:: Flask_ 7 | .. |PyZMQ| replace:: PyZMQ_ 8 | .. |ZeroMQ| replace:: ZeroMQ_ 9 | .. |Websockets| replace:: websockets_ 10 | 11 | .. |start| image:: images/start_button.png 12 | :alt: Start button 13 | 14 | .. |stop| image:: images/stop_button.png 15 | :alt: Stop button 16 | 17 | .. |restart| image:: images/restart_button.png 18 | :alt: Restart button 19 | 20 | .. |shutdown| image:: images/shutdown_button.png 21 | :alt: Shutdown button 22 | 23 | .. |refresh| image:: images/refresh_button.png 24 | :alt: Refresh button 25 | 26 | .. |autorefresh| image:: images/autorefresh_button.png 27 | :alt: Refresh button 28 | 29 | .. |star| image:: images/star_button.png 30 | :alt: Star button 31 | 32 | .. |br| raw:: html 33 | 34 |
35 | 36 | .. _Supervisor: http://supervisord.org 37 | .. _psutil: https://pypi.python.org/pypi/psutil 38 | .. _matplotlib: https://matplotlib.org 39 | .. _lxml: https://lxml.de 40 | .. _Flask-RESTX: https://flask-restx.readthedocs.io 41 | .. _Flask: https://flask.palletsprojects.com 42 | .. _PyZMQ: https://pyzmq.readthedocs.io 43 | .. _ZeroMQ: https://zeromq.org 44 | .. _websockets: https://websockets.readthedocs.io 45 | -------------------------------------------------------------------------------- /supvisors/test/etc/supervisord_mc.conf: -------------------------------------------------------------------------------- 1 | [unix_http_server] 2 | file=/tmp/supervisor.sock 3 | 4 | [inet_http_server] 5 | port=:60000 6 | ;username=cliche 7 | ;password=p@$$w0rd 8 | 9 | [supervisord] 10 | logfile=./log/supervisord.log 11 | loglevel=info 12 | pidfile=/tmp/supervisord.pid 13 | minfds=1536 14 | 15 | [rpcinterface:supervisor] 16 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 17 | 18 | [supervisorctl] 19 | serverurl=http://localhost:60000 20 | 21 | [include] 22 | files = common/*/*.ini %(host_node_name)s/*.ini %(host_node_name)s/*/*.ini 23 | 24 | [rpcinterface:supvisors] 25 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 26 | multicast_group = 239.0.0.1:60001 27 | multicast_ttl = 1 28 | rules_files = etc/my_movies*.xml 29 | auto_fence = false 30 | event_link = WS 31 | event_port = 60002 32 | synchro_options = LIST,CORE,TIMEOUT,USER 33 | synchro_timeout = 20 34 | inactivity_ticks = 3 35 | disabilities_file = /tmp/disabilities.json 36 | starting_strategy = CONFIG 37 | conciliation_strategy = USER 38 | stats_enabled = true 39 | stats_collecting_period = 1 40 | stats_periods = 2.5,20,160 41 | stats_histo = 100 42 | stats_irix_mode = true 43 | tail_limit = 50MB 44 | tailf_limit = 50MB 45 | logfile = AUTO 46 | 47 | [ctlplugin:supvisors] 48 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 49 | -------------------------------------------------------------------------------- /supvisors/client/clientutils.py: -------------------------------------------------------------------------------- 1 | # ====================================================================== 2 | # Copyright 2023 Julien LE CLEACH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # 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 | 17 | from supervisor import loggers 18 | from supervisor.loggers import LevelsByName 19 | 20 | 21 | def create_logger(logfile=r'subscriber.log', loglevel=LevelsByName.INFO, 22 | fmt='%(asctime)s;%(levelname)s;%(message)s\n', 23 | rotating=True, maxbytes=10 * 1024 * 1024, backups=1, stdout=True): 24 | """ Return a simple Supervisor logger. """ 25 | logger = loggers.getLogger(loglevel) 26 | if stdout: 27 | loggers.handle_stdout(logger, fmt) 28 | loggers.handle_file(logger, logfile, fmt, rotating, maxbytes, backups) 29 | return logger 30 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/template_etc/console/programs_console.ini: -------------------------------------------------------------------------------- 1 | [program:scen2_chart_view] 2 | command=./bin/scen2/chart_view.sh 3 | autostart=false 4 | killasgroup=true 5 | stopasgroup=true 6 | redirect_stderr=true 7 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 8 | stdout_logfile_backups=5 9 | 10 | [program:scen2_sensor_control] 11 | command=./bin/scen2/sensor_control.sh 12 | autostart=false 13 | killasgroup=true 14 | stopasgroup=true 15 | redirect_stderr=true 16 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 17 | stdout_logfile_backups=5 18 | 19 | [program:scen2_sensor_view] 20 | command=./bin/scen2/sensor_view.sh 21 | autostart=false 22 | killasgroup=true 23 | stopasgroup=true 24 | redirect_stderr=true 25 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 26 | stdout_logfile_backups=5 27 | 28 | [program:scen2_check_internal_data_bus] 29 | command=./bin/scen2/check_internal_data_bus.sh 30 | autostart=false 31 | startsecs=0 32 | killasgroup=true 33 | stopasgroup=true 34 | redirect_stderr=true 35 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 36 | stdout_logfile_backups=5 37 | 38 | [program:scen2_internal_data_bus] 39 | command=./bin/scen2/internal_data_bus.sh 40 | autostart=false 41 | startsecs=10 42 | killasgroup=true 43 | stopasgroup=true 44 | redirect_stderr=true 45 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 46 | stdout_logfile_backups=5 47 | 48 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_1/etc/rocky51/programs_rocky51.ini: -------------------------------------------------------------------------------- 1 | [program:scen1_hci] 2 | command=bin/scen1/hci.sh 3 | autostart=false 4 | killasgroup=true 5 | stopasgroup=true 6 | redirect_stderr=true 7 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 8 | stdout_logfile_backups=5 9 | 10 | [program:scen1_config_manager] 11 | command=bin/scen1/config_manager.sh 12 | autostart=false 13 | killasgroup=true 14 | stopasgroup=true 15 | redirect_stderr=true 16 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 17 | stdout_logfile_backups=5 18 | 19 | [program:scen1_data_processing] 20 | command=bin/scen1/data_processing.sh 21 | autostart=false 22 | killasgroup=true 23 | stopasgroup=true 24 | redirect_stderr=true 25 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 26 | stdout_logfile_backups=5 27 | 28 | [program:scen1_external_interface] 29 | command=bin/scen1/external_interface.sh 30 | autostart=false 31 | killasgroup=true 32 | stopasgroup=true 33 | redirect_stderr=true 34 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 35 | stdout_logfile_backups=5 36 | 37 | [program:scen1_data_recorder] 38 | command=bin/scen1/data_recorder.sh 39 | autostart=false 40 | killasgroup=true 41 | stopasgroup=true 42 | redirect_stderr=true 43 | stdout_logfile=log/%(program_name)s_%(ENV_CUR_DATE)s_%(ENV_CUR_TIME)s.log 44 | stdout_logfile_backups=5 45 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/console/programs_console.ini: -------------------------------------------------------------------------------- 1 | [program:scen2_chart_view] 2 | command = ./bin/scen2/chart_view.sh 3 | autostart = false 4 | killasgroup = true 5 | stopasgroup = true 6 | redirect_stderr = true 7 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 8 | stdout_logfile_backups = 5 9 | 10 | [program:scen2_sensor_control] 11 | command = ./bin/scen2/sensor_control.sh 12 | autostart = false 13 | killasgroup = true 14 | stopasgroup = true 15 | redirect_stderr = true 16 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 17 | stdout_logfile_backups = 5 18 | 19 | [program:scen2_sensor_view] 20 | command = ./bin/scen2/sensor_view.sh 21 | autostart = false 22 | killasgroup = true 23 | stopasgroup = true 24 | redirect_stderr = true 25 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 26 | stdout_logfile_backups = 5 27 | 28 | [program:scen2_check_internal_data_bus] 29 | command = ./bin/scen2/check_internal_data_bus.sh 30 | autostart = false 31 | startsecs = 0 32 | killasgroup = true 33 | stopasgroup = true 34 | redirect_stderr = true 35 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 36 | stdout_logfile_backups = 5 37 | 38 | [program:scen2_internal_data_bus] 39 | command = ./bin/scen2/internal_data_bus.sh 40 | autostart = false 41 | startsecs = 10 42 | killasgroup = true 43 | stopasgroup = true 44 | redirect_stderr = true 45 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 46 | stdout_logfile_backups = 5 47 | 48 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/LoggerLevels.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | 20 | /** 21 | * The LoggerLevels enumeration. 22 | */ 23 | public enum LoggerLevels { 24 | BLATHER(3), 25 | TRACE(5), 26 | DEBUG(10), 27 | INFO(20), 28 | WARN(30), 29 | ERROR(40), 30 | CRITICAL(50); 31 | 32 | /** The level code. */ 33 | private int levelCode; 34 | 35 | /** The constructor links the state code to the state name. */ 36 | private LoggerLevels(final int levelCode) { 37 | this.levelCode = levelCode; 38 | } 39 | 40 | /** 41 | * The getLevelCode method returns the value of the logger level. 42 | * 43 | * @return String: The value of the logger level. 44 | */ 45 | public int getLevelCode() { 46 | return this.levelCode; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /supvisors/ui/css/card.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | /* 18 | * Supvisors common style for a card box 19 | */ 20 | 21 | div.card { 22 | padding: 0 15px; 23 | align-items: center; 24 | border: 1px solid black outset; 25 | border-radius: 6px; 26 | box-shadow: 0px 2px 10px black; 27 | background-image: linear-gradient(180deg, var(--dark1-color), var(--light2-color), var(--dark1-color)); 28 | } 29 | 30 | div.card table.status { 31 | border: none; 32 | background: transparent; 33 | } 34 | 35 | div.card table.status th, div.card table.status td { 36 | border: none; 37 | background: transparent; 38 | } 39 | 40 | div.card table.status td { 41 | text-align: center; 42 | } 43 | 44 | div.card table.status .table_main { 45 | font-size: 1em; 46 | text-align: center; 47 | } 48 | 49 | div.card table.status .table_title { 50 | text-align: right; 51 | } 52 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Supvisors documentation build configuration file 4 | 5 | import os 6 | import sys 7 | from datetime import date 8 | 9 | # -- General configuration ------------------------------------------------ 10 | 11 | # Sphinx extension module names 12 | extensions = ['sphinx.ext.autodoc', 'myst_parser'] 13 | 14 | # Add any paths that contain templates here, relative to this directory. 15 | templates_path = [] 16 | 17 | # The suffix(es) of source filenames. 18 | source_suffix = ['.rst', '.md'] 19 | 20 | # The master toctree document. 21 | master_doc = 'index' 22 | 23 | # General information about the project. 24 | year = date.today().year 25 | 26 | project = u'Supvisors' 27 | copyright = u'2016-{}, Julien Le Cléach'.format(year) 28 | author = u'Julien Le Cléach' 29 | 30 | # The version info for the project you're documenting, acts as replacement for 31 | # |version| and |release|, also used in various other places throughout the 32 | # built documents. 33 | # 34 | # The Supvisors version. 35 | parent = os.path.dirname(os.path.dirname(__file__)) 36 | sys.path.append(os.path.abspath(parent)) 37 | version_txt = os.path.join(parent, 'supvisors/version.txt') 38 | version = release = open(version_txt).read().split('=')[1].strip() 39 | 40 | exclude_patterns = ['.build', 'Thumbs.db', '.DS_Store'] 41 | 42 | pygments_style = 'sphinx' 43 | 44 | # -- Options for HTML output ---------------------------------------------- 45 | 46 | # html_theme = 'sphinx_rtd_theme' 47 | html_theme = 'renku' 48 | 49 | html_static_path = [] 50 | -------------------------------------------------------------------------------- /supvisors/ui/css/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | /* 18 | * Supvisors Application page style 19 | */ 20 | 21 | /* Style for application operational status */ 22 | .status_empty, .status_green, .status_yellow, .status_red { 23 | padding: 15px 50px; 24 | } 25 | 26 | .status_empty { 27 | background: url(../img/leds_empty_30.png) no-repeat center; 28 | } 29 | 30 | .status_green { 31 | background: url(../img/leds_green_30.png) no-repeat center; 32 | } 33 | 34 | .status_yellow { 35 | background: url(../img/leds_yellow_30.png) no-repeat center; 36 | } 37 | 38 | .status_red { 39 | background: url(../img/leds_red_30.png) no-repeat center; 40 | } 41 | 42 | /* update the background of the strategies box */ 43 | #strategies { 44 | background-image: linear-gradient(180deg, var(--light2-color), var(--light1-color)); 45 | } 46 | 47 | #strategies div.button_group { 48 | background-image: none; 49 | } 50 | 51 | #strategies div.button_group:nth-child(2) { 52 | padding-top: 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /supvisors/test/etc/supervisord.conf: -------------------------------------------------------------------------------- 1 | [unix_http_server] 2 | file=/tmp/supervisor.sock 3 | 4 | [inet_http_server] 5 | port=:60000 6 | ;username=cliche 7 | ;password=p@$$w0rd 8 | 9 | [supervisord] 10 | logfile=./log/supervisord.log 11 | loglevel=info 12 | pidfile=/tmp/supervisord.pid 13 | 14 | [rpcinterface:supervisor] 15 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 16 | 17 | [supervisorctl] 18 | serverurl=http://localhost:60000 19 | 20 | [include] 21 | files = common/*/*.ini 22 | %(host_node_name)s/*.ini 23 | %(host_node_name)s/*/*.ini 24 | 25 | [rpcinterface:supvisors] 26 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 27 | software_name = Supvisors Tests 28 | software_icon = ../ui/img/icon.png 29 | supvisors_list = 17.0.1.11,supv02,192.168.1.70:30000 30 | rules_files = etc/my_movies*.xml 31 | css_files = ui/test.css 32 | auto_fence = false 33 | event_link = ZMQ 34 | event_port = 60002 35 | synchro_options = LIST,CORE,TIMEOUT,USER 36 | synchro_timeout = 30 37 | inactivity_ticks = 3 38 | core_identifiers = supv-01,supv-03 39 | disabilities_file = /tmp/disabilities.json 40 | starting_strategy = CONFIG 41 | conciliation_strategy = USER 42 | stats_enabled = true 43 | stats_collecting_period = 1 44 | stats_periods = 2.5,20,160 45 | stats_histo = 100 46 | stats_irix_mode = true 47 | tail_limit = 50MB 48 | tailf_limit = 50MB 49 | logfile = AUTO 50 | ;logfile = ./log/supvisors.log 51 | ;logfile_maxbytes = 50MB 52 | ;logfile_backups = 10 53 | ;loglevel = debug 54 | 55 | [ctlplugin:supvisors] 56 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 57 | -------------------------------------------------------------------------------- /supvisors/tools/apis/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # ====================================================================== 5 | # Copyright 2022 Julien LE CLEACH 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # ====================================================================== 19 | 20 | from flask_restx import Api 21 | from supervisor.compat import xmlrpclib 22 | 23 | from .system_namespace import api as system_api 24 | from .supervisor_namespace import api as supervisor_api 25 | from .supvisors_namespace import api as supvisors_api 26 | 27 | # create Api with all namespaces 28 | api = Api(title='Supvisors Flask interface') 29 | api.add_namespace(system_api) 30 | api.add_namespace(supervisor_api) 31 | api.add_namespace(supvisors_api) 32 | 33 | 34 | @api.errorhandler 35 | def default_error_handler(error): 36 | """ Default error handler. """ 37 | return {'message': str(error)}, getattr(error, 'code', 500) 38 | 39 | 40 | @api.errorhandler(xmlrpclib.Fault) 41 | def supervisor_error_handler(error): 42 | """ Supervisor error handler. """ 43 | return {'message': error.faultString, 'code': error.faultCode}, 400 44 | 45 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/gathering/configure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # get consoles from Supvisors rules file 4 | RULES_FILE=etc/supvisors_rules.xml 5 | 6 | PY_ALIAS="from xml.etree.ElementTree import parse 7 | root = parse('$RULES_FILE').getroot() 8 | consoles = root.findtext('./alias[@name=\"consoles\"]') 9 | print(consoles.replace(',', ' ')) 10 | " 11 | 12 | CONSOLES=`python3 -c "$PY_ALIAS"` 13 | NB_CONSOLES=`echo $CONSOLES | wc -w` 14 | 15 | # clear bin folder 16 | rm -f bin/* 17 | 18 | # link bin folders 19 | for scenario in `ls -d ../scen*` 20 | do 21 | bin_path=`ls -d $scenario/bin/*` 22 | bin_dir=`basename $bin_path` 23 | ln -s ../$scenario/bin/$bin_dir bin/$bin_dir 24 | done 25 | 26 | # clear configuration files 27 | find etc -name "*.ini" | xargs rm -f 28 | 29 | # copy Scenario 1 configuration 30 | mkdir -p etc/scenario_1 31 | for folder in `ls -d ../scenario_1/etc/*/` 32 | do 33 | cp -rf $folder etc/scenario_1 34 | done 35 | 36 | # duplicate Scenario 2 SRV+HCI applications 3 times 37 | supvisors_breed -d etc/scenario_2 -t ../scenario_2/template_etc -b scen2_srv=3 scen2_hci=3 -x -v 38 | 39 | # duplicate Scenario 3 HCI applications iaw the number of consoles 40 | # option -x is used to separate the definitions 41 | supvisors_breed -d etc/scenario_3 -t ../scenario_3/template_etc -b scen3_hci=$NB_CONSOLES -x -v 42 | 43 | # copy Scenario 3 common + server configurations 44 | cp -rf ../scenario_3/etc/common etc/scenario_3 45 | cp -rf ../scenario_3/etc/server etc/scenario_3 46 | 47 | # assign one HCI application per console 48 | for console in $CONSOLES 49 | do 50 | mkdir -p etc/scenario_3/console/$console 51 | FIRST=`ls etc/scenario_3/console/group_scen3*.ini | head -1` 52 | mv -f $FIRST etc/scenario_3/console/$console 53 | done 54 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/server/group_server.ini: -------------------------------------------------------------------------------- 1 | [group:scen3_srv] 2 | programs=scen3_item_manager,scen3_track_manager,scen3_system_health,scen3_common_bus_interface,scen3_check_common_data_bus,scen3_check_internal_data_bus 3 | 4 | [program:scen3_item_manager] 5 | command=./bin/scen3/item_manager.sh 6 | autostart=false 7 | killasgroup=true 8 | stopasgroup=true 9 | redirect_stderr=true 10 | stdout_logfile=log/%(program_name)s.log 11 | stdout_logfile_backups=5 12 | 13 | [program:scen3_track_manager] 14 | command=./bin/scen3/track_manager.sh 15 | autostart=false 16 | killasgroup=true 17 | stopasgroup=true 18 | redirect_stderr=true 19 | stdout_logfile=log/%(program_name)s.log 20 | stdout_logfile_backups=5 21 | 22 | [program:scen3_system_health] 23 | command=./bin/scen3/system_health.sh 24 | autostart=false 25 | killasgroup=true 26 | stopasgroup=true 27 | redirect_stderr=true 28 | stdout_logfile=log/%(program_name)s.log 29 | stdout_logfile_backups=5 30 | 31 | [program:scen3_check_common_data_bus] 32 | command=./bin/scen3/check_common_data_bus.sh 33 | autostart=false 34 | startsecs=0 35 | killasgroup=true 36 | stopasgroup=true 37 | redirect_stderr=true 38 | stdout_logfile=log/%(program_name)s.log 39 | stdout_logfile_backups=5 40 | 41 | [program:scen3_common_bus_interface] 42 | command=./bin/scen3/common_bus_interface.sh 43 | autostart=false 44 | killasgroup=true 45 | stopasgroup=true 46 | redirect_stderr=true 47 | stdout_logfile=log/%(program_name)s.log 48 | stdout_logfile_backups=5 49 | 50 | [program:scen3_check_internal_data_bus] 51 | command=./bin/scen3/check_internal_data_bus.sh 52 | autostart=false 53 | startsecs=0 54 | killasgroup=true 55 | stopasgroup=true 56 | redirect_stderr=true 57 | stdout_logfile=log/%(program_name)s.log 58 | stdout_logfile_backups=5 59 | 60 | -------------------------------------------------------------------------------- /supvisors/ui/css/index.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | /* 18 | * Supvisors Main page 19 | */ 20 | 21 | /* Contents part */ 22 | #index_contents { 23 | display: flex; 24 | flex: 1; 25 | justify-content: space-evenly; 26 | flex-wrap: wrap; 27 | gap: 13px; 28 | overflow: auto; 29 | padding: 10px; 30 | } 31 | 32 | #index_contents .card { 33 | display: flex; 34 | margin: auto; 35 | } 36 | 37 | #index_contents table { 38 | height: 100%; 39 | margin: 10px; 40 | } 41 | 42 | #index_contents th:not(.state_cell) { 43 | height: 18px; 44 | background-image: linear-gradient(180deg, var(--dark2-color), var(--dark1-color)); 45 | } 46 | 47 | #index_contents th a.active { 48 | color: var(--selected-color); 49 | } 50 | 51 | #index_contents tr:first-child th { 52 | border-bottom: solid 1px var(--border-color); 53 | } 54 | 55 | #index_contents td:nth-child(1) { 56 | vertical-align: center; 57 | } 58 | 59 | #index_contents td.process_list { 60 | max-width: 250px; 61 | } 62 | 63 | #index_contents tbody .button { 64 | margin-bottom: 4px; 65 | } 66 | 67 | /* fix state columns width */ 68 | #index_contents .state_cell { 69 | width: 50px; 70 | } 71 | -------------------------------------------------------------------------------- /supvisors/tools/supvisorsflask.py: -------------------------------------------------------------------------------- 1 | # ====================================================================== 2 | # Copyright 2022 Julien LE CLEACH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # 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 | 17 | import sys 18 | 19 | from flask import Flask, g 20 | from supervisor.childutils import getRPCInterface 21 | 22 | from .apis import api 23 | from .apis.utils import parse_args 24 | 25 | # Create the Flask application 26 | app = Flask(__name__) 27 | api.init_app(app) 28 | 29 | 30 | @app.before_request 31 | def get_supervisor_proxy(): 32 | """ Get Supervisor proxy before any request. """ 33 | # get the Supervisor proxy 34 | supervisor_url = app.config.get('url') 35 | g.proxy = getRPCInterface({'SUPERVISOR_SERVER_URL': supervisor_url}) 36 | # provide version information 37 | api.version = g.proxy.supvisors.get_api_version() 38 | 39 | 40 | def main(): 41 | # read the arguments 42 | args = parse_args(sys.argv[1:]) 43 | if args.debug: 44 | print(f'ArgumentParser: {args}') 45 | # start the Flask application 46 | app.config['url'] = args.supervisor_url 47 | flask_options = {k: v for k, v in vars(args).items() 48 | if k in ['host', 'port', 'debug'] and v is not None} 49 | app.run(**flask_options) 50 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/SupvisorsInstanceState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | /** 20 | * The SupvisorsInstanceState enumeration. 21 | * 22 | * STOPPED: used when the local Supvisors instance does not receive any heartbeat message from the remote Supvisors instance (default state). 23 | * CHECKING: used when the local Supvisors instance is checking the status of the remote Supvisors instance. 24 | * CHECKED: used when the local Supvisors instance has checked the status of the remote Supvisors instance. 25 | * RUNNING: used when the local Supvisors instance is ready to work with the remote Supvisors instance. 26 | * FAILED: used when the local Supvisors instance fails to communicate with the remote Supvisors instance. 27 | * ISOLATED: used when the local Supvisors instance has actually disconnected the remote Supvisors instance. 28 | */ 29 | public enum SupvisorsInstanceState { 30 | STOPPED(0), 31 | CHECKING(1), 32 | CHECKED(2), 33 | RUNNING(3), 34 | FAILED(4), 35 | ISOLATED(5); 36 | 37 | /** The state code. */ 38 | private final int state; 39 | 40 | /** The constructor links the state code to the state name. */ 41 | private SupvisorsInstanceState(int state) { 42 | this.state = state; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/template_etc/server/programs_server.ini: -------------------------------------------------------------------------------- 1 | [program:scen2_config_manager] 2 | command=./bin/scen2/config_manager.sh 3 | autostart=false 4 | killasgroup=true 5 | stopasgroup=true 6 | redirect_stderr=true 7 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 8 | stdout_logfile_backups=5 9 | 10 | [program:scen2_check_common_data_bus] 11 | command=./bin/scen2/check_common_data_bus.sh 12 | autostart=false 13 | startsecs=0 14 | killasgroup=true 15 | stopasgroup=true 16 | redirect_stderr=true 17 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 18 | stdout_logfile_backups=5 19 | 20 | [program:scen2_common_bus_interface] 21 | command=./bin/scen2/common_bus_interface.sh 22 | autostart=false 23 | killasgroup=true 24 | stopasgroup=true 25 | redirect_stderr=true 26 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 27 | stdout_logfile_backups=5 28 | 29 | [program:scen2_check_internal_data_bus] 30 | command=./bin/scen2/check_internal_data_bus.sh 31 | autostart=false 32 | startsecs=0 33 | killasgroup=true 34 | stopasgroup=true 35 | redirect_stderr=true 36 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 37 | stdout_logfile_backups=5 38 | 39 | [program:scen2_internal_data_bus] 40 | command=./bin/scen2/internal_data_bus.sh 41 | autostart=false 42 | startsecs=10 43 | killasgroup=true 44 | stopasgroup=true 45 | redirect_stderr=true 46 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 47 | stdout_logfile_backups=5 48 | 49 | [program:scen2_data_processing] 50 | command=./bin/scen2/data_processing.sh 51 | autostart=false 52 | killasgroup=true 53 | stopasgroup=true 54 | redirect_stderr=true 55 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 56 | stdout_logfile_backups=5 57 | 58 | [program:scen2_sensor_acquisition] 59 | command=./bin/scen2/sensor_acquisition.sh 60 | autostart=false 61 | killasgroup=true 62 | stopasgroup=true 63 | redirect_stderr=true 64 | stdout_logfile=log/%(group_name)s_%(program_name)s.log 65 | stdout_logfile_backups=5 66 | 67 | -------------------------------------------------------------------------------- /supvisors/tests/test_clientutils.py: -------------------------------------------------------------------------------- 1 | # ====================================================================== 2 | # Copyright 2022 Julien LE CLEACH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # 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 | 17 | 18 | from unittest.mock import call 19 | 20 | from supervisor.loggers import Logger, LevelsByName 21 | 22 | from supvisors.client.clientutils import create_logger 23 | 24 | 25 | def test_create_logger(mocker): 26 | """ Test the create_logger method. """ 27 | mocked_stdout = mocker.patch('supervisor.loggers.handle_stdout') 28 | mocked_file = mocker.patch('supervisor.loggers.handle_file') 29 | # test default 30 | default_format = '%(asctime)s;%(levelname)s;%(message)s\n' 31 | logger = create_logger() 32 | assert isinstance(logger, Logger) 33 | assert logger.level == LevelsByName.INFO 34 | assert mocked_stdout.call_args_list == [call(logger, default_format)] 35 | assert mocked_file.call_args_list == [call(logger, r'subscriber.log', default_format, True, 10485760, 1)] 36 | mocker.resetall() 37 | # test with parameters 38 | new_format = '%(asctime)s %(message)s' 39 | logger = create_logger('/tmp/client.log', LevelsByName.CRIT, new_format, False, 1024, 10, False) 40 | assert isinstance(logger, Logger) 41 | assert logger.level == LevelsByName.CRIT 42 | assert not mocked_stdout.called 43 | assert mocked_file.call_args_list == [call(logger, '/tmp/client.log', new_format, False, 1024, 10)] 44 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Run all tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | tests: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | python-version: [3.9, "3.10", 3.11, 3.12, 3.13] 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Set up Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v4 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | 21 | - name: Show Python version 22 | run: python -V 23 | 24 | - name: Set TOXENV based on Python version 25 | run: python -c "import sys; print(f'TOXENV=py{sys.version_info.major}{sys.version_info.minor}')" | tee -a $GITHUB_ENV 26 | 27 | - name: Install dependencies 28 | run: pip install virtualenv tox 29 | 30 | - name: Run the unit tests 31 | run: tox 32 | 33 | coverage: 34 | runs-on: ubuntu-latest 35 | strategy: 36 | fail-fast: false 37 | 38 | steps: 39 | - uses: actions/checkout@v3 40 | 41 | - name: Set up Python ${{ matrix.python-version }} 42 | uses: actions/setup-python@v4 43 | with: 44 | python-version: '3.11' 45 | 46 | - name: Install dependencies 47 | run: pip install virtualenv tox 48 | 49 | - name: Run unit test coverage 50 | run: TOXENV=cover tox 51 | 52 | - name: Coveralls 53 | # does not work yet as pytest-cov does not provide Lcov files 54 | # uses: coverallsapp/github-action@master 55 | run: pip install coveralls && coveralls --service=github 56 | env: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | 59 | docs: 60 | runs-on: ubuntu-latest 61 | 62 | steps: 63 | - uses: actions/checkout@v3 64 | 65 | - name: Set up Python ${{ matrix.python-version }} 66 | uses: actions/setup-python@v4 67 | with: 68 | python-version: '3.11' 69 | 70 | - name: Install dependencies 71 | run: pip install virtualenv tox 72 | 73 | - name: Build the docs 74 | run: TOXENV=docs tox 75 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/server/programs_server.ini: -------------------------------------------------------------------------------- 1 | [program:scen2_config_manager] 2 | command = ./bin/scen2/config_manager.sh 3 | autostart = false 4 | killasgroup = true 5 | stopasgroup = true 6 | redirect_stderr = true 7 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 8 | stdout_logfile_backups = 5 9 | 10 | [program:scen2_check_common_data_bus] 11 | command = ./bin/scen2/check_common_data_bus.sh 12 | autostart = false 13 | startsecs = 0 14 | killasgroup = true 15 | stopasgroup = true 16 | redirect_stderr = true 17 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 18 | stdout_logfile_backups = 5 19 | 20 | [program:scen2_common_bus_interface] 21 | command = ./bin/scen2/common_bus_interface.sh 22 | autostart = false 23 | killasgroup = true 24 | stopasgroup = true 25 | redirect_stderr = true 26 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 27 | stdout_logfile_backups = 5 28 | 29 | [program:scen2_check_internal_data_bus] 30 | command = ./bin/scen2/check_internal_data_bus.sh 31 | autostart = false 32 | startsecs = 0 33 | killasgroup = true 34 | stopasgroup = true 35 | redirect_stderr = true 36 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 37 | stdout_logfile_backups = 5 38 | 39 | [program:scen2_internal_data_bus] 40 | command = ./bin/scen2/internal_data_bus.sh 41 | autostart = false 42 | startsecs = 10 43 | killasgroup = true 44 | stopasgroup = true 45 | redirect_stderr = true 46 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 47 | stdout_logfile_backups = 5 48 | 49 | [program:scen2_data_processing] 50 | command = ./bin/scen2/data_processing.sh 51 | autostart = false 52 | killasgroup = true 53 | stopasgroup = true 54 | redirect_stderr = true 55 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 56 | stdout_logfile_backups = 5 57 | 58 | [program:scen2_sensor_acquisition] 59 | command = ./bin/scen2/sensor_acquisition.sh 60 | autostart = false 61 | killasgroup = true 62 | stopasgroup = true 63 | redirect_stderr = true 64 | stdout_logfile = log/%(group_name)s_%(program_name)s.log 65 | stdout_logfile_backups = 5 66 | 67 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/SupvisorsState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | /** 20 | * The State enumeration for Supvisors. 21 | * 22 | * OFF is the Supvisors entry state, used until the local Supvisors instance is operational. 23 | * SYNCHRONIZATION is used when Supvisors is synchronizing all Supvisors instances. 24 | * ELECTION is used when Supvisors is electing the Supvisors Master instance (must be unanimous). 25 | * DISTRIBUTION is used when Supvisors is starting applications automatically. 26 | * OPERATION is used when Supvisors is working normally. 27 | * CONCILIATION is used when Supvisors is conciliating conflicts due to multiple instance of the same process. 28 | * RESTARTING is used when Supvisors is stopping all processes before restarting all Supvisors instances. 29 | * SHUTTING_DOWN is used when Supvisors is stopping all processes before shutting down all Supvisors instances. 30 | * FINAL is used just before Supvisors is shut down. 31 | */ 32 | public enum SupvisorsState { 33 | OFF(0), 34 | SYNCHRONIZATION(1), 35 | ELECTION(2), 36 | DISTRIBUTION(3), 37 | OPERATION(4), 38 | CONCILIATION(5), 39 | RESTARTING(6), 40 | SHUTTING_DOWN(7), 41 | FINAL(8); 42 | 43 | /** The state code. */ 44 | private int stateCode; 45 | 46 | /** The constructor links the state code to the state name. */ 47 | private SupvisorsState(final int stateCode) { 48 | this.stateCode = stateCode; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /supvisors/test/test_supervisor_177/etc/supervisord.conf: -------------------------------------------------------------------------------- 1 | [inet_http_server] 2 | port=:60000 3 | 4 | [supervisord] 5 | logfile=log/supervisord.log 6 | logfile_backups=10 7 | loglevel=info 8 | pidfile=/tmp/supervisord.pid 9 | nodaemon=false 10 | umask=002 11 | 12 | [rpcinterface:supervisor] 13 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 14 | 15 | [rpcinterface:supvisors] 16 | supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 17 | 18 | [supervisorctl] 19 | serverurl=http://localhost:60000 20 | 21 | [ctlplugin:supvisors] 22 | supervisor.ctl_factory = supvisors.supvisorsctl:make_supvisors_controller_plugin 23 | 24 | 25 | # Configuration to test Supervisor issue #177 26 | [group:dummy1] 27 | programs=autostarted,stopped 28 | 29 | [group:dummy2] 30 | programs=autostarted,control 31 | 32 | [program:control] 33 | command=zenity --info --text=%(program_name)s 34 | autostart=true 35 | killasgroup=true 36 | stopasgroup=true 37 | redirect_stderr=true 38 | stdout_logfile=log/%(program_name)s.log 39 | 40 | [program:autostarted] 41 | command=zenity --info --text=%(group_name)s-%(program_name)s_%(process_num)d 42 | process_name=%(program_name)s_%(process_num)d 43 | numprocs=2 44 | numprocs_start=10 45 | autostart=true 46 | killasgroup=true 47 | stopasgroup=true 48 | redirect_stderr=true 49 | stdout_logfile=log/%(group_name)s-%(program_name)s_%(process_num)d.log 50 | 51 | [program:stopped] 52 | command=zenity --text=%(group_name)s-%(program_name)s 53 | process_name=%(program_name)s_%(process_num)d 54 | numprocs=2 55 | numprocs_start=20 56 | autostart=false 57 | killasgroup=true 58 | stopasgroup=true 59 | redirect_stderr=true 60 | stdout_logfile=log/%(program_name)s_%(process_num)d.log 61 | 62 | [eventlistener:listener] 63 | command=python bin/evt_listener.py 64 | events=EVENT 65 | buffer_size=50 66 | autostart=true 67 | stderr_logfile=log/%(program_name)s.log 68 | 69 | [eventlistener:multiple_listener] 70 | command=python bin/evt_listener.py 71 | process_name=%(program_name)s_%(process_num)02d 72 | numprocs=2 73 | events=PROCESS_STATE 74 | buffer_size=50 75 | autostart=true 76 | stderr_logfile=log/%(program_name)s_%(process_num)d.log 77 | -------------------------------------------------------------------------------- /supvisors/tools/apis/system_namespace.py: -------------------------------------------------------------------------------- 1 | # ====================================================================== 2 | # Copyright 2022 Julien LE CLEACH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # 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 | 17 | from flask import g, jsonify 18 | from flask_restx import Namespace, Resource 19 | from supervisor.xmlrpc import SystemNamespaceRPCInterface 20 | 21 | from .utils import get_docstring_description, get_docstring_parameters 22 | 23 | # Supervisor System part 24 | api = Namespace('system', description='System operations') 25 | 26 | 27 | @api.route('/listMethods', methods=('GET',)) 28 | @api.doc(description=get_docstring_description(SystemNamespaceRPCInterface.listMethods)) 29 | class SystemListMethods(Resource): 30 | @staticmethod 31 | def get(): 32 | return jsonify(g.proxy.system.listMethods()) 33 | 34 | 35 | @api.route('/methodHelp/', methods=('GET',)) 36 | @api.doc(description=get_docstring_description(SystemNamespaceRPCInterface.methodHelp)) 37 | class SystemMethodHelp(Resource): 38 | @api.doc(params=get_docstring_parameters(SystemNamespaceRPCInterface.methodHelp)) 39 | def get(self, name): 40 | return g.proxy.system.methodHelp(name) 41 | 42 | 43 | @api.route('/methodSignature/', methods=('GET',)) 44 | @api.doc(description=get_docstring_description(SystemNamespaceRPCInterface.methodSignature)) 45 | class SystemMethodSignature(Resource): 46 | @api.doc(params=get_docstring_parameters(SystemNamespaceRPCInterface.methodSignature)) 47 | def get(self, name): 48 | return jsonify(g.proxy.system.methodSignature(name)) 49 | -------------------------------------------------------------------------------- /supvisors/web/viewmaintail.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # ====================================================================== 5 | # Copyright 2022 Julien LE CLEACH 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # ====================================================================== 19 | 20 | from urllib.parse import quote 21 | 22 | from supervisor.compat import as_string 23 | from supervisor.web import MeldView 24 | from supervisor.xmlrpc import Faults, RPCError 25 | 26 | 27 | class MainTailView(MeldView): 28 | """ Adaptation of supervisor.web.TailView to display the logs of Supervisor. """ 29 | 30 | def render(self): 31 | """ Rendering of the Main tail page. """ 32 | supvisors = self.context.supervisord.supvisors 33 | form = self.context.form 34 | # get log limit to read 35 | limit = form.get('limit', '1024') 36 | limit = min(-1024, int(limit) * -1 if limit.isdigit() else -1024) 37 | # read Supervisor logs from RPC interface 38 | rpc_intf = supvisors.supervisor_data.supervisor_rpc_interface 39 | try: 40 | tail = rpc_intf.readLog(limit, 0) 41 | except RPCError as e: 42 | if e.code == Faults.NO_FILE: 43 | tail = 'No file for Supervisor' 44 | else: 45 | tail = f'ERROR: unexpected rpc fault [{e.code}] {e.text}' 46 | # generate page 47 | root = self.clone() 48 | root.findmeld('title').content('Supervisor tail') 49 | root.findmeld('tailbody').content(tail) 50 | url = f'maintail.html?limit={quote(str(abs(limit)))}' 51 | root.findmeld('refresh_anchor').attributes(href=url) 52 | return as_string(root.write_xhtmlstring()) 53 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/supvisors_rules_mc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | @SERVER 6 | 2 7 | true 8 | 2 9 | 10 | 11 | @SERVER 12 | 1 13 | true 14 | true 15 | 16 | 17 | 18 | 19 | 20 | 1 21 | LESS_LOADED 22 | CONTINUE 23 | RESTART_PROCESS 24 | 25 | 26 | model_services 27 | 3 28 | 29 | 30 | check_data_bus 31 | 2 32 | 33 | 34 | model_services 35 | 36 | 37 | check_data_bus 38 | 39 | 40 | 41 | 42 | 43 | 44 | SINGLE_INSTANCE 45 | #,@CONSOLE 46 | 3 47 | CONTINUE 48 | 49 | 50 | 2 51 | 8 52 | 53 | 54 | check_data_bus 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/ProcessState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | import com.google.gson.annotations.SerializedName; 20 | import java.util.HashMap; 21 | 22 | /** 23 | * The ProcessState enumeration. 24 | * 25 | * See the description in the Supervisor documentation. 26 | * http://supervisord.org/subprocess.html#process-states 27 | * 28 | * The DELETED enumeration has been added to support the Supervisor issue #177 in the event where the user decreases 29 | * dynamically the numprocs value and thus processes are removed from Supervisor. 30 | */ 31 | public enum ProcessState { 32 | @SerializedName("0") 33 | STOPPED(0), 34 | @SerializedName("10") 35 | STARTING(10), 36 | @SerializedName("20") 37 | RUNNING(20), 38 | @SerializedName("30") 39 | BACKOFF(30), 40 | @SerializedName("40") 41 | STOPPING(40), 42 | @SerializedName("100") 43 | EXITED(100), 44 | @SerializedName("200") 45 | FATAL(200), 46 | @SerializedName("1000") 47 | UNKNOWN(1000), 48 | @SerializedName("-1") 49 | DELETED(-1); 50 | 51 | /** The state code. */ 52 | private int stateCode; 53 | 54 | /** Keep a map to get enum from int. */ 55 | private static HashMap map = 56 | new HashMap(); 57 | 58 | static { 59 | for (ProcessState state : ProcessState.values()) { 60 | map.put(state.stateCode, state); 61 | } 62 | } 63 | 64 | /** The constructor links the state code to the state name. */ 65 | private ProcessState(final int stateCode) { 66 | this.stateCode = stateCode; 67 | } 68 | 69 | /** Get a ProcessState enum from integer. */ 70 | public static ProcessState valueOf(int stateCode) { 71 | return map.get(stateCode); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/SupervisorFaults.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | import java.util.HashMap; 20 | 21 | 22 | /** 23 | * The SupervisorFaults enumeration. 24 | * 25 | * These are the faults defined in the supervisor.xmlprc module 26 | */ 27 | public enum SupervisorFaults { 28 | UNKNOWN_METHOD(1), 29 | INCORRECT_PARAMETERS(2), 30 | BAD_ARGUMENTS(3), 31 | SIGNATURE_UNSUPPORTED(4), 32 | SHUTDOWN_STATE(6), 33 | BAD_NAME(10), 34 | BAD_SIGNAL(11), 35 | NO_FILE(20), 36 | NOT_EXECUTABLE(21), 37 | FAILED(30), 38 | ABNORMAL_TERMINATION(40), 39 | SPAWN_ERROR(50), 40 | ALREADY_STARTED(60), 41 | NOT_RUNNING(70), 42 | SUCCESS(80), 43 | ALREADY_ADDED(90), 44 | STILL_RUNNING(91), 45 | CANT_REREAD(92); 46 | 47 | /** The fault code. */ 48 | private int faultCode; 49 | 50 | /** The mapping between fault codes and enumeration values. */ 51 | private static HashMap mapping = new HashMap(); 52 | 53 | /** Initialization of the static map. */ 54 | static { 55 | for (SupervisorFaults fault : SupervisorFaults.values()) { 56 | mapping.put(fault.faultCode, fault); 57 | } 58 | } 59 | 60 | /** The constructor links the fault code to the fault name. */ 61 | private SupervisorFaults(final int faultCode) { 62 | this.faultCode = faultCode; 63 | } 64 | 65 | /** 66 | * The getFault function returns the enumeration value associated to the fault code. 67 | * 68 | * @param int faultCode: The fault code. 69 | * @return SupervisorFaults: the corresponding enumeration 70 | */ 71 | public static SupervisorFaults getFault(final int faultCode) { 72 | return mapping.get(faultCode); 73 | } 74 | 75 | } 76 | 77 | -------------------------------------------------------------------------------- /supvisors/ui/css/message.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | /* 18 | * Supvisors style for Message / Time boxes 19 | */ 20 | 21 | #statusBox { 22 | display: flex; 23 | flex-direction: row; 24 | justify-content: space-around; 25 | } 26 | 27 | #messageBox, #timeBox { 28 | min-height: 33px; 29 | max-height: 33px; 30 | } 31 | 32 | #messageBox { 33 | display: flex; 34 | align-items: center; 35 | font-size: 0.9em; 36 | width: 100%; 37 | margin: 5px; 38 | } 39 | 40 | #timeBox { 41 | display: flex; 42 | flex-direction: column; 43 | min-width: 200px; 44 | max-width: 200px; 45 | margin: 5px 5px 5px 0; 46 | text-align: right; 47 | } 48 | 49 | #timeBox p { 50 | font-size: 0.8em; 51 | } 52 | 53 | .empty, .info, .warn, .erro { 54 | padding: 5px; 55 | margin: 5px auto; 56 | border-radius: 10px; 57 | } 58 | 59 | .empty { 60 | background-image: linear-gradient(165deg, var(--navbg-color), silver); 61 | border: 1px grey inset; 62 | } 63 | 64 | .info { 65 | background-image: linear-gradient(165deg, var(--navbg-color), dodgerblue); 66 | border: 1px blue inset; 67 | } 68 | 69 | #messageBox.info::before { 70 | content: url(../img/info_20.png) '\00a0'; 71 | float: left; 72 | position: relative; 73 | top: 2px; 74 | } 75 | 76 | .warn { 77 | background-image: linear-gradient(165deg, var(--navbg-color), #f90); 78 | border: 1px orange inset; 79 | } 80 | 81 | .warn::before { 82 | content: url(../img/warn_20.png) '\00a0'; 83 | float: left; 84 | position: relative; 85 | top: 2px; 86 | } 87 | 88 | .erro { 89 | background-image: linear-gradient(165deg, var(--navbg-color), orangered); 90 | border: 1px red inset; 91 | } 92 | 93 | .erro::before { 94 | content: url(../img/erro_20.png) '\00a0'; 95 | float: left; 96 | position: relative; 97 | top: 2px; 98 | } 99 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_3/etc/supvisors_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | server_1,server_2,server_3 5 | console_1,console_2,console_3 6 | 7 | 8 | 9 | servers 10 | 2 11 | true 12 | 2 13 | 14 | 15 | servers 16 | 1 17 | true 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 1 25 | LESS_LOADED 26 | CONTINUE 27 | RESTART_PROCESS 28 | 29 | 30 | model_services 31 | 3 32 | 33 | 34 | check_data_bus 35 | 2 36 | 37 | 38 | model_services 39 | 40 | 41 | check_data_bus 42 | 43 | 44 | 45 | 46 | 47 | 48 | SINGLE_INSTANCE 49 | #,consoles 50 | 3 51 | CONTINUE 52 | 53 | 54 | 2 55 | 8 56 | 57 | 58 | check_data_bus 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/SupervisorLogResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | 20 | /** 21 | * The Class SupervisorLogResult. 22 | * 23 | * It gives a structured form to the process information received from a XML-RPC. 24 | */ 25 | public class SupervisorLogResult { 26 | 27 | /** The log bytes. */ 28 | private String bytes; 29 | 30 | /** The log offset. */ 31 | private Integer offset; 32 | 33 | /** The log overflow. */ 34 | private Boolean overflow; 35 | 36 | /** 37 | * The constructor gets all information from an HashMap. 38 | * 39 | * @param HashMap addressInfo: The untyped structure got from the XML-RPC. 40 | */ 41 | public SupervisorLogResult(final Object[] objectsArray) { 42 | this.bytes = (String) objectsArray[0]; 43 | this.offset = (Integer) objectsArray[1]; 44 | this.overflow = (Boolean) objectsArray[2]; 45 | } 46 | 47 | /** 48 | * The getBytes method returns the log bytes. 49 | * 50 | * @return String: The log bytes. 51 | */ 52 | public String getBytes() { 53 | return this.bytes; 54 | } 55 | 56 | /** 57 | * The getOffset method returns the offset. 58 | * 59 | * @return Integer: The log offset. 60 | */ 61 | public Integer getOffset() { 62 | return this.offset; 63 | } 64 | 65 | /** 66 | * The getGroupName method returns the log overflow. 67 | * 68 | * @return Boolean: The log overflow. 69 | */ 70 | public Boolean getOverflow() { 71 | return this.overflow; 72 | } 73 | 74 | /** 75 | * The toString method returns a printable form of the contents of the instance. 76 | * 77 | * @return String: The contents of the instance. 78 | */ 79 | public String toString() { 80 | return "SupervisorLogResult(offset=" + this.offset 81 | + " overflow=" + this.overflow + " bytes=" + this.bytes + ")"; 82 | } 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /supvisors/client/java/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ${version} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/SupervisorState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | import java.util.HashMap; 20 | 21 | 22 | /** 23 | * The Class SupervisorState. 24 | * 25 | * It gives a structured form to the supervisor state received from a XML-RPC. 26 | */ 27 | public class SupervisorState { 28 | 29 | /** 30 | * The State enumeration for Supervisor. 31 | * 32 | * FATAL is used when Supervisor has experienced a serious error. 33 | * RUNNING is used when Supervisor is working normally. 34 | * RESTARTING is used when Supervisor is in the process of restarting. 35 | * SHUTDOWN is used when Supervisor is in the process of shutting down. 36 | */ 37 | public enum State { 38 | FATAL(2), 39 | RUNNING(1), 40 | RESTARTING(0), 41 | SHUTDOWN(-1); 42 | 43 | /** The state code. */ 44 | private int stateCode; 45 | 46 | /** The constructor links the state code to the state name. */ 47 | private State(final int stateCode) { 48 | this.stateCode = stateCode; 49 | } 50 | } 51 | 52 | /** The supervisor state. */ 53 | private State state; 54 | 55 | /** 56 | * The constructor gets the state information from an HashMap. 57 | * 58 | * @param HashMap stateInfo: The untyped structure got from the XML-RPC. 59 | */ 60 | public SupervisorState(HashMap stateInfo) { 61 | this.state = State.valueOf((String) stateInfo.get("statename")); 62 | } 63 | 64 | /** 65 | * The getState method returns the state of supervisor. 66 | * 67 | * @return State: The state of the supervisor. 68 | */ 69 | public State getState() { 70 | return this.state; 71 | } 72 | 73 | /** 74 | * The toString method returns a printable form of the contents of the instance. 75 | * 76 | * @return String: The contents of the instance. 77 | */ 78 | public String toString() { 79 | return "SupervisorState(state=" + this.state + ")"; 80 | } 81 | 82 | } 83 | 84 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/SupvisorsStateModes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | import java.util.HashMap; 20 | 21 | /** 22 | * The Class SupvisorsStateModes. 23 | * 24 | * It gives a structured form to the Supvisors Instance state & modes received from a XML-RPC. 25 | */ 26 | 27 | public class SupvisorsStateModes extends SupvisorsCommonStateModes { 28 | 29 | /** True if the Supvisors instance has starting jobs in progress. */ 30 | private Boolean starting_jobs; 31 | 32 | /** True if the Supvisors instance has stopping jobs in progress. */ 33 | private Boolean stopping_jobs; 34 | 35 | /** 36 | * This constructor gets all information from an HashMap. 37 | * 38 | * @param HashMap instanceInfo: The untyped structure got from the XML-RPC. 39 | */ 40 | public SupvisorsStateModes(HashMap info) { 41 | super(info); 42 | this.starting_jobs = (Boolean) info.get("starting_jobs"); 43 | this.stopping_jobs = (Boolean) info.get("stopping_jobs"); 44 | } 45 | 46 | /** 47 | * The hasStartingJobs method returns True if the Supvisors instance has jobs in progress in its Starter. 48 | * 49 | * @return Boolean: The starting jobs progress. 50 | */ 51 | public Boolean hasStartingJobs() { 52 | return this.starting_jobs; 53 | } 54 | 55 | /** 56 | * The hasStoppingJobs method returns True if the Supvisors instance has jobs in progress in its Stopper. 57 | * 58 | * @return Boolean: The stopping jobs progress. 59 | */ 60 | public Boolean hasStoppingJobs() { 61 | return this.stopping_jobs; 62 | } 63 | 64 | /** 65 | * The toString method returns a printable form of the SupvisorsStateModes instance. 66 | * 67 | * @return String: The contents of the SupvisorsStateModes. 68 | */ 69 | public String toString() { 70 | return "SupvisorsStateModes(" + super.toString() 71 | + " startingJobs=" + this.starting_jobs 72 | + " stoppingJobs=" + this.stopping_jobs + ")"; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /supvisors/ui/css/button.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | /* 18 | * Button styles 19 | */ 20 | .button { 21 | display: inline-block; 22 | padding: 2px 4px; 23 | margin-bottom: 2px; 24 | background-image: linear-gradient(180deg, var(--vlight2-color), var(--vlight1-color)); 25 | border: none; 26 | border-radius: 6px; 27 | box-shadow: 0 2px #666; 28 | color: var(--text-color); 29 | font-size: .8em; 30 | text-decoration: none; 31 | text-align: center; 32 | outline: none; 33 | } 34 | 35 | .button.on { 36 | cursor: pointer; 37 | } 38 | 39 | .button.off { 40 | cursor: not-allowed; 41 | color: var(--light2-color); 42 | background-color: var(--light1-color); 43 | background-image: none; 44 | box-shadow: 0 2px #555; 45 | } 46 | 47 | .button.on:hover { 48 | background-image: linear-gradient(180deg, var(--light1-color), var(--light2-color)); 49 | } 50 | 51 | .button.on:active { 52 | background-image: linear-gradient(180deg, var(--dark1-color), var(--dark2-color)); 53 | transform: translateY(1px); 54 | box-shadow: 0 1px #777, 0 -1px #777; 55 | } 56 | 57 | .button.active { 58 | color: var(--selected-color); 59 | background-image: linear-gradient(180deg, var(--dark1-color), var(--dark2-color)); 60 | box-shadow: 0 1px #777, 0 -1px #777; 61 | transform: translateY(1px); 62 | } 63 | 64 | .button.active.on:hover { 65 | background-image: linear-gradient(180deg, var(--light1-color), var(--light2-color)); 66 | } 67 | 68 | .button.active.on:active { 69 | background-image: linear-gradient(180deg, var(--vlight2-color), var(--vlight1-color)); 70 | box-shadow: 0 2px #666; 71 | transform: translateY(-1px); 72 | } 73 | 74 | /* Button group based on button definition above */ 75 | div.button_group { 76 | display: flex; 77 | flex-direction: row; 78 | justify-content: center; 79 | align-items: center; 80 | margin: 0 auto; 81 | } 82 | 83 | div.button_group .button:not(:first-child) { 84 | border-top-left-radius: 0; 85 | border-bottom-left-radius: 0; 86 | margin-left: 1px; 87 | } 88 | 89 | div.button_group .button:not(:last-child) { 90 | border-top-right-radius: 0; 91 | border-bottom-right-radius: 0; 92 | } 93 | -------------------------------------------------------------------------------- /supvisors/tests/test_plot.py: -------------------------------------------------------------------------------- 1 | # ====================================================================== 2 | # Copyright 2017 Julien LE CLEACH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # 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 | 17 | import pytest 18 | 19 | pytest.importorskip('matplotlib', reason='cannot test as optional matplotlib is not installed') 20 | 21 | from supvisors.web.plot import * 22 | from supvisors.web.viewimage import StatsImage 23 | 24 | 25 | def test_plot(logger_instance): 26 | """ Test a simple plot. 27 | Complex to test anything. Just check that there is no exception. """ 28 | plot = StatisticsPlot(logger_instance) 29 | assert plot.ydata == {} 30 | # add series of data 31 | plot.add_timeline([0, 1, 2]) 32 | plot.add_plot('dummy_title_1', 'unit_1', [1, 2, 3]) 33 | plot.add_plot('dummy_title_2', 'unit_2', [10, 20, 30]) 34 | assert plot.xdata == [0, 1, 2] 35 | assert plot.ydata == {('dummy_title_1', 'unit_1'): [1, 2, 3], ('dummy_title_2', 'unit_2'): [10, 20, 30]} 36 | # export image in buffer 37 | contents = StatsImage() 38 | plot.export_image(contents) 39 | 40 | 41 | def test_plot_error(mocker, logger_instance): 42 | """ Check the exception handling when saving the figure. """ 43 | plot = StatisticsPlot(logger_instance) 44 | assert plot.ydata == {} 45 | # add series of data 46 | plot.add_timeline([0, 1, 2]) 47 | plot.add_plot('dummy_title_1', 'unit_1', [1, 2, 3]) 48 | plot.add_plot('dummy_title_2', 'unit_2', [10, 20, 30]) 49 | assert plot.ydata == {('dummy_title_1', 'unit_1'): [1, 2, 3], ('dummy_title_2', 'unit_2'): [10, 20, 30]} 50 | # mock the savefig function 51 | mocker.patch.object(plt, 'savefig', side_effect=RuntimeError) 52 | # export image in buffer 53 | contents = StatsImage() 54 | plot.export_image(contents) 55 | 56 | 57 | def test_get_range(): 58 | """ Test a simple plot. 59 | Complex to test anything. Just check that there is no exception. """ 60 | # first test 61 | min_range, max_range = StatisticsPlot.get_range([10, 50, 30, 90]) 62 | assert pytest.approx(min_range) == 2.0 63 | assert pytest.approx(max_range) == 118.0 64 | # second test 65 | min_range, max_range = StatisticsPlot.get_range([0, 100]) 66 | assert pytest.approx(min_range) == 0.0 67 | assert pytest.approx(max_range) == 135.0 68 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/supvisors_rules_mc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 3 6 | true 7 | 10 8 | 9 | 10 | 2 11 | true 12 | true 13 | 14 | 15 | 1 16 | true 17 | 2 18 | 19 | 20 | 21 | 22 | 23 | SINGLE_INSTANCE 24 | @SERVER 25 | 1 26 | LESS_LOADED 27 | STOP 28 | 29 | 30 | model_services 31 | 4 32 | 33 | 34 | check_data_bus 35 | 3 36 | 37 | 38 | model_services 39 | 40 | 41 | check_data_bus 42 | 43 | 44 | data_bus 45 | RESTART_APPLICATION 46 | 47 | 48 | 49 | 50 | 51 | 52 | SINGLE_INSTANCE 53 | @CONSOLE 54 | LOCAL 55 | CONTINUE 56 | 57 | 58 | 3 59 | 8 60 | 61 | 62 | check_data_bus 63 | 64 | 65 | data_bus 66 | STOP_APPLICATION 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/SupervisorConfigUpdates.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | import java.util.List; 20 | 21 | /** 22 | * The class SupervisorConfigUpdates. 23 | * 24 | * It gives a structured form to the process rules received from a XML-RPC. 25 | */ 26 | public class SupervisorConfigUpdates { 27 | 28 | /** The list of added configurations. */ 29 | private List added; 30 | 31 | /** The list of changed configurations. */ 32 | private List changed; 33 | 34 | /** The list of removed configurations. */ 35 | private List removed; 36 | 37 | /** 38 | * The constructor gets all information from an object array. 39 | * 40 | * @param Object[] objectArray: The untyped structure got from the XML-RPC. 41 | */ 42 | public SupervisorConfigUpdates(final Object[] objectsArray) { 43 | // real structure is enclosed in array 44 | Object[] array = (Object[]) objectsArray[0]; 45 | this.added = DataConversion.arrayToStringList((Object[]) array[0]); 46 | this.changed = DataConversion.arrayToStringList((Object[]) array[1]); 47 | this.removed = DataConversion.arrayToStringList((Object[]) array[2]); 48 | } 49 | 50 | /** 51 | * The getAdded method returns the list of added configurations. 52 | * 53 | * @return List: The list of added configurations. 54 | */ 55 | public List getAdded() { 56 | return this.added; 57 | } 58 | 59 | /** 60 | * The getChanged method returns the list of changed configurations. 61 | * 62 | * @return List: The list of changed configurations. 63 | */ 64 | public List getChanged() { 65 | return this.changed; 66 | } 67 | 68 | /** 69 | * The getRemoved method returns the list of removed configurations. 70 | * 71 | * @return List: The list of removed configurations. 72 | */ 73 | public List getRemoved() { 74 | return this.removed; 75 | } 76 | 77 | /** 78 | * The toString method returns a printable form of the contents of the instance. 79 | * 80 | * @return String: The contents of the instance. 81 | */ 82 | public String toString() { 83 | return "SupervisorConfigUpdates(added=" + this.added 84 | + " changed=" + this.changed + " removed=" + this.removed + ")"; 85 | } 86 | 87 | } 88 | 89 | -------------------------------------------------------------------------------- /supvisors/test/scripts/supervisorctl_test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | function sendRequest() { 4 | echo "====================================================================" 5 | echo "# Testing: supervisorctl" "$@" 6 | echo "====================================================================" 7 | supervisorctl help "$1" 8 | echo 9 | supervisorctl "$@" 10 | echo 11 | } 12 | 13 | sleep 1 14 | 15 | # print global help 16 | sendRequest help 17 | 18 | # change log level 19 | sendRequest loglevel error 20 | 21 | # status requests 22 | sendRequest sversion 23 | sendRequest sstate 24 | sendRequest sstate all 25 | sendRequest sstate supv-01 26 | sendRequest master 27 | sendRequest strategies 28 | sendRequest stats_status 29 | 30 | sendRequest instance_status 31 | sendRequest instance_status 17.0.1.11:60000 32 | 33 | sendRequest application_info 34 | sendRequest application_info database 35 | 36 | sendRequest application_rules 37 | sendRequest application_rules database 38 | sendRequest application_rules database player 39 | 40 | sendRequest sstatus 41 | sendRequest sstatus database:* 42 | sendRequest sstatus database:movie_server_01 database:movie_server_02 database:movie_server_03 43 | 44 | sendRequest local_status 45 | sendRequest local_status database:* 46 | sendRequest local_status database:movie_server_01 database:movie_server_02 database:movie_server_03 47 | 48 | sendRequest process_rules 49 | sendRequest process_rules database:movie_server_02 50 | sendRequest process_rules database:movie_server_02 player:movie_player 51 | 52 | # command requests on processes 53 | sendRequest test_start_process CONFIG my_movies:converter_01 54 | sendRequest start_process CONFIG my_movies:converter_01 55 | sendRequest restart_process LESS_LOADED my_movies:converter_01 56 | sendRequest stop_process my_movies:converter_01 57 | sendRequest start_any_process CONFIG converter 58 | 59 | sendRequest start_args my_movies:converter_02 -x 3 -d \'additional arguments\' 60 | sleep 3 61 | 62 | sendRequest start_process_args MOST_LOADED my_movies:converter_02 -x 3 -d \'additional arguments\' 63 | sleep 3 64 | 65 | sendRequest start_any_process_args CONFIG converter -x 3 66 | sleep 3 67 | 68 | sendRequest all_start_args my_movies:converter_05 -x 3 69 | sleep 3 70 | 71 | sendRequest all_start my_movies:converter_12 72 | sleep 3 73 | 74 | # check conciliation 75 | sendRequest conflicts 76 | sendRequest conciliate INFANTICIDE 77 | sleep 10 78 | 79 | # Supervisor enhancements 80 | sendRequest lazy_update_numprocs converter 12 81 | sendRequest update_numprocs converter 10 82 | sendRequest update_numprocs converter 15 83 | sendRequest disable converter 84 | sendRequest enable converter 85 | 86 | # command requests on applications 87 | sendRequest restart_application MOST_LOADED database 88 | sendRequest stop_application database 89 | sendRequest test_start_application LESS_LOADED database 90 | sendRequest start_application LESS_LOADED database 91 | 92 | # command requests on Supervisor 93 | sendRequest sreload 94 | sleep 40 95 | sendRequest sshutdown 96 | -------------------------------------------------------------------------------- /supvisors/ui/css/header.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | /* 18 | * Supvisors common style for page header 19 | */ 20 | #right_side header { 21 | flex: 1; 22 | display: flex; 23 | flex-direction: row; 24 | min-height: 100px; 25 | max-height: 100px; 26 | padding: 0 10px; 27 | justify-content: space-between; 28 | align-items: center; 29 | } 30 | 31 | #right_side header .card { 32 | display: flex; 33 | height: 95%; 34 | } 35 | 36 | #right_side header .line_separator { 37 | flex: 1; 38 | display: flex; 39 | margin: 0 10px; 40 | border-bottom: 2px dotted var(--text-color); 41 | } 42 | 43 | /* Style for user software elements */ 44 | #right_side header .card div img { 45 | max-height: 95px; 46 | } 47 | 48 | /* Style for instance status (applicable to SupvisorsInstanceStatus and Application) */ 49 | #instance_status table.status { 50 | border: none; 51 | background: transparent; 52 | } 53 | 54 | #instance_status table.status th, #instance_status table.status td { 55 | border: none; 56 | background: transparent; 57 | } 58 | 59 | #instance_status table.status td { 60 | text-align: center; 61 | } 62 | 63 | .table_main { 64 | font-size: 1em; 65 | text-align: center; 66 | } 67 | 68 | .table_title { 69 | text-align: right; 70 | } 71 | 72 | code.hstate { 73 | display: inline-block; 74 | padding: 3px 8px; 75 | font-size: 1.6em; 76 | border-radius: 6px; 77 | text-shadow: 3px 3px 4px black; 78 | background: var(--vlight1-color); 79 | } 80 | 81 | /* Style for option boxes */ 82 | div.option_box { 83 | margin: 0 5px; 84 | border: 3px ridge var(--border-color); 85 | font-size: .7em; 86 | } 87 | 88 | div.option_box div.option_title { 89 | background-color: var(--th-color); 90 | font-weight: bold; 91 | text-align: center; 92 | border-bottom: solid 1px var(--border-color); 93 | padding: 3px 10px; 94 | } 95 | 96 | div.option_box div.button_group { 97 | background-image: linear-gradient(180deg, var(--light2-color), var(--light1-color)); 98 | padding: 3px 10px; 99 | } 100 | 101 | /* Style for action buttons */ 102 | table.buttons { 103 | border: none; 104 | background: transparent; 105 | } 106 | 107 | table.buttons td { 108 | border: none; 109 | padding: 2px 3px; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /supvisors/client/java/org/supvisors/common/SupvisorsStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | package org.supvisors.common; 18 | 19 | import java.util.Arrays; 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | 25 | /** 26 | * The Class SupvisorsStatus. 27 | * 28 | * It gives a structured form to the supervisor state received from a XML-RPC. 29 | */ 30 | public class SupvisorsStatus extends SupvisorsCommonStateModes { 31 | 32 | /** The identifiers of where starting jobs are in progress. */ 33 | private List starting_jobs; 34 | 35 | /** The identifiers of where stopping jobs are in progress. */ 36 | private List stopping_jobs; 37 | 38 | /** 39 | * The constructor gets the state information from an HashMap. 40 | * 41 | * @param HashMap stateInfo: The untyped structure got from the XML-RPC. 42 | */ 43 | public SupvisorsStatus(HashMap info) { 44 | super(info); 45 | Object[] startingJobs = (Object[]) info.get("starting_jobs"); 46 | this.starting_jobs = DataConversion.arrayToStringList(startingJobs); 47 | Object[] stoppingJobs = (Object[]) info.get("stopping_jobs"); 48 | this.stopping_jobs = DataConversion.arrayToStringList(stoppingJobs); 49 | } 50 | 51 | /** 52 | * The getStartingJobs method returns the identifiers of the Supvisors instances where starting jobs are in progress. 53 | * 54 | * @return List: The list of identifiers where Supvisors has starting jobs. 55 | */ 56 | public List getStartingJobs() { 57 | return this.starting_jobs; 58 | } 59 | 60 | /** 61 | * The getStoppingJobs method returns the identifiers of the Supvisors instances where stopping jobs are in progress. 62 | * 63 | * @return List: The list of identifiers where Supvisors has stopping jobs. 64 | */ 65 | public List getStoppingJobs() { 66 | return this.stopping_jobs; 67 | } 68 | 69 | /** 70 | * The toString method returns a printable form of the SupvisorsStatus instance. 71 | * 72 | * @return String: The contents of the SupvisorsStatus. 73 | */ 74 | public String toString() { 75 | return "SupvisorsStatus(" + super.toString() 76 | + " startingJobs=" + this.starting_jobs 77 | + " stoppingJobs=" + this.stopping_jobs + ")"; 78 | } 79 | 80 | } 81 | 82 | -------------------------------------------------------------------------------- /supvisors/ui/css/process_table.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Julien LE CLEACH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 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 | 17 | /* 18 | * Supvisors style for pages displaying a process table 19 | */ 20 | 21 | #process_contents { 22 | display: flex; 23 | flex: 1; 24 | flex-direction: row; 25 | justify-content: space-around; 26 | overflow: auto; 27 | margin: 5px; 28 | } 29 | 30 | #process_left_side { 31 | overflow: auto; 32 | padding-right: 12px; 33 | } 34 | 35 | /* process table */ 36 | .process_table { 37 | font-family: Verdana, Arial, sans-serif; 38 | text-align: justify; 39 | margin-right: 5px; 40 | overflow: auto; 41 | } 42 | 43 | .process_table thead, .process_table thead tr { 44 | border: solid 1px var(--border-color); 45 | } 46 | 47 | .process_table thead th { 48 | position: sticky; 49 | top: 0; 50 | z-index: 20; 51 | } 52 | 53 | .process_table tbody tr:last-child td { 54 | border-bottom: none; 55 | } 56 | 57 | .process_table tfoot th { 58 | position: sticky; 59 | bottom: 0; 60 | z-index: 20; 61 | } 62 | 63 | table .name { 64 | width: 200px; 65 | } 66 | 67 | table .state { 68 | width: 50px; 69 | } 70 | 71 | table .desc { 72 | width: 250px; 73 | } 74 | 75 | .shex { 76 | vertical-align: top; 77 | } 78 | 79 | .centered { 80 | text-align: center; 81 | } 82 | 83 | .expected { 84 | font-style: italic; 85 | } 86 | 87 | tbody.hoverable tr:hover, tbody.hoverable tr:hover td:not(.state_cell) { 88 | background-color: var(--navbg-color); 89 | background-image: none; 90 | } 91 | 92 | /* 93 | * Related to the detailed statistics 94 | */ 95 | #process_right_side { 96 | max-width: 500px; 97 | align-items: center; 98 | margin-right: 10px; 99 | } 100 | 101 | #process_right_side div.card { 102 | text-align: center; 103 | width: 400px; 104 | margin-top: 6px; 105 | margin-bottom: 10px; 106 | box-shadow: 0px 0px 6px black; 107 | } 108 | 109 | #process_right_side div.card .selected { 110 | color: var(--selected-color); 111 | } 112 | 113 | .stats_contents { 114 | flex: 0; 115 | display: flex; 116 | width: 450px; 117 | margin-bottom: 10px; 118 | flex-direction: row; 119 | justify-content: space-evenly; 120 | } 121 | 122 | .stats_contents div>* { 123 | margin-left: 5px; 124 | } 125 | 126 | .stats_contents td { 127 | text-align: center; 128 | } 129 | -------------------------------------------------------------------------------- /supvisors/test/use_cases/scenario_2/etc/supvisors_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | server_1,server_2,server_3 5 | console_1,console_2,console_3 6 | 7 | 8 | 9 | 3 10 | true 11 | 10 12 | 13 | 14 | 2 15 | true 16 | true 17 | 18 | 19 | 1 20 | true 21 | 2 22 | 23 | 24 | 25 | 26 | 27 | SINGLE_INSTANCE 28 | servers 29 | 1 30 | LESS_LOADED 31 | STOP 32 | 33 | 34 | model_services 35 | 4 36 | 37 | 38 | check_data_bus 39 | 3 40 | 41 | 42 | model_services 43 | 44 | 45 | check_data_bus 46 | 47 | 48 | data_bus 49 | RESTART_APPLICATION 50 | 51 | 52 | 53 | 54 | 55 | 56 | SINGLE_INSTANCE 57 | consoles 58 | LOCAL 59 | CONTINUE 60 | 61 | 62 | 3 63 | 8 64 | 65 | 66 | check_data_bus 67 | 68 | 69 | data_bus 70 | STOP_APPLICATION 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /supvisors/test/scripts/process_app.py: -------------------------------------------------------------------------------- 1 | # ====================================================================== 2 | # Copyright 2016 Julien LE CLEACH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # 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 | 17 | import os 18 | 19 | from sys import stderr 20 | from tkinter import * 21 | 22 | 23 | class ProcessAppTk(Tk): 24 | 25 | cpt = 1 26 | 27 | def __init__(self, namespec, description): 28 | """ Initialization of the attributes. """ 29 | Tk.__init__(self, None) 30 | print(f'Starting {namespec} in {os.getenv("SUPERVISOR_SERVER_URL")}') 31 | self.title('Supvisors') 32 | self.grid() 33 | # create main form 34 | form_window = PanedWindow(self, orient=VERTICAL) 35 | # display namespec into a PanedWindow 36 | main_window = PanedWindow(form_window, orient=VERTICAL) 37 | main_window.add(Label(main_window, text=f'Supvisors namespec: {namespec}')) 38 | if description: 39 | main_window.add(Label(main_window, text=f'Supvisors description: {description}')) 40 | # talk action 41 | main_window.add(Button(self, text='Talk', command=self.talk)) 42 | # add window to form and pack it 43 | form_window.add(main_window) 44 | form_window.pack() 45 | # close action 46 | Button(self, text=u"Close", command=self.quit).pack(side=BOTTOM, padx=10, pady=2) 47 | # window properties 48 | self.grid_columnconfigure(0, weight=1) 49 | self.resizable(False, False) 50 | 51 | @staticmethod 52 | def talk(): 53 | print('Talking seq=%d' % ProcessAppTk.cpt, flush=True) 54 | print('[ERR] Talking seq=%d' % ProcessAppTk.cpt, file=stderr, flush=True) 55 | ProcessAppTk.cpt = ProcessAppTk.cpt + 1 56 | 57 | def quit(self): 58 | print('Quit called') 59 | Tk.quit(self) 60 | 61 | 62 | if __name__ == "__main__": 63 | # get arguments 64 | import argparse 65 | 66 | parser = argparse.ArgumentParser(description='Start a dummy window named with a namespec.') 67 | parser.add_argument('-n', '--namespec', required=True, help='the namespec of the program') 68 | parser.add_argument('-x', '--xkill', type=int, metavar='SEC', help='kill the window after SEC seconds') 69 | parser.add_argument('-d', '--description', metavar='DESC', help='an additional description') 70 | args = parser.parse_args() 71 | # create window 72 | root = ProcessAppTk(args.namespec, args.description) 73 | # create auto-kill task 74 | if args.xkill is not None: 75 | root.after(args.xkill * 1000, root.quit) 76 | # start main loop 77 | root.mainloop() 78 | -------------------------------------------------------------------------------- /docs/faq.rst: -------------------------------------------------------------------------------- 1 | .. _faq: 2 | 3 | Frequent Asked Questions 4 | ======================== 5 | 6 | How to change the Supvisors Web UI ? 7 | ------------------------------------ 8 | 9 | If the user is considering structural updates of the |Supvisors| Web UI, such as: 10 | 11 | * adding/removing information, 12 | * changing the ``XHTML`` elements structure, 13 | * adding ``Javascript`` code, 14 | 15 | the recommended way to proceed is obviously to work on a fork and update the ``XHTML``, ``CSS`` and ``Python`` code 16 | as needed. 17 | 18 | However, if the updates under consideration are involving ``CSS`` only, such as: 19 | 20 | * updating resources (colors, fonts, font sizes, bitmaps), 21 | * updating object feedbacks (hover, active, focus), 22 | * reorganizing HTML elements (``div`` sizes and positions), 23 | * hiding some existing parts, 24 | 25 | the following hint will provide a way to do it without updating |Supvisors|, based on a simple bootstrap 26 | and monkeypatch. 27 | 28 | Every Supvisors ``XHTML`` page include a style instruction that can be used to inject user ``CSS`` by code. 29 | It is placed after the inclusion of all ``CSS`` files, so that the user ``CSS`` may overwrite anything. 30 | 31 | .. code-block:: html 32 | 33 | 34 | 35 | The bootstrap consists in inserting some user code between the |Supervisor| plugin factory and the |Supvisors| plugin 36 | creation. The code will create the |Supvisors| plugin and monkeypatch the ``ViewHandler.write_style`` method, 37 | so that the style instruction above is filled with ``CSS`` instructions that can be hardcoded as shown below 38 | or simply read from a file. 39 | 40 | .. code-block:: python 41 | 42 | from supvisors.plugin import make_supvisors_rpcinterface 43 | from supvisors.web.viewhandler import ViewHandler 44 | 45 | USER_CSS = """ 46 | div { 47 | background-color: black; 48 | } 49 | """ 50 | 51 | def write_style(self, root): 52 | """ Insert additional CSS instructions into the pages. """ 53 | root.findmeld('style_mid').content(USER_CSS) 54 | 55 | def make_user_rpcinterface(supervisord, **config): 56 | """ Create the Supvisors plugin and monkeypatch the write_style method. """ 57 | intf = make_supvisors_rpcinterface(supervisord, **config) 58 | ViewHandler.write_style = write_style 59 | return inf 60 | 61 | 62 | Finally, in the |Supervisor| configuration file, the |Supvisors| plugin has to be configured using the bootstrap 63 | instead of the |Supvisors| usual function. 64 | 65 | .. code-block:: ini 66 | 67 | [rpcinterface:supvisors] 68 | ;supervisor.rpcinterface_factory = supvisors.plugin:make_supvisors_rpcinterface 69 | supervisor.rpcinterface_factory = :make_user_rpcinterface 70 | 71 | 72 | .. important:: 73 | 74 | Before starting the |Supervisor| daemon, ensure that the bootstrap is visible in the :command:`Python` context. 75 | It can be part of an installed :command:`Python` package or just set in the ``PYTHONPATH`` environment variable. 76 | 77 | .. code-block:: bash 78 | 79 | [bash] > export PYTHONPATH=:${PYTHONPATH} 80 | [bash] > supervisord 81 | 82 | 83 | .. include:: common.rst 84 | -------------------------------------------------------------------------------- /supvisors/tools/apis/utils.py: -------------------------------------------------------------------------------- 1 | # ====================================================================== 2 | # Copyright 2022 Julien LE CLEACH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # 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 | 17 | import os 18 | from argparse import ArgumentParser 19 | from typing import Dict 20 | from urllib.parse import urlparse 21 | 22 | from supvisors.utils import parse_docstring 23 | 24 | 25 | def get_docstring_description(func) -> str: 26 | """ Extract the first part of the docstring. """ 27 | docstring = parse_docstring(func.__doc__) 28 | return docstring[0][4] 29 | 30 | 31 | def get_docstring_parameters(func) -> Dict: 32 | """ Extract the parameters from the docstring. 33 | Supervisor and Supvisors have different formats. """ 34 | docstring = parse_docstring(func.__doc__) 35 | return {entry[3]: entry[4] for entry in docstring if entry[1] == 'param'} 36 | 37 | 38 | # Argument parsing 39 | def is_url(arg_parser, arg): 40 | """ Test if the argument is a well-formatted URL. 41 | 42 | :param arg_parser: the argument parser 43 | :param arg: the argument to test 44 | :return: True if the argument is a folder 45 | """ 46 | try: 47 | result = urlparse(arg) 48 | if all([result.scheme, result.netloc, result.port]): 49 | return arg 50 | except ValueError as exc: 51 | arg_parser.error(f'Could not parse the URL provided: {arg} ({exc})') 52 | arg_parser.error(f'The URL provided is invalid: {arg}') 53 | 54 | 55 | def parse_args(args): 56 | """ Parse arguments got from the command line. 57 | 58 | :param args: the command line arguments 59 | :return: the parsed arguments 60 | """ 61 | # check if this process has been spawned by Supervisor 62 | supervisor_url = os.environ.get('SUPERVISOR_SERVER_URL') 63 | # create argument parser 64 | parser = ArgumentParser(description='Start a Flask application to interact with Supvisors', add_help=False) 65 | parser.add_argument('--help', action='help', help='show this help message and exit') 66 | parser.add_argument('-u', '--supervisor_url', type=lambda x: is_url(parser, x), 67 | default=supervisor_url, required=not supervisor_url, 68 | help='the Supervisor URL, required if supvisorsflask is not spawned by Supervisor') 69 | parser.add_argument('-h', '--host', type=str, help='the Flask server IP address') 70 | parser.add_argument('-p', '--port', type=int, help='the Flask server port number') 71 | parser.add_argument('-d', '--debug', action='store_true', help='the Flask Debug mode') 72 | # parse arguments from command line 73 | args = parser.parse_args(args) 74 | return args 75 | --------------------------------------------------------------------------------