├── .clang-format ├── .clang-format-include ├── .clang-tidy ├── .clangd ├── .copr └── Makefile ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── documentation.md │ └── feature_request.md └── workflows │ ├── images.yml │ ├── integration-tests.yml │ ├── lint.yml │ ├── multihost-tests.yml │ ├── publish.yml │ ├── sbom.yml │ └── unit-tests.yml ├── .gitignore ├── .gitmodules ├── .markdownlint-cli2.yaml ├── .packit.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── LICENSES ├── BSD-3-Clause.txt ├── LGPL2.1.txt ├── MIT-0.txt ├── MIT.txt └── README.md ├── Makefile ├── Makefile.skipper ├── README.developer.md ├── README.maintainer.md ├── README.md ├── SECURITY.md ├── bluechi.spec.in ├── build-scripts ├── build-bindings.sh ├── build-push-containers.sh ├── build-rpm.sh ├── build-srpm.sh ├── clang-tidy-all.sh ├── copyright-header-check.sh ├── create-archive.sh ├── create-spec.sh ├── generate-bindings.sh ├── generate-unit-tests-code-coverage.sh ├── install-coverage.sh ├── spdx-header-check.sh └── version.sh ├── config ├── agent.conf.d │ └── README.md ├── agent │ └── agent.conf ├── controller.conf.d │ └── README.md ├── controller │ └── controller.conf ├── meson.build └── tmpfile │ └── bluechi.conf ├── containers ├── build-base └── integration-test-base ├── data ├── meson.build ├── org.eclipse.bluechi.Agent.conf.in ├── org.eclipse.bluechi.Agent.xml ├── org.eclipse.bluechi.Controller.xml ├── org.eclipse.bluechi.Job.xml ├── org.eclipse.bluechi.Metrics.xml ├── org.eclipse.bluechi.Monitor.xml ├── org.eclipse.bluechi.Node.xml ├── org.eclipse.bluechi.conf.in ├── org.eclipse.bluechi.internal.Agent.Metrics.xml ├── org.eclipse.bluechi.internal.Agent.xml ├── org.eclipse.bluechi.internal.Controller.xml └── org.eclipse.bluechi.internal.Proxy.xml ├── debian ├── README.md ├── bluechi-agent.install ├── bluechi-agent.manpages ├── bluechi-controller.install ├── bluechi-controller.manpages ├── bluechi-deb-build ├── bluechi-is-online.install ├── bluechi-is-online.manpages ├── bluechictl.install ├── bluechictl.manpages ├── changelog ├── control ├── copyright ├── not-installed ├── patches │ └── series ├── rules └── source │ └── format ├── doc ├── .readthedocs.yaml ├── README.md ├── api-examples │ ├── c │ │ ├── enable-unit.c │ │ ├── get-cpuweight.c │ │ ├── list-node-units.c │ │ ├── list-nodes.c │ │ ├── monitor-agent-connection.c │ │ ├── monitor-node-connections.c │ │ ├── monitor-system-status.c │ │ ├── monitor-unit.c │ │ ├── set-cpuweight.c │ │ ├── setup.md │ │ └── start-unit.c │ ├── cpp │ │ ├── enable-unit.cpp │ │ ├── get-cpuweight.cpp │ │ ├── list-node-units.cpp │ │ ├── list-nodes.cpp │ │ ├── monitor-agent-connection.cpp │ │ ├── monitor-node-connections.cpp │ │ ├── monitor-system-status.cpp │ │ ├── monitor-unit.cpp │ │ ├── set-cpuweight.cpp │ │ ├── setup.md │ │ ├── start-unit.cpp │ │ ├── test │ │ └── test.cpp │ ├── go │ │ ├── enable-unit.go │ │ ├── get-cpuweight.go │ │ ├── list-node-units.go │ │ ├── list-nodes.go │ │ ├── monitor-agent-connection.go │ │ ├── monitor-node-connections.go │ │ ├── monitor-system-status.go │ │ ├── monitor-unit.go │ │ ├── set-cpuweight.go │ │ ├── setup.md │ │ └── start-unit.go │ ├── python │ │ ├── enable-unit.py │ │ ├── get-cpuweight.py │ │ ├── get-unit-properties.py │ │ ├── get-unit-property.py │ │ ├── list-active-services.py │ │ ├── list-node-units.py │ │ ├── list-nodes.py │ │ ├── monitor-agent-connection.py │ │ ├── monitor-node-connections.py │ │ ├── monitor-system-status.py │ │ ├── monitor-unit.py │ │ ├── set-cpuweight.py │ │ ├── setup.md │ │ └── start-unit.py │ └── rust │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── enable-unit.rs │ │ ├── get-cpuweight.rs │ │ ├── list-node-units.rs │ │ ├── list-nodes.rs │ │ ├── monitor-agent-connection.rs │ │ ├── monitor-node-connections.rs │ │ ├── monitor-system-status.rs │ │ ├── monitor-unit.rs │ │ ├── set-cpuweight.rs │ │ ├── setup.md │ │ └── start-unit.rs ├── bluechi-examples │ ├── CPUWeight.py │ ├── DisableUnit.py │ ├── EnableUnit.py │ ├── ListActiveServices.py │ ├── ListAllNodes.py │ ├── ListNodeUnits.py │ ├── MonitorAgentConnection.py │ ├── MonitorNodeConnections.py │ ├── MonitorSystemStatus.py │ ├── SetCPUWeight.py │ ├── StartUnit.py │ └── StopUnit.py ├── diagrams.drawio.xml ├── docs │ ├── api │ │ ├── client_generation.md │ │ ├── description.md │ │ └── examples.md │ ├── architecture.md │ ├── assets │ │ ├── img │ │ │ ├── bluechi_architecture_overview.png │ │ │ ├── bluechi_cross_node_dependency.png │ │ │ ├── bluechi_proxy_architecture.png │ │ │ ├── bluechi_proxy_service_multi_node.png │ │ │ ├── bluechi_proxy_service_single_node.png │ │ │ ├── bluechi_secure_proxy_connection.png │ │ │ ├── bluechi_secure_simple_connection.png │ │ │ ├── bluechi_setup_multi_node.png │ │ │ ├── bluechi_setup_single_node.png │ │ │ └── bluechi_using_proxy_services.png │ │ └── js │ │ │ └── tab-sync.js │ ├── configuration.md │ ├── cross_node_dependencies │ │ ├── index.md │ │ ├── proxy_services.md │ │ └── usage.md │ ├── getting_started │ │ ├── cross_node_dependencies.md │ │ ├── examples_bluechictl.md │ │ ├── installation.md │ │ ├── multi_node.md │ │ └── single_node.md │ ├── index.md │ ├── man │ │ ├── bluechi-agent-conf.md │ │ ├── bluechi-agent-selinux.md │ │ ├── bluechi-agent.md │ │ ├── bluechi-controller-conf.md │ │ ├── bluechi-controller-selinux.md │ │ ├── bluechi-controller.md │ │ ├── bluechi-is-online.md │ │ ├── bluechi-proxy.md │ │ └── bluechictl.md │ ├── monitoring │ │ ├── index.md │ │ └── peers.md │ ├── resources.md │ ├── security │ │ ├── index.md │ │ ├── securing_multi_node.md │ │ └── selinux.md │ └── tools │ │ ├── ansible.md │ │ └── bluechi-is-online.md ├── eclipse-bluechi-introduction.pdf ├── man │ ├── bluechi-agent-selinux.8.md │ ├── bluechi-agent.1.md │ ├── bluechi-agent.conf.5.md │ ├── bluechi-controller-selinux.8.md │ ├── bluechi-controller.1.md │ ├── bluechi-controller.conf.5.md │ ├── bluechi-is-online.1.md │ ├── bluechi-proxy.1.md │ ├── bluechictl.1.md │ └── meson.build ├── mkdocs.yml ├── overrides │ └── main.html └── requirements.txt ├── logo ├── bluechi-logo-horiz-1280.png ├── bluechi-logo-horiz.png ├── bluechi-logo-horiz.svg ├── bluechi-logo-plain.png ├── bluechi-logo-plain.svg ├── bluechi-logo-vert-100.png ├── bluechi-logo-vert.png └── bluechi-logo-vert.svg ├── meson.build ├── meson_options.txt ├── requirements.txt ├── selinux ├── .gitignore ├── bluechi.fc ├── bluechi.if ├── bluechi.te ├── build-selinux.sh └── meson.build ├── setup.cfg ├── skipper.yaml ├── src ├── agent │ ├── agent.c │ ├── agent.h │ ├── main.c │ ├── meson.build │ ├── proxy.c │ ├── proxy.h │ ├── test │ │ ├── agent │ │ │ ├── agent_apply_config_test.c │ │ │ └── meson.build │ │ └── meson.build │ └── types.h ├── bindings │ ├── README.md │ ├── generator │ │ ├── README.md │ │ ├── img │ │ │ └── structure.png │ │ ├── requirements.txt │ │ ├── src │ │ │ ├── __init__.py │ │ │ ├── dbus_typing.py │ │ │ ├── generator.py │ │ │ ├── model.py │ │ │ ├── template.py │ │ │ └── xml_parser.py │ │ └── test │ │ │ └── test_dbus_typing.py │ └── python │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bluechi │ │ ├── __init__.py │ │ ├── api.py │ │ └── ext.py │ │ ├── requirements.txt │ │ ├── setup.cfg │ │ ├── setup.py │ │ ├── setup.py.in │ │ └── templates │ │ ├── agent.tmpl │ │ ├── api.tmpl │ │ ├── apibase.tmpl │ │ ├── block_imports.tmpl │ │ ├── consts.tmpl │ │ ├── controller.tmpl │ │ ├── job.tmpl │ │ ├── license.tmpl │ │ ├── metrics.tmpl │ │ ├── monitor.tmpl │ │ ├── node.tmpl │ │ ├── skeleton_method.tmpl │ │ ├── skeleton_property.tmpl │ │ └── skeleton_signal.tmpl ├── client │ ├── client.c │ ├── client.h │ ├── main.c │ ├── meson.build │ ├── method-daemon-reload.c │ ├── method-daemon-reload.h │ ├── method-default-target.c │ ├── method-default-target.h │ ├── method-enable-disable.c │ ├── method-enable-disable.h │ ├── method-freeze-thaw.c │ ├── method-freeze-thaw.h │ ├── method-help.c │ ├── method-help.h │ ├── method-is-enabled.c │ ├── method-is-enabled.h │ ├── method-kill.c │ ├── method-kill.h │ ├── method-list-unit-files.c │ ├── method-list-unit-files.h │ ├── method-list-units.c │ ├── method-list-units.h │ ├── method-loglevel.c │ ├── method-loglevel.h │ ├── method-metrics.c │ ├── method-metrics.h │ ├── method-monitor.c │ ├── method-monitor.h │ ├── method-reset-failed.c │ ├── method-reset-failed.h │ ├── method-status.c │ ├── method-status.h │ ├── method-unit-lifecycle.c │ ├── method-unit-lifecycle.h │ ├── types.h │ ├── usage.c │ └── usage.h ├── controller │ ├── controller.c │ ├── controller.h │ ├── job.c │ ├── job.h │ ├── main.c │ ├── meson.build │ ├── metrics.c │ ├── metrics.h │ ├── monitor.c │ ├── monitor.h │ ├── node.c │ ├── node.h │ ├── proxy_monitor.c │ ├── proxy_monitor.h │ ├── test │ │ ├── controller │ │ │ ├── controller_apply_config_test.c │ │ │ └── meson.build │ │ └── meson.build │ └── types.h ├── is-online │ ├── help.c │ ├── help.h │ ├── is-online.c │ ├── is-online.h │ ├── main.c │ ├── meson.build │ └── opt.h ├── libbluechi │ ├── bus │ │ ├── bus.c │ │ ├── bus.h │ │ ├── utils.c │ │ └── utils.h │ ├── cli │ │ ├── command.c │ │ └── command.h │ ├── common │ │ ├── cfg.c │ │ ├── cfg.h │ │ ├── common.h │ │ ├── event-util.c │ │ ├── event-util.h │ │ ├── list.h │ │ ├── math-util.c │ │ ├── math-util.h │ │ ├── network.c │ │ ├── network.h │ │ ├── opt.h │ │ ├── parse-util.c │ │ ├── parse-util.h │ │ ├── protocol.c │ │ ├── protocol.h │ │ ├── string-util.c │ │ ├── string-util.h │ │ ├── time-util.c │ │ └── time-util.h │ ├── log │ │ ├── log.c │ │ └── log.h │ ├── meson.build │ ├── service │ │ ├── shutdown.c │ │ └── shutdown.h │ ├── socket.c │ ├── socket.h │ └── test │ │ ├── bus │ │ ├── meson.build │ │ └── utils │ │ │ ├── bus_id_is_valid_test.c │ │ │ └── meson.build │ │ ├── cli │ │ ├── command │ │ │ ├── command_add_option_test.c │ │ │ ├── command_execute_test.c │ │ │ ├── command_flag_exists_test.c │ │ │ ├── command_get_option_long_test.c │ │ │ ├── command_get_option_test.c │ │ │ ├── get_option_type_test.c │ │ │ ├── meson.build │ │ │ └── methods_get_method_test.c │ │ └── meson.build │ │ ├── common │ │ ├── cfg │ │ │ ├── cfg_def_conf_test.c │ │ │ ├── cfg_get_set_test.c │ │ │ ├── cfg_load_complete_configuration_test.c │ │ │ ├── cfg_load_from_env_test.c │ │ │ ├── cfg_load_from_file_test.c │ │ │ └── meson.build │ │ ├── list_test.c │ │ ├── meson.build │ │ ├── network │ │ │ ├── assemble_tcp_address.c │ │ │ ├── get_address_test.c │ │ │ ├── is_ipv4_test.c │ │ │ ├── is_ipv6_test.c │ │ │ └── meson.build │ │ ├── parse-util_test.c │ │ ├── string-util │ │ │ ├── ends_with_test.c │ │ │ ├── match_glob_test.c │ │ │ ├── meson.build │ │ │ └── string_builder_test.c │ │ ├── time-util │ │ │ ├── get_log_timestamp.c │ │ │ ├── meson.build │ │ │ ├── micros_to_millis_test.c │ │ │ └── timespec_to_micros_test.c │ │ └── time-util_test.c │ │ ├── log │ │ ├── bc_log_init_test.c │ │ ├── bc_log_to_stderr_full_test.c │ │ ├── bc_log_to_stderr_test.c │ │ ├── log_level_to_string_test.c │ │ ├── log_target_to_str_test.c │ │ ├── meson.build │ │ └── string_to_log_level_test.c │ │ ├── meson.build │ │ └── socket │ │ ├── meson.build │ │ ├── socket_option_test.c │ │ └── socket_set_options_test.c └── proxy │ ├── main.c │ └── meson.build ├── subprojects └── README.md ├── systemd-units ├── bluechi-agent-user.service ├── bluechi-agent.service ├── bluechi-controller.service ├── bluechi-controller.socket.in ├── bluechi-dep@.service ├── bluechi-proxy-user@.service ├── bluechi-proxy@.service └── meson.build └── tests ├── .fmf └── version ├── README.md ├── bluechi_machine_lib ├── bluechictl.py └── util.py ├── bluechi_test ├── bluechi_is_online.py ├── bluechictl.py ├── client.py ├── command.py ├── config.py ├── constants.py ├── container_scripts │ ├── cmd-on-port.sh │ ├── create_monitor.py │ └── listen.py ├── fixtures.py ├── machine.py ├── service.py ├── systemctl.py ├── systemd_lists.py ├── test.py └── util.py ├── conftest.py ├── containers ├── integration-test-local └── integration-test-snapshot ├── plans ├── container.fmf └── multihost.fmf ├── requirements.txt ├── scripts ├── create_coverage_report.py ├── gather-code-coverage.sh ├── setup-src-dir-for-coverage.sh └── tests-setup.sh ├── tests ├── main.fmf └── tier0 │ ├── bluechi-agent-cmd-line-c-invalid-config │ ├── config-files │ │ └── invalid.conf │ ├── main.fmf │ └── test_bluechi_agent_cmd_line_c_invalid_config.py │ ├── bluechi-agent-cmd-options │ ├── main.fmf │ ├── python │ │ ├── is_node_connected.py │ │ └── verify_heartbeat.py │ └── test_bluechi_agent_cmd_options.py │ ├── bluechi-agent-connect-via-controller-address │ ├── config │ │ └── Invalid-ControllerAddress.conf │ ├── main.fmf │ └── test_bluechi_agent_connect_via_controller_address.py │ ├── bluechi-agent-get-logtarget │ ├── main.fmf │ ├── python │ │ └── agent_has_logtarget.py │ └── test_bluechi_agent_get_logtarget.py │ ├── bluechi-agent-invalid-port-configuration │ ├── main.fmf │ └── test_agent_invalid_port_configuration.py │ ├── bluechi-agent-logisquiet │ ├── main.fmf │ └── test_agent_logisquiet.py │ ├── bluechi-agent-loglevel │ ├── main.fmf │ └── test_agent_loglevel.py │ ├── bluechi-agent-logtarget │ ├── main.fmf │ └── test_agent_logtarget.py │ ├── bluechi-agent-resolve-fqdn │ ├── main.fmf │ └── test_bluechi_agent_resolve_fqdn.py │ ├── bluechi-agent-set-loglevel-invalid │ ├── main.fmf │ └── test_bluechi_agent_set_loglevel_invalid.py │ ├── bluechi-agent-set-loglevel │ ├── main.fmf │ └── test_bluechi_agent_set_loglevel.py │ ├── bluechi-agent-started-and-connected │ ├── main.fmf │ └── test_agent_started_and_connected.py │ ├── bluechi-agent-switch-controller │ ├── main.fmf │ ├── python │ │ └── switch_controller.py │ └── test_bluechi_agent_switch_controller.py │ ├── bluechi-agent-user-bus │ ├── main.fmf │ ├── python │ │ └── start_agent_as_user.py │ └── test_bluechi_agent_user_bus.py │ ├── bluechi-and-agent-on-same-machine │ ├── main.fmf │ ├── python │ │ └── is_node_connected.py │ └── test_bluechi_and_agent_on_same_machine.py │ ├── bluechi-anonymous-node │ ├── main.fmf │ ├── python │ │ └── node_foo_not_connected.py │ └── test_anonymous_node.py │ ├── bluechi-change-port-with-c-cmd-option │ ├── config-files │ │ ├── agent_port_8421.conf │ │ └── ctrl_port_8421.conf │ ├── main.fmf │ ├── python │ │ └── is_node_connected.py │ └── test_bluechi_change_port_with_c_cmd_option.py │ ├── bluechi-change-port-with-p-cmd-option │ ├── main.fmf │ ├── python │ │ └── is_node_connected.py │ └── test_bluechi_change_port_with_p_cmd_option.py │ ├── bluechi-controller-cmd-line-c-invalid-config │ ├── config-files │ │ └── invalid.conf │ ├── main.fmf │ └── test_bluechi_controller_cmd_line_c_invalid_config.py │ ├── bluechi-controller-disable-tcp-enable-uds │ ├── main.fmf │ └── test_bluechi_controller_disable_tcp_enable_uds.py │ ├── bluechi-controller-disable-tcp │ ├── main.fmf │ ├── python │ │ └── is_node_connected.py │ └── test_bluechi_controller_disable_tcp.py │ ├── bluechi-controller-get-logtarget │ ├── main.fmf │ ├── python │ │ └── controller_has_logtarget.py │ └── test_bluechi_agent_get_logtarget.py │ ├── bluechi-controller-runs-tcp-and-socket-activation-parallel │ ├── main.fmf │ └── test_bluechi_controller_runs_tcp_and_socket_activation_parallel.py │ ├── bluechi-controller-runs-uds-and-socket-activation-parallel │ ├── main.fmf │ └── test_bluechi_controller_runs_uds_and_socket_activation_parallel.py │ ├── bluechi-controller-set-loglevel-invalid │ ├── main.fmf │ └── test_bluechi_controller_set_loglevel_invalid.py │ ├── bluechi-controller-set-loglevel │ ├── main.fmf │ └── test_bluechi_controller_set_loglevel.py │ ├── bluechi-controller-start-transient-unit │ ├── main.fmf │ ├── python │ │ └── start_transient.py │ └── test_bluechi_controller_start_transient_unit.py │ ├── bluechi-daemon-reload │ ├── main.fmf │ └── test_bluechi_deamon_reload.py │ ├── bluechi-enable-disable-service │ ├── main.fmf │ └── test_bluechi_enable_disable_service.py │ ├── bluechi-freeze-and-thaw-service │ ├── main.fmf │ └── test_bluechi_freeze_and_thaw_service.py │ ├── bluechi-heartbeat-agent-disconnected │ ├── main.fmf │ ├── python │ │ └── is_agent_disconnected.py │ └── test_bluechi_heartbeat_agent_disconnected.py │ ├── bluechi-heartbeat-disabled │ ├── main.fmf │ ├── python │ │ └── is_node_connected.py │ └── test_bluechi_heartbeat_disabled.py │ ├── bluechi-heartbeat-node-disconnected │ ├── main.fmf │ ├── python │ │ └── is_node_disconnected.py │ └── test_bluechi_heartbeat_node_disconnected.py │ ├── bluechi-help-option-provided │ ├── main.fmf │ └── test_help_option_provided.py │ ├── bluechi-internal-hello │ ├── main.fmf │ ├── python │ │ └── call_internal_hello.py │ └── test_bluechi_internal_hello.py │ ├── bluechi-invalid-port │ ├── main.fmf │ └── test_agent_invalid_port.py │ ├── bluechi-is-online-agent-monitor │ ├── main.fmf │ └── test_bluechi_is_online_agent_monitor.py │ ├── bluechi-is-online-agent-wait │ ├── main.fmf │ └── test_bluechi_is_online_agent_wait.py │ ├── bluechi-is-online-agent │ ├── main.fmf │ └── test_bluechi_is_online_agent.py │ ├── bluechi-is-online-node-monitor │ ├── main.fmf │ └── test_bluechi_is_online_node_monitor.py │ ├── bluechi-is-online-node-wait │ ├── main.fmf │ └── test_bluechi_is_online_node_wait.py │ ├── bluechi-is-online-node │ ├── main.fmf │ └── test_bluechi_is_online_node.py │ ├── bluechi-is-online-system-monitor │ ├── main.fmf │ └── test_bluechi_is_online_system_monitor.py │ ├── bluechi-is-online-system-wait │ ├── main.fmf │ └── test_bluechi_is_online_system_wait.py │ ├── bluechi-is-online-system │ ├── main.fmf │ └── test_bluechi_is_online_system.py │ ├── bluechi-job-cancel │ ├── main.fmf │ ├── python │ │ └── start_and_cancel.py │ └── test_bluechi_job_cancel.py │ ├── bluechi-kill-unit │ ├── main.fmf │ └── test_bluechi_kill_unit.py │ ├── bluechi-list-unit-files-on-a-node │ ├── main.fmf │ └── test_bluechi_list_unit_files_on_a_node.py │ ├── bluechi-list-unit-files-on-all-nodes │ ├── main.fmf │ └── test_bluechi_list_unit_files_on_all_nodes.py │ ├── bluechi-list-units-on-a-node │ ├── main.fmf │ └── test_bluechi_list_units_on_a_node.py │ ├── bluechi-list-units-on-all-nodes │ ├── main.fmf │ └── test_bluechi_list_units_on_all_nodes.py │ ├── bluechi-long-multiline-config-setting │ ├── main.fmf │ └── test_long_multiline_config_setting.py │ ├── bluechi-monitor-service │ ├── main.fmf │ ├── python │ │ └── monitor.py │ └── test_bluechi_monitor_service.py │ ├── bluechi-no-param-provided │ ├── main.fmf │ └── test_no_param_provided.py │ ├── bluechi-node-property-peer-ip │ ├── main.fmf │ ├── python │ │ ├── has_node_ip.py │ │ └── is_node_connected.py │ └── test_bluechi_property_peer_ip.py │ ├── bluechi-node-status │ ├── main.fmf │ └── test_bluechi_node_status.py │ ├── bluechi-nodes-statuses │ ├── main.fmf │ └── test_bluechi_nodes_statuses.py │ ├── bluechi-reload-unit │ ├── main.fmf │ └── test_bluechi_reload_unit_service.py │ ├── bluechi-request-cancel │ ├── main.fmf │ └── test_bluechi_request_cancel.py │ ├── bluechi-reset-failed-node │ ├── main.fmf │ └── test_bluechi_reset_failed_node.py │ ├── bluechi-reset-failed-units │ ├── main.fmf │ └── test_bluechi_reset_failed_units.py │ ├── bluechi-reset-failed │ ├── main.fmf │ └── test_bluechi_reset_failed.py │ ├── bluechi-restart-unit │ ├── main.fmf │ ├── python │ │ └── monitor.py │ └── test_bluechi_restart_unit.py │ ├── bluechi-service-startup │ ├── main.fmf │ └── test_service_startup.py │ ├── bluechi-unsupported-option-error │ ├── main.fmf │ └── test_unsupported_option_error.py │ ├── bluechi-version-option-provided │ ├── main.fmf │ └── test_version_option_provided.py │ ├── bluechictl-is-enabled │ ├── main.fmf │ └── test_bluechictl_is_enabled.py │ ├── bluechictl-metrics │ ├── main.fmf │ ├── python │ │ └── bluechictl_metrics.py │ └── test_bluechictl_metrics.py │ ├── bluechictl-monitor-unit-created-removed │ ├── main.fmf │ ├── python │ │ └── monitor.py │ └── test_bluechictl_monitor_unit_created_removed.py │ ├── bluechictl-set-get-default-target │ ├── main.fmf │ └── test_bluechictl_set_get_default_target.py │ ├── bluechictl-status-watch-service │ ├── main.fmf │ ├── python │ │ └── bluechictl_status_watch.py │ └── test_bluechictl_status_watch_service.py │ ├── bluechictl-status-watch │ ├── main.fmf │ ├── python │ │ └── bluechictl_status_watch.py │ └── test_bluechictl_status_watch.py │ ├── main.fmf │ ├── metrics-enable-and-disable │ ├── main.fmf │ ├── python │ │ └── metrics_is_enabled.py │ └── test_metrics_enable_and_disable.py │ ├── metrics-start-unit │ ├── main.fmf │ ├── python │ │ └── start_unit_job_metrics.py │ └── test_metrics_start_unit.py │ ├── monitor-agent-loses-connection │ ├── main.fmf │ ├── python │ │ ├── is_agent_connected.py │ │ └── monitor_ctrl_down.py │ └── test_monitor_agent_loses_connection.py │ ├── monitor-listener-added-as-peer │ ├── main.fmf │ ├── python │ │ └── added_as_peer.py │ └── test_monitor_listener_added.py │ ├── monitor-listener-added-more-than-once │ ├── main.fmf │ ├── python │ │ └── added_more_than_once.py │ └── test_monitor_listener_added_more_than_once.py │ ├── monitor-listener-not-added-as-peer │ ├── main.fmf │ ├── python │ │ └── not_added_as_peer.py │ └── test_monitor_listener_not_added.py │ ├── monitor-listener-owner-added-as-peer │ ├── main.fmf │ ├── python │ │ └── added_owner_as_peer.py │ └── test_monitor_listener_owner_added.py │ ├── monitor-listener-removed-as-peer │ ├── main.fmf │ ├── python │ │ └── removed_as_peer.py │ └── test_monitor_listener_removed.py │ ├── monitor-multiple-nodes-and-units │ ├── main.fmf │ ├── python │ │ └── monitor.py │ └── test_monitor_multiple_nodes_and_units.py │ ├── monitor-node-disconnect │ ├── main.fmf │ ├── python │ │ └── monitor.py │ └── test_monitor_node_disconnect.py │ ├── monitor-node-reconnect │ ├── main.fmf │ ├── python │ │ └── is_node_connected.py │ └── test_monitor_node_reconnect.py │ ├── monitor-open-close │ ├── main.fmf │ ├── python │ │ └── monitor.py │ └── test_monitor_open_close.py │ ├── monitor-specific-node-and-unit │ ├── main.fmf │ ├── python │ │ └── monitor.py │ └── test_monitor_specific_node_and_unit.py │ ├── monitor-system-status-ctrl-stop │ ├── main.fmf │ ├── python │ │ └── system-monitor.py │ └── test_monitor_system_status_ctrl_stop.py │ ├── monitor-system-status │ ├── main.fmf │ ├── python │ │ └── system-monitor.py │ └── test_monitor_system_status.py │ ├── monitor-unsubscribe │ ├── main.fmf │ ├── python │ │ └── unsubscribe-automatically.py │ └── test_monitor_unsubscribe.py │ ├── monitor-wildcard-node-reconnect │ ├── main.fmf │ ├── python │ │ └── monitor.py │ └── test_monitor_wildcard_node_reconnect.py │ ├── monitor-wildcard-unit-changes │ ├── main.fmf │ ├── python │ │ └── monitor.py │ └── test_monitor_wildcard_unit_changes.py │ ├── properties-get │ ├── main.fmf │ ├── python │ │ └── get_properties.py │ └── test_properties_get.py │ ├── property-get │ ├── main.fmf │ ├── python │ │ └── get_property.py │ └── test_property_get.py │ ├── property-set │ ├── main.fmf │ ├── python │ │ └── set_property.py │ └── test_property_set.py │ ├── proxy-service-denied-by-default │ ├── main.fmf │ └── test_proxy_service_denied_by_default.py │ ├── proxy-service-fails-on-execstart │ ├── main.fmf │ └── test_proxy_service_fails_on_execstart.py │ ├── proxy-service-fails-on-non-existent-node │ ├── main.fmf │ └── test_proxy_fails_on_non_existent_node.py │ ├── proxy-service-fails-on-non-existent-service │ ├── main.fmf │ └── test_proxy_service_fails_on_non_existent_service.py │ ├── proxy-service-fails-on-typo-in-file │ ├── main.fmf │ └── test_proxy_service_fails_on_typo_in_file.py │ ├── proxy-service-multiple-services-multiple-nodes │ ├── main.fmf │ └── test_proxy_service_multiple_services_multiple_nodes.py │ ├── proxy-service-multiple-services-one-node │ ├── main.fmf │ └── test_proxy_service_multiple_services_one_node.py │ ├── proxy-service-propagate-target-service-failure │ ├── main.fmf │ └── test_proxy_service_propagate_target_service_failure.py │ ├── proxy-service-start │ ├── main.fmf │ └── test_proxy_service_start.py │ ├── proxy-service-stop-bluechi-dep │ ├── main.fmf │ └── test_proxy_service_stop_bluechi_dep.py │ ├── proxy-service-stop-requesting-with-unneeded │ ├── main.fmf │ └── test_proxy_service_stop_requesting_with_unneeded.py │ ├── proxy-service-stop-requesting │ ├── main.fmf │ └── test_proxy_service_stop_requesting.py │ └── proxy-service-stop-target │ ├── main.fmf │ └── test_proxy_service_stop_target.py └── tools └── FFI ├── README.md └── bluechi-tester /.clang-format-include: -------------------------------------------------------------------------------- 1 | src/**/* 2 | -------------------------------------------------------------------------------- /.clangd: -------------------------------------------------------------------------------- 1 | CompileFlags: 2 | CompilationDatabase: builddir/ # Search builddir/ directory for compile_commands.json produced by meson 3 | -------------------------------------------------------------------------------- /.copr/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: installdeps srpm 2 | 3 | installdeps: 4 | dnf -y install gcc gcc-c++ git jq libselinux-devel meson systemd-devel rpm-build 5 | 6 | srpm: installdeps 7 | git config --global --add safe.directory "$(shell pwd)" 8 | ./build-scripts/build-srpm.sh 9 | cp rpmbuild/SRPMS/*.src.rpm $(outdir) 10 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # See github docs for more info on the syntax: 2 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 3 | 4 | # Default to all maintainers if nothing more specific matches 5 | * @alexlarsson @engelmi @mkemel 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: 7 | --- 8 | 9 | ## Describe the bug 10 | 11 | Please enter a clear and concise description of what the bug is. 12 | 13 | ## To Reproduce 14 | 15 | Please provide the steps to reproduce the issue. 16 | 17 | 1. ... 18 | 2. ... 19 | 3. ... 20 | 21 | ## Expected behavior 22 | 23 | Please describe what you would expect to happen. 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation request 3 | about: If you think something is not well described 4 | title: '' 5 | labels: documentation 6 | assignees: 7 | --- 8 | 9 | ## Please describe what information you were trying to find 10 | 11 | If you can describe the information you were trying to find we can structure our documentation better. 12 | 13 | ... 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature 6 | assignees: 7 | --- 8 | 9 | ## Please describe what you would like to see 10 | 11 | A clear and concise description of what you would like to see improved. 12 | 13 | ## Please describe the solution you'd like 14 | 15 | A clear and concise description of what you want to happen. 16 | 17 | ## Please describe your use case 18 | 19 | A clear and concise description of how you would use this feature. 20 | -------------------------------------------------------------------------------- /.github/workflows/images.yml: -------------------------------------------------------------------------------- 1 | name: Container Images 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | image: 7 | description: Name of the image to build and push to quay.io 8 | required: true 9 | type: choice 10 | options: 11 | - build-base 12 | - integration-test-base 13 | 14 | jobs: 15 | build_container: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout sources 19 | uses: actions/checkout@v4 20 | 21 | - name: Set up QEMU 22 | uses: docker/setup-qemu-action@v3 23 | 24 | - name: Build manifest 25 | run: | 26 | ./build-scripts/build-push-containers.sh ${{ inputs.image }} 27 | 28 | - name: Push manifest o quay.io 29 | uses: redhat-actions/push-to-registry@v2 30 | with: 31 | image: ${{ inputs.image }} 32 | registry: quay.io/bluechi 33 | username: bluechi+bluechi_bot 34 | password: ${{ secrets.QUAY_BOT_API_TOKEN }} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE 2 | .vscode/ 3 | .idea/ 4 | inspectionProfiles/ 5 | 6 | # Build 7 | tags 8 | builddir/ 9 | bluechi.spec 10 | rpmbuild/ 11 | artifacts/ 12 | build-scripts/RELEASE 13 | 14 | ## python build artifacts 15 | build/ 16 | dist/ 17 | bluechi.egg-info/ 18 | 19 | # Integration test 20 | bluechi-rpms/ 21 | __pycache__/ 22 | ## virtual env directories 23 | env/ 24 | .venv/ 25 | venv/ 26 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "subprojects/hashmap.c"] 2 | path = subprojects/hashmap.c 3 | url = https://github.com/eclipse-bluechi/hashmap.c.git 4 | [submodule "subprojects/inih"] 5 | path = subprojects/inih 6 | url = https://github.com/benhoyt/inih.git 7 | -------------------------------------------------------------------------------- /.markdownlint-cli2.yaml: -------------------------------------------------------------------------------- 1 | # Documentation for available configuration options can be found at 2 | # https://github.com/DavidAnson/markdownlint/tree/main/doc 3 | config: 4 | MD010: 5 | # Ignore tab characters in code blocks 6 | code_blocks: false 7 | MD013: 8 | # Ignore line length in code blocks 9 | code_blocks: false 10 | # Maximum line length 11 | line_length: 120 12 | # Ignore line length for tables 13 | tables: false 14 | 15 | globs: 16 | - "**/*.md" 17 | 18 | ignores: 19 | - "doc/man/*.md" 20 | - "subprojects/*/*.md" 21 | -------------------------------------------------------------------------------- /LICENSES/MIT-0.txt: -------------------------------------------------------------------------------- 1 | The MIT-Zero License 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /LICENSES/MIT.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Makefile.skipper: -------------------------------------------------------------------------------- 1 | rpm: 2 | SKIP_GIT_CONFIG=yes SKIP_BUILDDEP=yes ARTIFACTS_DIR=./tests/bluechi-rpms/ ./build-scripts/build-rpm.sh 3 | 4 | clean-rpm: 5 | rm -rf ./tests/bluechi-rpms/ 6 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | This project implements the [Eclipse Foundation Security Policy](https://www.eclipse.org/security). 4 | 5 | ## Supported Versions 6 | 7 | These versions of Eclipse BlueChi are currently being supported with security 8 | updates. 9 | 10 | | Version | Released | Supported | 11 | | ------- | ---------- | --------- | 12 | | 0.7.0 | 2024-01-19 | Yes | 13 | | 0.6.0 | 2023-11-13 | Yes | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Please report vulnerabilities to the Eclipse Foundation Security Team at 18 | . 19 | -------------------------------------------------------------------------------- /build-scripts/build-bindings.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | # Important note: 8 | # Run from root directory 9 | 10 | VERSION=$($(dirname "$(readlink -f "$0")")/version.sh) 11 | 12 | function python() { 13 | # Package python bindings 14 | PYTHON_BINDINGS_DIR="src/bindings/python/" 15 | cd $PYTHON_BINDINGS_DIR 16 | 17 | ## Set version and release 18 | sed \ 19 | -e "s|@VERSION@|${VERSION}|g" \ 20 | < "setup.py.in" \ 21 | > "setup.py" 22 | 23 | python3 "setup.py" bdist_wheel --dist-dir=dist/ 24 | } 25 | 26 | echo "Building bindings $1" 27 | echo "" 28 | $1 29 | -------------------------------------------------------------------------------- /build-scripts/build-rpm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | source $(dirname "$(readlink -f "$0")")/build-srpm.sh 8 | 9 | # Install build dependencies 10 | if [ "${SKIP_BUILDDEP}" != "yes" ]; then 11 | dnf builddep -y rpmbuild/SRPMS/*src.rpm 12 | fi 13 | 14 | # Build binary package 15 | rpmbuild \ 16 | --define "_topmdir rpmbuild" \ 17 | --define "_rpmdir rpmbuild" \ 18 | --define "with_coverage ${WITH_COVERAGE:=0}"\ 19 | --define "with_python ${WITH_PYTHON:=1}" \ 20 | --rebuild rpmbuild/SRPMS/*src.rpm 21 | 22 | # Move RPMs to exported artifacts 23 | ARTIFACTS_DIR="${ARTIFACTS_DIR:=$(pwd)/artifacts/rpms-$(date +%04Y%02m%02d%02H%02M)}" 24 | [[ -d $ARTIFACTS_DIR ]] || mkdir -p $ARTIFACTS_DIR 25 | find rpmbuild -iname \*rpm | xargs mv -t $ARTIFACTS_DIR 26 | -------------------------------------------------------------------------------- /build-scripts/build-srpm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | # Clean previously generated release cache 8 | $(dirname "$(readlink -f "$0")")/version.sh clean 9 | 10 | # Create source archive 11 | source $(dirname "$(readlink -f "$0")")/create-archive.sh 12 | 13 | mv bluechi-$VERSION.tar.gz rpmbuild/SOURCES/ 14 | 15 | # Build source package 16 | rpmbuild \ 17 | -D "_topdir rpmbuild" \ 18 | -bs bluechi.spec 19 | -------------------------------------------------------------------------------- /build-scripts/clang-tidy-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | additional_opts=$1 8 | 9 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 10 | SRC_DIR=$SCRIPT_DIR/../src 11 | BUILD_DIR=$SCRIPT_DIR/../builddir 12 | SUBPROJECTS_DIR=$SCRIPT_DIR/../subprojects 13 | 14 | ALL_SRC_FILES=$(find $SRC_DIR -name "*.[ch]" \ 15 | ! -path "$SRC_DIR/libbluechi/ini/ini.[ch]" \ 16 | ! -path "$SRC_DIR/libbluechi/hashmap/hashmap.[ch]" \ 17 | ! -path "$SRC_DIR/*/test/**" \ 18 | ! -path "$BUILD_DIR/**") 19 | 20 | for src_file in $ALL_SRC_FILES 21 | do 22 | echo "Linting $src_file..." 23 | 24 | # Header config.h is autogenerated during the build, so it needs to be added manually here as a parameter 25 | clang-tidy $additional_opts --quiet $src_file -- \ 26 | -I $SRC_DIR \ 27 | -I $BUILD_DIR \ 28 | -I $SUBPROJECTS_DIR/hashmap.c \ 29 | -I $SUBPROJECTS_DIR/inih \ 30 | -Wno-unknown-warning-option \ 31 | -include config.h 32 | done 33 | -------------------------------------------------------------------------------- /build-scripts/create-archive.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | source $(dirname "$(readlink -f "$0")")/create-spec.sh 8 | 9 | # Prepare source archive 10 | [[ -d rpmbuild/SOURCES ]] || mkdir -p rpmbuild/SOURCES 11 | 12 | git archive \ 13 | --format=tar \ 14 | -o bluechi-$VERSION.tar \ 15 | --prefix=bluechi-$VERSION/build-scripts/ \ 16 | --add-file=build-scripts/RELEASE \ 17 | --prefix=bluechi-$VERSION/ \ 18 | --add-file=bluechi.spec \ 19 | HEAD 20 | git submodule foreach --recursive \ 21 | "git archive --prefix=bluechi-$VERSION/\$path/ --output=\$sha1.tar HEAD && \ 22 | tar --concatenate --file=$(pwd)/bluechi-$VERSION.tar \$sha1.tar && rm \$sha1.tar" 23 | gzip bluechi-$VERSION.tar 24 | -------------------------------------------------------------------------------- /build-scripts/create-spec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | VERSION_SCRIPT=$(dirname "$(readlink -f "$0")")/version.sh 8 | 9 | VERSION="$(${VERSION_SCRIPT} short)" 10 | RELEASE="$(${VERSION_SCRIPT} release)" 11 | 12 | # Set version and release 13 | sed \ 14 | -e "s|@VERSION@|${VERSION}|g" \ 15 | -e "s|@RELEASE@|${RELEASE}|g" \ 16 | < bluechi.spec.in \ 17 | > bluechi.spec 18 | -------------------------------------------------------------------------------- /build-scripts/generate-bindings.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | SCRIPT_DIR=$( realpath "$0" ) 8 | SCRIPT_DIR=$(dirname "$SCRIPT_DIR")/ 9 | BINDINGS_DIR=$SCRIPT_DIR"../src/bindings/" 10 | 11 | generator=$BINDINGS_DIR"generator/src/generator.py" 12 | data_dir=$SCRIPT_DIR"../data/" 13 | 14 | function python(){ 15 | # Generate python bindings 16 | template_dir=$BINDINGS_DIR"/python/templates/" 17 | output_file_path=$BINDINGS_DIR"/python/bluechi/api.py" 18 | python3 "$generator" "$data_dir" "$template_dir" "$output_file_path" 19 | isort "$output_file_path" 20 | black "$output_file_path" 21 | } 22 | 23 | echo "Generating bindings for $1" 24 | echo "" 25 | $1 26 | -------------------------------------------------------------------------------- /build-scripts/install-coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | # This script should be executed only from meson as a part of install flow! 8 | # 9 | COVERAGE_ROOT="${MESON_INSTALL_DESTDIR_PREFIX}/share/bluechi-coverage" 10 | 11 | # Install all created `*.gcno` files so they could be packaged into bluechi-coverage RPM. 12 | mkdir -p ${COVERAGE_ROOT} 13 | ( cd $MESON_BUILD_ROOT ; find . -name "*.gcno" -exec cp -v --parents {} ${COVERAGE_ROOT} \; ) 14 | -------------------------------------------------------------------------------- /build-scripts/version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | # Current version of BlueChi 8 | VERSION=1.1.0 9 | # Specify if build is a official release or a snapshot build 10 | IS_RELEASE="0" 11 | # Used for official releases. Increment if necessary 12 | RELEASE="1" 13 | # Used to cache generated snapshot release for further usage 14 | RELEASE_FILE=$(dirname "$(readlink -f "$0")")/RELEASE 15 | 16 | function short(){ 17 | echo ${VERSION} 18 | } 19 | 20 | function long(){ 21 | echo "$(short)-$(release)" 22 | } 23 | 24 | function release(){ 25 | # Package release 26 | if [ -f "${RELEASE_FILE}" ]; then 27 | # Read existing release from release file to keep the same release during the whole build 28 | RELEASE="$(cat ${RELEASE_FILE})" 29 | else 30 | # Release file doesn't exist, populate it with a release 31 | if [ $IS_RELEASE == "0" ]; then 32 | RELEASE="0.$(date +%04Y%02m%02d%02H%02M).git$(git rev-parse --short ${GITHUB_SHA:-HEAD})" 33 | fi 34 | echo ${RELEASE} > ${RELEASE_FILE} 35 | fi 36 | echo $RELEASE 37 | } 38 | 39 | function clean(){ 40 | rm -f "${RELEASE_FILE}" 41 | } 42 | 43 | [ -z $1 ] && short || $1 44 | -------------------------------------------------------------------------------- /config/agent.conf.d/README.md: -------------------------------------------------------------------------------- 1 | # agent configuration directory 2 | 3 | This directory is used for user configuration of `bluechi-agent`. 4 | Each configuration file should end with `.conf` suffix, otherwise it's ignored. 5 | Configuration files from this directory are loaded by alphabetical order, 6 | configuration from a file loaded later overwrites the previous configuration. 7 | 8 | It's suggested to name configuration files using `-.conf` template, 9 | where `` is a number, for example `95-debug-logging.conf`. 10 | -------------------------------------------------------------------------------- /config/controller.conf.d/README.md: -------------------------------------------------------------------------------- 1 | # bluechi-controller configuration directory 2 | 3 | This directory is used for user configuration of `bluechi-controller`. 4 | Each configuration file should end with `.conf` suffix, otherwise it's ignored. 5 | Configuration files from this directory are loaded by alphabetical order, 6 | configuration from a file loaded later overwrites the previous configuration. 7 | 8 | It's suggested to name configuration files using `-.conf`template, 9 | where `` is a number, for example `95-debug-logging.conf`. 10 | -------------------------------------------------------------------------------- /config/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | install_data( 7 | install_dir : get_option('sysconfdir') / 'bluechi' 8 | ) 9 | 10 | install_data( 11 | 'agent/agent.conf', 12 | install_dir : join_paths(get_option('datadir'), 'bluechi-agent', 'config') 13 | ) 14 | 15 | install_data( 16 | 'controller/controller.conf', 17 | install_dir : join_paths(get_option('datadir'), 'bluechi', 'config') 18 | ) 19 | 20 | install_data( 21 | 'agent.conf.d/README.md', 22 | install_dir : join_paths(get_option('sysconfdir') / 'bluechi' / 'agent.conf.d') 23 | ) 24 | 25 | install_data( 26 | 'controller.conf.d/README.md', 27 | install_dir : join_paths(get_option('sysconfdir') / 'bluechi' / 'controller.conf.d') 28 | ) 29 | 30 | install_data( 31 | 'tmpfile/bluechi.conf', 32 | install_dir : join_paths(get_option('prefix'), 'lib', 'tmpfiles.d') 33 | ) 34 | -------------------------------------------------------------------------------- /config/tmpfile/bluechi.conf: -------------------------------------------------------------------------------- 1 | D! /run/bluechi 0700 root root 2 | -------------------------------------------------------------------------------- /containers/build-base: -------------------------------------------------------------------------------- 1 | FROM quay.io/centos/centos:stream9 2 | 3 | # CRB is required for meson 4 | # EPEL is required for lcov, python3-flake8, python3-html2text and codespell 5 | RUN dnf install -y dnf-plugin-config-manager && \ 6 | dnf config-manager -y --set-enabled crb && \ 7 | dnf install -y epel-release && \ 8 | dnf update --refresh --nodocs -y && \ 9 | dnf install --nodocs \ 10 | bzip2 \ 11 | clang \ 12 | clang-tools-extra \ 13 | codespell \ 14 | createrepo_c \ 15 | dnf-utils \ 16 | g++ \ 17 | gcc \ 18 | git \ 19 | golang-github-cpuguy83-md2man \ 20 | gzip \ 21 | jq \ 22 | lcov \ 23 | libselinux-devel \ 24 | make \ 25 | meson \ 26 | python3-html2text \ 27 | python3-pip \ 28 | python3-devel \ 29 | rpm-build \ 30 | sed \ 31 | selinux-policy-devel \ 32 | systemd-devel \ 33 | tar \ 34 | valgrind \ 35 | -y && \ 36 | dnf -y clean all 37 | 38 | # Install python dependencies 39 | COPY requirements.txt . 40 | RUN python3 -m venv /opt/bluechi-env && \ 41 | . /opt/bluechi-env/bin/activate && \ 42 | pip install -r requirements.txt && \ 43 | deactivate 44 | -------------------------------------------------------------------------------- /containers/integration-test-base: -------------------------------------------------------------------------------- 1 | FROM quay.io/centos/centos:stream9 2 | 3 | RUN dnf upgrade --refresh --nodocs -y && \ 4 | dnf install --nodocs epel-release -y && \ 5 | dnf install --nodocs \ 6 | lcov \ 7 | lsof \ 8 | policycoreutils-python-utils \ 9 | procps-ng \ 10 | python3-dasbus \ 11 | selinux-policy \ 12 | systemd \ 13 | systemd-devel \ 14 | valgrind \ 15 | -y && \ 16 | dnf -y clean all 17 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | # Installing the public DBus API 7 | install_data( 8 | [ 9 | 'org.eclipse.bluechi.Job.xml', 10 | 'org.eclipse.bluechi.Controller.xml', 11 | 'org.eclipse.bluechi.Monitor.xml', 12 | 'org.eclipse.bluechi.Node.xml', 13 | 'org.eclipse.bluechi.Agent.xml' 14 | ], 15 | install_dir: join_paths(get_option('datadir'), 'dbus-1', 'interfaces'), 16 | ) 17 | 18 | # Installing the DBus permission configuration files 19 | dbus_service_dir = join_paths(get_option('datadir'), 'dbus-1', 'system.d') 20 | dbus_srv_user = get_option('dbus-srv-user') 21 | if dbus_srv_user == '' 22 | dbus_srv_user = 'root' 23 | endif 24 | 25 | conf = configuration_data() 26 | conf.set('dbus_srv_user', dbus_srv_user) 27 | 28 | configure_file( 29 | output: 'org.eclipse.bluechi.conf', 30 | input: 'org.eclipse.bluechi.conf.in', 31 | configuration: conf, 32 | install_dir: dbus_service_dir, 33 | ) 34 | configure_file( 35 | output: 'org.eclipse.bluechi.Agent.conf', 36 | input: 'org.eclipse.bluechi.Agent.conf.in', 37 | configuration: conf, 38 | install_dir: dbus_service_dir, 39 | ) 40 | -------------------------------------------------------------------------------- /data/org.eclipse.bluechi.Agent.conf.in: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /data/org.eclipse.bluechi.conf.in: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /data/org.eclipse.bluechi.internal.Agent.Metrics.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /data/org.eclipse.bluechi.internal.Controller.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /data/org.eclipse.bluechi.internal.Proxy.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /debian/bluechi-agent.install: -------------------------------------------------------------------------------- 1 | etc/bluechi/agent.conf.d/README.md 2 | usr/lib/systemd/system/bluechi-agent.service 3 | usr/lib/systemd/system/bluechi-dep@.service 4 | usr/lib/systemd/system/bluechi-proxy@.service 5 | usr/lib/systemd/user/bluechi-agent.service 6 | usr/lib/systemd/user/bluechi-dep@.service 7 | usr/lib/systemd/user/bluechi-proxy@.service 8 | usr/libexec/bluechi-agent 9 | usr/libexec/bluechi-proxy 10 | usr/share/bluechi-agent/config/agent.conf 11 | usr/share/dbus-1/interfaces/org.eclipse.bluechi.Agent.xml 12 | usr/share/dbus-1/system.d/org.eclipse.bluechi.Agent.conf 13 | -------------------------------------------------------------------------------- /debian/bluechi-agent.manpages: -------------------------------------------------------------------------------- 1 | usr/share/man/man1/bluechi-agent.1 2 | usr/share/man/man5/bluechi-agent.conf.5 3 | usr/share/man/man1/bluechi-proxy.1 4 | -------------------------------------------------------------------------------- /debian/bluechi-controller.install: -------------------------------------------------------------------------------- 1 | etc/bluechi/controller.conf.d/README.md 2 | usr/lib/systemd/system/bluechi-controller.service 3 | usr/lib/systemd/system/bluechi-controller.socket 4 | usr/libexec/bluechi-controller 5 | usr/share/bluechi/config/controller.conf 6 | usr/share/dbus-1/interfaces/org.eclipse.bluechi.Controller.xml 7 | usr/share/dbus-1/interfaces/org.eclipse.bluechi.Job.xml 8 | usr/share/dbus-1/interfaces/org.eclipse.bluechi.Monitor.xml 9 | usr/share/dbus-1/interfaces/org.eclipse.bluechi.Node.xml 10 | usr/share/dbus-1/system.d/org.eclipse.bluechi.conf 11 | usr/lib/tmpfiles.d/bluechi.conf 12 | -------------------------------------------------------------------------------- /debian/bluechi-controller.manpages: -------------------------------------------------------------------------------- 1 | usr/share/man/man1/bluechi-controller.1 2 | usr/share/man/man5/bluechi-controller.conf.5 3 | -------------------------------------------------------------------------------- /debian/bluechi-deb-build: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | RUN apt update && \ 4 | apt upgrade -y && \ 5 | DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt install \ 6 | apt-utils \ 7 | cmake \ 8 | debhelper-compat \ 9 | dpkg-dev \ 10 | gcovr \ 11 | git \ 12 | go-md2man \ 13 | libsystemd-dev \ 14 | meson \ 15 | pkgconf \ 16 | wget \ 17 | -y 18 | -------------------------------------------------------------------------------- /debian/bluechi-is-online.install: -------------------------------------------------------------------------------- 1 | usr/bin/bluechi-is-online 2 | -------------------------------------------------------------------------------- /debian/bluechi-is-online.manpages: -------------------------------------------------------------------------------- 1 | usr/share/man/man1/bluechi-is-online.1 2 | -------------------------------------------------------------------------------- /debian/bluechictl.install: -------------------------------------------------------------------------------- 1 | usr/bin/bluechictl 2 | -------------------------------------------------------------------------------- /debian/bluechictl.manpages: -------------------------------------------------------------------------------- 1 | usr/share/man/man1/bluechictl.1 2 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | bluechi (1.0.0-1) stable; urgency=low 2 | 3 | * Upgrading to BlueChi v1.0.0. 4 | 5 | -- Michael Engel Tue, 27 May 2025 14:05:29 +0200 6 | 7 | 8 | bluechi (0.10.0-1) stable; urgency=low 9 | 10 | * Upgrading to BlueChi v0.10.0. 11 | 12 | -- Michael Engel Wed, 26 Feb 2025 14:05:29 +0200 13 | 14 | 15 | bluechi (0.9.0-1) stable; urgency=low 16 | 17 | * Upgrading to BlueChi v0.9.0. 18 | 19 | -- Michael Engel Di, 19 Nov 2024 14:05:29 +0200 20 | 21 | 22 | bluechi (0.8.0-1) stable; urgency=low 23 | 24 | * Initial packaging. 25 | 26 | -- Michael Engel Di, 30 Jul 2024 14:05:29 +0200 27 | -------------------------------------------------------------------------------- /debian/not-installed: -------------------------------------------------------------------------------- 1 | usr/share/man/man8/bluechi-agent-selinux.8 2 | usr/share/man/man8/bluechi-controller-selinux.8 3 | -------------------------------------------------------------------------------- /debian/patches/series: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/debian/patches/series -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | %: 3 | dh $@ 4 | 5 | execute_after_dh_clean: 6 | rm -f build-scripts/RELEASE 7 | 8 | override_dh_auto_configure: 9 | echo pdm-start 10 | meson setup -Dprefix=/usr -Dwith_selinux=false builddir 11 | echo pdm-end 12 | 13 | override_dh_install: 14 | meson install -C builddir --dest=debian/bluechi-controller 15 | meson install -C builddir --dest=debian/bluechi-agent 16 | meson install -C builddir --dest=debian/bluechictl 17 | dh_install 18 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /doc/.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-22.04 11 | tools: 12 | python: "3.11" 13 | 14 | mkdocs: 15 | configuration: doc/mkdocs.yml 16 | 17 | # Optionally declare the Python requirements required to build your docs 18 | python: 19 | install: 20 | - requirements: doc/requirements.txt 21 | -------------------------------------------------------------------------------- /doc/api-examples/c/setup.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **Setup sample project** 4 | 5 | The C/C++ snippets using [libsystemd](https://www.freedesktop.org/software/systemd/man/libsystemd.html) require at least a simple project setup. Create it via: 6 | 7 | ```bash 8 | # create project directory 9 | mkdir bluechi 10 | cd bluechi 11 | ``` 12 | 13 | **Installing dependencies** 14 | 15 | The C/C++ snippets use the [libsystemd](https://www.freedesktop.org/software/systemd/man/libsystemd.html) library for the D-Bus bindings. For compilation `gcc` and/or `g++` can be used. Install it via: 16 | 17 | ```bash 18 | # on Ubuntu 19 | apt update 20 | apt install libsystemd-dev build-essential 21 | # on Fedora/CentOS 22 | dnf install systemd-devel gcc g++ 23 | ``` 24 | 25 | **Build and run the sample project** 26 | 27 | The snippet chosen to run needs to be copied into the previously created the `bluechi` directory. After that the example can be build and run via: 28 | 29 | ```bash 30 | # either build for C 31 | gcc .c -g -Wall -o `pkg-config --cflags --libs libsystemd` 32 | # or for C++ 33 | g++ .cpp -g -Wall -o `pkg-config --cflags --libs libsystemd` 34 | # run the binary 35 | ./ 36 | ``` 37 | -------------------------------------------------------------------------------- /doc/api-examples/cpp/list-nodes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: MIT-0 5 | */ 6 | #include 7 | #include 8 | 9 | int main() { 10 | auto connection = sdbus::createSystemBusConnection(); 11 | auto controllerProxy = sdbus::createProxy( 12 | *connection, 13 | sdbus::ServiceName("org.eclipse.bluechi"), 14 | sdbus::ObjectPath("/org/eclipse/bluechi")); 15 | 16 | std::vector< sdbus::Struct< std::string, sdbus::ObjectPath, std::string, std::string > > nodes; 17 | sdbus::ObjectPath nodePath; 18 | controllerProxy->callMethod("ListNodes").onInterface("org.eclipse.bluechi.Controller").storeResultsTo(nodes); 19 | 20 | for (auto &node : nodes) { 21 | std::cout << "Node: " << node.get< 0 >() << ", Status: " << node.get< 2 >() << std::endl; 22 | } 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /doc/api-examples/cpp/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/api-examples/cpp/test -------------------------------------------------------------------------------- /doc/api-examples/go/list-nodes.go: -------------------------------------------------------------------------------- 1 | // Copyright Contributors to the Eclipse BlueChi project 2 | // 3 | // SPDX-License-Identifier: MIT-0 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | 11 | "github.com/godbus/dbus/v5" 12 | ) 13 | 14 | const ( 15 | BcDusInterface = "org.eclipse.bluechi" 16 | BcObjectPath = "/org/eclipse/bluechi" 17 | MethodListNodes = "org.eclipse.bluechi.Controller.ListNodes" 18 | ) 19 | 20 | func main() { 21 | conn, err := dbus.ConnectSystemBus() 22 | if err != nil { 23 | fmt.Fprintln(os.Stderr, "Failed to connect to system bus:", err) 24 | os.Exit(1) 25 | } 26 | defer conn.Close() 27 | 28 | var nodes [][]interface{} 29 | busObject := conn.Object(BcDusInterface, BcObjectPath) 30 | err = busObject.Call(MethodListNodes, 0).Store(&nodes) 31 | if err != nil { 32 | fmt.Fprintln(os.Stderr, "Failed to list nodes:", err) 33 | os.Exit(1) 34 | } 35 | 36 | for _, node := range nodes { 37 | fmt.Printf("Name: %s, Status: %s\n", node[0], node[2]) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /doc/api-examples/go/setup.md: -------------------------------------------------------------------------------- 1 | 2 | **Installing Go** 3 | 4 | First of all, install Go as described in the [official documentation](https://go.dev/doc/install). 5 | 6 | **Setup sample project** 7 | 8 | The Go snippets require at least a simple project setup. Create it via: 9 | 10 | ```bash 11 | # create project directory 12 | mkdir bluechi 13 | cd bluechi 14 | 15 | # initialize the project 16 | go mod init bluechi 17 | ``` 18 | 19 | **Installing dependencies** 20 | 21 | The Go snippets require [godbus](https://github.com/godbus/dbus/). Navigate into the `bluechi` directory and add it as a dependency via: 22 | 23 | ```bash 24 | go get github.com/godbus/dbus/v5 25 | ``` 26 | 27 | **Build and run the sample project** 28 | 29 | The snippet chosen to run needs to be copied into the `bluechi` directory. After that the example can be build and run via: 30 | 31 | ```bash 32 | go build 33 | ./ args... 34 | ``` 35 | -------------------------------------------------------------------------------- /doc/api-examples/python/get-cpuweight.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | import sys 8 | 9 | import dasbus.connection 10 | 11 | bus = dasbus.connection.SystemMessageBus() 12 | 13 | if len(sys.argv) != 3: 14 | print(f"Usage: python {sys.argv[0]} node_name unit_name") 15 | sys.exit(1) 16 | 17 | node_name = sys.argv[1] 18 | unit_name = sys.argv[2] 19 | 20 | controller = bus.get_proxy("org.eclipse.bluechi", "/org/eclipse/bluechi") 21 | node_path = controller.GetNode(node_name) 22 | node = bus.get_proxy("org.eclipse.bluechi", node_path) 23 | 24 | value = node.GetUnitProperty(unit_name, "org.freedesktop.systemd1.Service", "CPUWeight") 25 | print(value.get_uint64()) 26 | -------------------------------------------------------------------------------- /doc/api-examples/python/get-unit-properties.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | import sys 8 | 9 | import dasbus.connection 10 | from dasbus.typing import get_native 11 | 12 | bus = dasbus.connection.SystemMessageBus() 13 | 14 | if len(sys.argv) != 3: 15 | print("No node name and unit supplied") 16 | sys.exit(1) 17 | 18 | node_name = sys.argv[1] 19 | unit_name = sys.argv[2] 20 | 21 | controller = bus.get_proxy("org.eclipse.bluechi", "/org/eclipse/bluechi") 22 | node_path = controller.GetNode(node_name) 23 | node = bus.get_proxy("org.eclipse.bluechi", node_path) 24 | 25 | properties = node.GetUnitProperties(unit_name, "org.freedesktop.systemd1.Unit") 26 | print("Unit properties:") 27 | print(get_native(properties)) 28 | 29 | print("Service properties:") 30 | properties = node.GetUnitProperties(unit_name, "org.freedesktop.systemd1.Service") 31 | print(get_native(properties)) 32 | -------------------------------------------------------------------------------- /doc/api-examples/python/get-unit-property.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | import sys 8 | 9 | import dasbus.connection 10 | from dasbus.typing import get_native 11 | 12 | bus = dasbus.connection.SystemMessageBus() 13 | 14 | if len(sys.argv) != 5: 15 | print("No node name, unit, interface and property supplied") 16 | sys.exit(1) 17 | 18 | node_name = sys.argv[1] 19 | unit_name = sys.argv[2] 20 | iface_name = sys.argv[3] 21 | property_name = sys.argv[4] 22 | 23 | controller = bus.get_proxy("org.eclipse.bluechi", "/org/eclipse/bluechi") 24 | node_path = controller.GetNode(node_name) 25 | node = bus.get_proxy("org.eclipse.bluechi", node_path) 26 | 27 | val = node.GetUnitProperty(unit_name, iface_name, property_name) 28 | print(f"{property_name}: {get_native(val)}") 29 | -------------------------------------------------------------------------------- /doc/api-examples/python/list-active-services.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from collections import namedtuple 8 | 9 | import dasbus.connection 10 | 11 | bus = dasbus.connection.SystemMessageBus() 12 | 13 | NodeUnitInfo = namedtuple( 14 | "NodeUnitInfo", 15 | [ 16 | "name", 17 | "description", 18 | "load_state", 19 | "active_state", 20 | "sub_state", 21 | "follower", 22 | "object_path", 23 | "job_id", 24 | "job_type", 25 | "job_object_path", 26 | ], 27 | ) 28 | 29 | controller = bus.get_proxy("org.eclipse.bluechi", "/org/eclipse/bluechi") 30 | units = controller.ListUnits() 31 | for node, units in units.items(): 32 | for u in units: 33 | info = NodeUnitInfo(*u) 34 | if info.active_state == "active" and info.name.endswith(".service"): 35 | print(f"Node: {node}, Unit: {info.name}") 36 | -------------------------------------------------------------------------------- /doc/api-examples/python/list-node-units.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | import sys 8 | from collections import namedtuple 9 | 10 | import dasbus.connection 11 | 12 | bus = dasbus.connection.SystemMessageBus() 13 | 14 | UnitInfo = namedtuple( 15 | "UnitInfo", 16 | [ 17 | "name", 18 | "description", 19 | "load_state", 20 | "active_state", 21 | "sub_state", 22 | "follower", 23 | "object_path", 24 | "job_id", 25 | "job_type", 26 | "job_object_path", 27 | ], 28 | ) 29 | 30 | if len(sys.argv) != 2: 31 | print("No node name supplied") 32 | sys.exit(1) 33 | 34 | node_name = sys.argv[1] 35 | 36 | controller = bus.get_proxy("org.eclipse.bluechi", "/org/eclipse/bluechi") 37 | node_path = controller.GetNode(node_name) 38 | node = bus.get_proxy("org.eclipse.bluechi", node_path) 39 | 40 | units = node.ListUnits() 41 | for u in units: 42 | info = UnitInfo(*u) 43 | print(f"{info.name} - {info.description}") 44 | -------------------------------------------------------------------------------- /doc/api-examples/python/list-nodes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from collections import namedtuple 8 | 9 | import dasbus.connection 10 | 11 | bus = dasbus.connection.SystemMessageBus() 12 | 13 | NodeInfo = namedtuple("NodeInfo", ["name", "object_path", "status", "peer_ip"]) 14 | 15 | controller = bus.get_proxy("org.eclipse.bluechi", "/org/eclipse/bluechi") 16 | nodes = controller.ListNodes() 17 | for n in nodes: 18 | info = NodeInfo(*n) 19 | print(f"Node: {info.name}, State: {info.status}") 20 | -------------------------------------------------------------------------------- /doc/api-examples/python/monitor-agent-connection.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: MIT-0 5 | 6 | from typing import Dict 7 | 8 | import dasbus.connection 9 | from dasbus.loop import EventLoop 10 | from dasbus.typing import Variant 11 | 12 | loop = EventLoop() 13 | bus = dasbus.connection.SystemMessageBus() 14 | 15 | agent_props_proxy = bus.get_proxy( 16 | "org.eclipse.bluechi.Agent", 17 | "/org/eclipse/bluechi", 18 | "org.freedesktop.DBus.Properties", 19 | ) 20 | 21 | 22 | def on_connection_status_changed( 23 | interface: str, 24 | changed_props: Dict[str, Variant], 25 | invalidated_props: Dict[str, Variant], 26 | ) -> None: 27 | con_status = changed_props["Status"].get_string() 28 | print(f"Agent status: {con_status}") 29 | 30 | 31 | agent_props_proxy.PropertiesChanged.connect(on_connection_status_changed) 32 | 33 | loop.run() 34 | -------------------------------------------------------------------------------- /doc/api-examples/python/monitor-node-connections.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: MIT-0 5 | 6 | from typing import Dict 7 | 8 | import dasbus.connection 9 | from dasbus.loop import EventLoop 10 | from dasbus.typing import Variant 11 | 12 | loop = EventLoop() 13 | bus = dasbus.connection.SystemMessageBus() 14 | 15 | controller = bus.get_proxy("org.eclipse.bluechi", "/org/eclipse/bluechi") 16 | nodes = controller.ListNodes() 17 | cached_nodes = [] 18 | for n in nodes: 19 | # node: [name, path, status] 20 | node = bus.get_proxy("org.eclipse.bluechi", n[1], "org.freedesktop.DBus.Properties") 21 | 22 | def changed_wrapper(node_name: str): 23 | def on_connection_status_changed( 24 | interface: str, 25 | changed_props: Dict[str, Variant], 26 | invalidated_props: Dict[str, Variant], 27 | ) -> None: 28 | con_status = changed_props["Status"].get_string() 29 | print(f"Node {node_name}: {con_status}") 30 | 31 | return on_connection_status_changed 32 | 33 | node.PropertiesChanged.connect(changed_wrapper(n[0])) 34 | cached_nodes.append(node) 35 | 36 | loop.run() 37 | -------------------------------------------------------------------------------- /doc/api-examples/python/monitor-system-status.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: MIT-0 5 | 6 | from typing import Dict 7 | 8 | import dasbus.connection 9 | from dasbus.loop import EventLoop 10 | from dasbus.typing import Variant 11 | 12 | loop = EventLoop() 13 | bus = dasbus.connection.SystemMessageBus() 14 | 15 | agent_props_proxy = bus.get_proxy( 16 | "org.eclipse.bluechi", "/org/eclipse/bluechi", "org.freedesktop.DBus.Properties" 17 | ) 18 | 19 | 20 | def on_connection_status_changed( 21 | interface: str, 22 | changed_props: Dict[str, Variant], 23 | invalidated_props: Dict[str, Variant], 24 | ) -> None: 25 | con_status = changed_props["Status"].get_string() 26 | print(f"System status: {con_status}") 27 | 28 | 29 | agent_props_proxy.PropertiesChanged.connect(on_connection_status_changed) 30 | 31 | loop.run() 32 | -------------------------------------------------------------------------------- /doc/api-examples/python/set-cpuweight.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | import sys 8 | 9 | import dasbus.connection 10 | from dasbus.typing import Variant 11 | 12 | bus = dasbus.connection.SystemMessageBus() 13 | 14 | if len(sys.argv) != 4: 15 | print(f"Usage: python {sys.argv[0]} node_name unit_name cpu_weight") 16 | sys.exit(1) 17 | 18 | node_name = sys.argv[1] 19 | unit_name = sys.argv[2] 20 | value = int(sys.argv[3]) 21 | 22 | # Don't persist change 23 | runtime = True 24 | 25 | controller = bus.get_proxy("org.eclipse.bluechi", "/org/eclipse/bluechi") 26 | node_path = controller.GetNode(node_name) 27 | node = bus.get_proxy("org.eclipse.bluechi", node_path) 28 | 29 | node.SetUnitProperties(unit_name, runtime, [("CPUWeight", Variant("t", value))]) 30 | -------------------------------------------------------------------------------- /doc/api-examples/python/setup.md: -------------------------------------------------------------------------------- 1 | 2 | **Installing Python** 3 | 4 | First of all, install Python via: 5 | 6 | ```bash 7 | # on Ubuntu 8 | apt install python3 python3-dev 9 | # on Fedora/CentOS 10 | dnf install python3 python3-devel 11 | ``` 12 | 13 | **Installing dependencies** 14 | 15 | The python snippets require the [dasbus](https://dasbus.readthedocs.io/en/latest/) package. Install it via pip: 16 | 17 | ```bash 18 | # ensure pip has been installed 19 | python3 -m ensurepip --default-pip 20 | pip3 install dasbus 21 | ``` 22 | 23 | **Running the examples** 24 | 25 | The snippets can be run by simply copy and pasting it into a new file running it via: 26 | 27 | ```bash 28 | python3 .py args... 29 | ``` 30 | -------------------------------------------------------------------------------- /doc/api-examples/python/start-unit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | import sys 8 | 9 | from dasbus.connection import SystemMessageBus 10 | 11 | bus = SystemMessageBus() 12 | 13 | if len(sys.argv) != 3: 14 | print(f"Usage: python {sys.argv[0]} node_name unit_name") 15 | sys.exit(1) 16 | 17 | node_name = sys.argv[1] 18 | unit_name = sys.argv[2] 19 | 20 | controller = bus.get_proxy("org.eclipse.bluechi", "/org/eclipse/bluechi") 21 | node_path = controller.GetNode(node_name) 22 | node = bus.get_proxy("org.eclipse.bluechi", node_path) 23 | 24 | my_job_path = node.StartUnit(unit_name, "replace") 25 | 26 | print(f"Started unit '{unit_name}' on node '{node_name}': {my_job_path}") 27 | -------------------------------------------------------------------------------- /doc/api-examples/rust/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /doc/api-examples/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bluechi" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = { version = "4.4.6", features = ["derive"] } 10 | dbus = "0.9.7" 11 | 12 | [[bin]] 13 | name = "enable-unit" 14 | path = "enable-unit.rs" 15 | 16 | [[bin]] 17 | name = "get-cpuweight" 18 | path = "get-cpuweight.rs" 19 | 20 | [[bin]] 21 | name = "list-node-units" 22 | path = "list-node-units.rs" 23 | 24 | [[bin]] 25 | name = "list-nodes" 26 | path = "list-nodes.rs" 27 | 28 | [[bin]] 29 | name = "monitor-agent-connection" 30 | path = "monitor-agent-connection.rs" 31 | 32 | [[bin]] 33 | name = "monitor-node-connections" 34 | path = "monitor-node-connections.rs" 35 | 36 | [[bin]] 37 | name = "monitor-system-status" 38 | path = "monitor-system-status.rs" 39 | 40 | [[bin]] 41 | name = "monitor-unit" 42 | path = "monitor-unit.rs" 43 | 44 | [[bin]] 45 | name = "set-cpuweight" 46 | path = "set-cpuweight.rs" 47 | 48 | [[bin]] 49 | name = "start-unit" 50 | path = "start-unit.rs" 51 | -------------------------------------------------------------------------------- /doc/api-examples/rust/list-nodes.rs: -------------------------------------------------------------------------------- 1 | // Copyright Contributors to the Eclipse BlueChi project 2 | // 3 | // SPDX-License-Identifier: MIT-0 4 | 5 | use dbus::blocking::Connection; 6 | use std::time::Duration; 7 | 8 | fn main() -> Result<(), Box> { 9 | let conn = Connection::new_system()?; 10 | 11 | let bluechi = conn.with_proxy( 12 | "org.eclipse.bluechi", 13 | "/org/eclipse/bluechi", 14 | Duration::from_millis(5000), 15 | ); 16 | 17 | let (nodes,): (Vec<(String, dbus::Path, String, String)>,) = 18 | bluechi.method_call("org.eclipse.bluechi.Controller", "ListNodes", ())?; 19 | 20 | for (name, _, status) in nodes { 21 | println!("Node: {}, Status: {}", name, status); 22 | } 23 | 24 | Ok(()) 25 | } 26 | -------------------------------------------------------------------------------- /doc/api-examples/rust/monitor-agent-connection.rs: -------------------------------------------------------------------------------- 1 | // Copyright Contributors to the Eclipse BlueChi project 2 | // 3 | // SPDX-License-Identifier: MIT-0 4 | 5 | use dbus::{ 6 | arg::Variant, 7 | blocking::{stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged, Connection}, 8 | Message, 9 | }; 10 | use std::time::Duration; 11 | 12 | fn main() -> Result<(), Box> { 13 | let conn = Connection::new_system()?; 14 | 15 | let bluechi = conn.with_proxy( 16 | "org.eclipse.bluechi.Agent", 17 | "/org/eclipse/bluechi", 18 | Duration::from_millis(5000), 19 | ); 20 | let _id = bluechi.match_signal( 21 | |signal: PropertiesPropertiesChanged, _: &Connection, _: &Message| { 22 | match signal.changed_properties.get_key_value("Status") { 23 | Some((_, Variant(changed_value))) => { 24 | println!("Agent status: {}", changed_value.as_str().unwrap_or("")) 25 | } 26 | _ => {} 27 | } 28 | true 29 | }, 30 | ); 31 | 32 | loop { 33 | conn.process(Duration::from_millis(1000))?; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /doc/api-examples/rust/monitor-system-status.rs: -------------------------------------------------------------------------------- 1 | // Copyright Contributors to the Eclipse BlueChi project 2 | // 3 | // SPDX-License-Identifier: MIT-0 4 | 5 | use dbus::{ 6 | arg::Variant, 7 | blocking::{stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged, Connection}, 8 | Message, 9 | }; 10 | use std::time::Duration; 11 | 12 | fn main() -> Result<(), Box> { 13 | let conn = Connection::new_system()?; 14 | 15 | let bluechi = conn.with_proxy( 16 | "org.eclipse.bluechi", 17 | "/org/eclipse/bluechi", 18 | Duration::from_millis(5000), 19 | ); 20 | let _id = bluechi.match_signal( 21 | |signal: PropertiesPropertiesChanged, _: &Connection, _: &Message| { 22 | match signal.changed_properties.get_key_value("Status") { 23 | Some((_, Variant(changed_value))) => { 24 | println!("System status: {}", changed_value.as_str().unwrap_or("")) 25 | } 26 | _ => {} 27 | } 28 | true 29 | }, 30 | ); 31 | 32 | loop { 33 | conn.process(Duration::from_millis(1000))?; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /doc/api-examples/rust/setup.md: -------------------------------------------------------------------------------- 1 | 2 | **Installing Rust** 3 | 4 | First of all, install Rust as describe in the [official documentation](https://www.rust-lang.org/tools/install). 5 | 6 | **Installing dependencies** 7 | 8 | The Rust snippets requires [dbus](https://docs.rs/dbus/latest/dbus/index.html). 9 | Since this crate needs the reference implementation `libdbus`, it has to be installed: 10 | 11 | ```bash 12 | # on Ubuntu 13 | apt install libdbus-1-dev pkg-config 14 | # on Fedora/CentOS 15 | dnf install dbus-devel pkgconf-pkg-config 16 | ``` 17 | 18 | **Build and run the sample project** 19 | 20 | The snippet chosen to run needs to be copied into the `bluechi` directory. After that the example can be build and run via: 21 | 22 | ```bash 23 | # clone the BlueChi project 24 | $ git clone https://github.com/eclipse-bluechi/bluechi.git 25 | 26 | # navigate into the rust api-examples directory 27 | $ cd bluechi/doc/api-examples/rust 28 | 29 | # build all example applications 30 | $ cargo build 31 | 32 | # run a specific example, e.g. start-unit 33 | $ ./target/debug/start-unit laptop cow.service 34 | $ ... 35 | ``` 36 | -------------------------------------------------------------------------------- /doc/bluechi-examples/CPUWeight.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from bluechi.api import Node 8 | 9 | cpu_weight = Node("my-node-name").get_unit_property( 10 | "ldconfig.service", "org.freedesktop.systemd1.Service", "CPUWeight" 11 | ) 12 | print(cpu_weight) 13 | -------------------------------------------------------------------------------- /doc/bluechi-examples/DisableUnit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from bluechi.ext import Unit 8 | 9 | Unit("my-node-name").disable_unit_files(["chronyd.service", "bluechi-agent.service"]) 10 | -------------------------------------------------------------------------------- /doc/bluechi-examples/EnableUnit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from bluechi.ext import Unit 8 | 9 | response = Unit("my-node-name").enable_unit_files( 10 | ["chronyd.service", "bluechi-agent.service"] 11 | ) 12 | if response.carries_install_info: 13 | print("The unit files included enablement information") 14 | else: 15 | print("The unit files did not include any enablement information") 16 | 17 | for change in response.changes: 18 | if change.change_type == "symlink": 19 | print( 20 | f"Created symlink {change.symlink_file}" 21 | " -> {enabled_service_info.symlink_dest}" 22 | ) 23 | elif change.change_type == "unlink": 24 | print(f'Removed "{change.symlink_file}".') 25 | -------------------------------------------------------------------------------- /doc/bluechi-examples/ListActiveServices.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from bluechi.api import Controller 8 | 9 | for unit in Controller().list_units(): 10 | # unit[node, name, description, load_state, active_state, ...] 11 | if unit[4] == "active" and unit[1].endswith(".service"): 12 | print(f"Node: {unit[0]}, Unit: {unit[1]}") 13 | -------------------------------------------------------------------------------- /doc/bluechi-examples/ListAllNodes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from bluechi.api import Controller 8 | 9 | for node in Controller().list_nodes(): 10 | # node[name, obj_path, status, peer_ip] 11 | print(f"Node: {node[0]}, State: {node[2]}") 12 | -------------------------------------------------------------------------------- /doc/bluechi-examples/ListNodeUnits.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from bluechi.api import Node 8 | 9 | for unit in Node("my-node-name").list_units(): 10 | # unit[name, description, ...] 11 | print(f"{unit[0]} - {unit[1]}") 12 | -------------------------------------------------------------------------------- /doc/bluechi-examples/MonitorAgentConnection.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: MIT-0 5 | 6 | from dasbus.loop import EventLoop 7 | from dasbus.typing import Variant 8 | 9 | from bluechi.api import Agent 10 | 11 | 12 | def on_connection_status_changed(status: Variant): 13 | con_status = status.get_string() 14 | print(con_status) 15 | 16 | 17 | loop = EventLoop() 18 | 19 | agent = Agent() 20 | agent.on_status_changed(on_connection_status_changed) 21 | 22 | loop.run() 23 | -------------------------------------------------------------------------------- /doc/bluechi-examples/MonitorNodeConnections.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: MIT-0 5 | 6 | from dasbus.loop import EventLoop 7 | from dasbus.typing import Variant 8 | 9 | from bluechi.api import Controller, Node 10 | 11 | loop = EventLoop() 12 | 13 | nodes = [] 14 | for node in Controller().list_nodes(): 15 | n = Node(node[0]) 16 | 17 | def changed_wrapper(node_name: str): 18 | def on_connection_status_changed(status: Variant): 19 | con_status = status.get_string() 20 | print(f"Node {node_name}: {con_status}") 21 | 22 | return on_connection_status_changed 23 | 24 | n.on_status_changed(changed_wrapper(n.name)) 25 | nodes.append(n) 26 | 27 | 28 | loop.run() 29 | -------------------------------------------------------------------------------- /doc/bluechi-examples/MonitorSystemStatus.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: MIT-0 5 | 6 | from dasbus.loop import EventLoop 7 | from dasbus.typing import Variant 8 | 9 | from bluechi.api import Controller 10 | 11 | 12 | def on_system_status_changed(status: Variant): 13 | con_status = status.get_string() 14 | print(con_status) 15 | 16 | 17 | loop = EventLoop() 18 | 19 | mgr = Controller() 20 | mgr.on_status_changed(on_system_status_changed) 21 | 22 | loop.run() 23 | -------------------------------------------------------------------------------- /doc/bluechi-examples/SetCPUWeight.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from dasbus.typing import Variant 8 | 9 | from bluechi.api import Node 10 | 11 | Node("my-node-name").set_unit_properties( 12 | "ldconfig.service", False, [("CPUWeight", Variant("t", 18446744073709551615))] 13 | ) 14 | -------------------------------------------------------------------------------- /doc/bluechi-examples/StartUnit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from bluechi.ext import Unit 8 | 9 | result = Unit("my-node-name").start_unit("chronyd.service") 10 | print(result) 11 | -------------------------------------------------------------------------------- /doc/bluechi-examples/StopUnit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | from bluechi.ext import Unit 8 | 9 | result = Unit("my-node-name").stop_unit("chronyd.service") 10 | print(result) 11 | -------------------------------------------------------------------------------- /doc/docs/architecture.md: -------------------------------------------------------------------------------- 1 | # BlueChi's Architecture 2 | 3 | The image below depicts a generic overview of the BlueChi architecture: 4 | 5 | ![BlueChi Architecture diagram](assets/img/bluechi_architecture_overview.png) 6 | 7 | Any application that wants to integrate with BlueChi does so via it's public D-Bus API on the local system bus. These 8 | custom applications can be written in [a variety of languages](./api/examples.md). 9 | 10 | One example of such an application shown in the diagram above is a state manager for the overall system. It can use 11 | BlueChi's API to perform actions, receive their the outcome and/or monitor the state of services as well as the 12 | connection state of managed nodes. 13 | 14 | For administrators, `bluechictl` is the preferred interface sparing 15 | administrators from interacting with BlueChi via D-Bus directly. 16 | -------------------------------------------------------------------------------- /doc/docs/assets/img/bluechi_architecture_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/docs/assets/img/bluechi_architecture_overview.png -------------------------------------------------------------------------------- /doc/docs/assets/img/bluechi_cross_node_dependency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/docs/assets/img/bluechi_cross_node_dependency.png -------------------------------------------------------------------------------- /doc/docs/assets/img/bluechi_proxy_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/docs/assets/img/bluechi_proxy_architecture.png -------------------------------------------------------------------------------- /doc/docs/assets/img/bluechi_proxy_service_multi_node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/docs/assets/img/bluechi_proxy_service_multi_node.png -------------------------------------------------------------------------------- /doc/docs/assets/img/bluechi_proxy_service_single_node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/docs/assets/img/bluechi_proxy_service_single_node.png -------------------------------------------------------------------------------- /doc/docs/assets/img/bluechi_secure_proxy_connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/docs/assets/img/bluechi_secure_proxy_connection.png -------------------------------------------------------------------------------- /doc/docs/assets/img/bluechi_secure_simple_connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/docs/assets/img/bluechi_secure_simple_connection.png -------------------------------------------------------------------------------- /doc/docs/assets/img/bluechi_setup_multi_node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/docs/assets/img/bluechi_setup_multi_node.png -------------------------------------------------------------------------------- /doc/docs/assets/img/bluechi_setup_single_node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/docs/assets/img/bluechi_setup_single_node.png -------------------------------------------------------------------------------- /doc/docs/assets/img/bluechi_using_proxy_services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/docs/assets/img/bluechi_using_proxy_services.png -------------------------------------------------------------------------------- /doc/docs/assets/js/tab-sync.js: -------------------------------------------------------------------------------- 1 | const tabSync = () => { 2 | const tabs = document.querySelectorAll(".tabbed-set > input") 3 | for (const tab of tabs) { 4 | tab.addEventListener("click", () => { 5 | const current = document.querySelector(`label[for=${tab.id}]`) 6 | const pos = current.getBoundingClientRect().top 7 | const labelContent = current.innerHTML 8 | const labels = document.querySelectorAll('.tabbed-set > label, .tabbed-alternate > .tabbed-labels > label') 9 | for (const label of labels) { 10 | if (label.innerHTML === labelContent && !document.querySelector(`input[id=${label.getAttribute('for')}]`).checked) { 11 | label.click() 12 | } 13 | } 14 | 15 | // Preserve scroll position 16 | const delta = (current.getBoundingClientRect().top) - pos 17 | window.scrollBy(0, delta) 18 | }) 19 | } 20 | } 21 | 22 | tabSync() 23 | -------------------------------------------------------------------------------- /doc/docs/man/bluechi-agent-conf.md: -------------------------------------------------------------------------------- 1 | 2 | --8<-- "man/bluechi-agent.conf.5.md:2" 3 | -------------------------------------------------------------------------------- /doc/docs/man/bluechi-agent-selinux.md: -------------------------------------------------------------------------------- 1 | 2 | --8<-- "man/bluechi-agent-selinux.8.md:2" 3 | -------------------------------------------------------------------------------- /doc/docs/man/bluechi-agent.md: -------------------------------------------------------------------------------- 1 | 2 | --8<-- "man/bluechi-agent.1.md:2" 3 | -------------------------------------------------------------------------------- /doc/docs/man/bluechi-controller-conf.md: -------------------------------------------------------------------------------- 1 | 2 | --8<-- "man/bluechi-controller.conf.5.md:2" 3 | -------------------------------------------------------------------------------- /doc/docs/man/bluechi-controller-selinux.md: -------------------------------------------------------------------------------- 1 | 2 | --8<-- "man/bluechi-controller-selinux.8.md:2" 3 | -------------------------------------------------------------------------------- /doc/docs/man/bluechi-controller.md: -------------------------------------------------------------------------------- 1 | 2 | --8<-- "man/bluechi-controller.1.md:2" 3 | -------------------------------------------------------------------------------- /doc/docs/man/bluechi-is-online.md: -------------------------------------------------------------------------------- 1 | 2 | --8<-- "man/bluechi-is-online.1.md:2" 3 | -------------------------------------------------------------------------------- /doc/docs/man/bluechi-proxy.md: -------------------------------------------------------------------------------- 1 | 2 | --8<-- "man/bluechi-proxy.1.md:2" 3 | -------------------------------------------------------------------------------- /doc/docs/man/bluechictl.md: -------------------------------------------------------------------------------- 1 | 2 | --8<-- "man/bluechictl.1.md:2" 3 | -------------------------------------------------------------------------------- /doc/eclipse-bluechi-introduction.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/doc/eclipse-bluechi-introduction.pdf -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs>=1.3.0 2 | mkdocs-material>=9.3.1 3 | pymdown-extensions>=10.0.1 4 | -------------------------------------------------------------------------------- /logo/bluechi-logo-horiz-1280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/logo/bluechi-logo-horiz-1280.png -------------------------------------------------------------------------------- /logo/bluechi-logo-horiz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/logo/bluechi-logo-horiz.png -------------------------------------------------------------------------------- /logo/bluechi-logo-plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/logo/bluechi-logo-plain.png -------------------------------------------------------------------------------- /logo/bluechi-logo-vert-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/logo/bluechi-logo-vert-100.png -------------------------------------------------------------------------------- /logo/bluechi-logo-vert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/logo/bluechi-logo-vert.png -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('api_bus', type: 'combo', 2 | choices: ['user', 'system'], value: 'system', 3 | description: 'The D-Bus daemon on which the public BlueChi API is provided') 4 | 5 | option('dbus-srv-user', type: 'string', description: 'The (existing) user which runs bluechi') 6 | 7 | option('with_analyzer', type : 'boolean', value : false, 8 | description : 'Add the gcc option -fanalyzer for static analysis') 9 | 10 | option('with_coverage', type : 'boolean', value : false, 11 | description : 'Enable the code coverage collection') 12 | 13 | option('with_man_pages', type : 'boolean', value : true, 14 | description : 'Build and install man pages') 15 | 16 | option('with_selinux', type : 'boolean', value : true, 17 | description : 'Include the build and install of bluechi-selinux') 18 | 19 | option('unix_domain_socket_path', type : 'string', 20 | description: 'The path of the Unix Domain Socket for BlueChi', 21 | value: '/run/bluechi/bluechi.sock') 22 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # NOTE: containers/build-base image needs to be rebuilt after changing this file! 2 | 3 | # Try to keep linter package versions aligned with latest Fedora RPM versions 4 | black==24.3.0 5 | flake8==6.0.0 6 | isort==5.13.2 7 | -------------------------------------------------------------------------------- /selinux/.gitignore: -------------------------------------------------------------------------------- 1 | *.bz2 2 | tmp 3 | *~ 4 | -------------------------------------------------------------------------------- /selinux/bluechi.fc: -------------------------------------------------------------------------------- 1 | /usr/bin/bluechi-controller -- gen_context(system_u:object_r:bluechi_exec_t,s0) 2 | /usr/libexec/bluechi-controller -- gen_context(system_u:object_r:bluechi_exec_t,s0) 3 | 4 | /usr/bin/bluechi-agent -- gen_context(system_u:object_r:bluechi_agent_exec_t,s0) 5 | /usr/libexec/bluechi-agent -- gen_context(system_u:object_r:bluechi_agent_exec_t,s0) 6 | 7 | # Since /var/run is canonical in rhel9 and /run in rhel10 8 | # we apply the context for both directories 9 | /run/bluechi(/.*)? gen_context(system_u:object_r:bluechi_var_run_t,s0) 10 | /var/run/bluechi(/.*)? gen_context(system_u:object_r:bluechi_var_run_t,s0) 11 | -------------------------------------------------------------------------------- /selinux/build-selinux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2019 Red Hat Inc. 3 | # Copyright 2022 Collabora Ltd. 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | set -eu 7 | 8 | TMP=$(mktemp -d selinux-build-XXXXXX) 9 | output="$1" 10 | shift 11 | cp -- "$@" "$TMP/" 12 | 13 | make -C "$TMP" -f /usr/share/selinux/devel/Makefile bluechi.pp 14 | bzip2 -9 "$TMP/bluechi.pp" 15 | cp "$TMP/bluechi.pp.bz2" "$output" 16 | rm -fr "$TMP" 17 | -------------------------------------------------------------------------------- /selinux/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2022 Collabora Ltd. 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | custom_target( 7 | 'bluechi.pp.bz2', 8 | input : ['bluechi.te', 'bluechi.fc'], 9 | output : ['bluechi.pp.bz2'], 10 | build_by_default : true, 11 | command : [ 12 | files('build-selinux.sh'), 13 | '@OUTPUT0@', 14 | '@INPUT@', 15 | ], 16 | install : true, 17 | install_dir : join_paths(get_option('datadir'), 'selinux', 'packages'), 18 | ) 19 | 20 | install_data( 21 | 'bluechi.if', 22 | install_dir : join_paths(get_option('datadir'), 'selinux', 'devel', 'include', 'services'), 23 | ) -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [black] 2 | target-version = ["py39", "py310", "py311"] 3 | 4 | [flake8] 5 | max-line-length = 120 6 | extend-ignore = E203,E701 7 | 8 | [isort] 9 | profile = black 10 | -------------------------------------------------------------------------------- /skipper.yaml: -------------------------------------------------------------------------------- 1 | build_container_image: quay.io/bluechi/build-base 2 | build_container_tag: latest 3 | make: 4 | makefile: Makefile.skipper 5 | -------------------------------------------------------------------------------- /src/agent/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | # node build configuration 7 | 8 | node_src = [ 9 | 'main.c', 10 | 'agent.c', 11 | 'proxy.c' 12 | ] 13 | 14 | executable( 15 | 'bluechi-agent', 16 | node_src, 17 | dependencies: [ 18 | systemd_dep, 19 | inih_dep, 20 | hashmapc_dep, 21 | ], 22 | link_with: [ 23 | bluechi_lib, 24 | ], 25 | c_args: common_cflags, 26 | include_directories: include_directories('..'), 27 | install: true, 28 | install_dir: join_paths(prefixdir, get_option('libexecdir')) 29 | ) 30 | 31 | # build test binaries 32 | subdir('test') 33 | -------------------------------------------------------------------------------- /src/agent/test/agent/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | agent_src = [ 7 | 'agent_apply_config_test', 8 | ] 9 | 10 | # setup node test src files to include in compilation 11 | node_test_src = [] 12 | foreach src : node_src 13 | # skip main to avoid duplicate main function error 14 | if src == 'main.c' 15 | continue 16 | endif 17 | node_test_src += '../../' + src 18 | endforeach 19 | 20 | foreach src : agent_src 21 | exec_test = executable(src, 22 | node_test_src + [src + '.c'], 23 | dependencies: [ 24 | systemd_dep, 25 | inih_dep, 26 | hashmapc_dep, 27 | ], 28 | link_with: [ 29 | bluechi_lib, 30 | ], 31 | c_args: common_cflags, 32 | include_directories: include_directories('../../..'), 33 | ) 34 | test(src, exec_test) 35 | endforeach 36 | -------------------------------------------------------------------------------- /src/agent/test/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | subdir('agent') 7 | -------------------------------------------------------------------------------- /src/agent/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | typedef struct ProxyService ProxyService; 9 | typedef struct Agent Agent; 10 | -------------------------------------------------------------------------------- /src/bindings/README.md: -------------------------------------------------------------------------------- 1 | # BlueChi bindings 2 | 3 | - [BlueChi bindings](#bluechi-bindings) 4 | - [Directory structure](#directory-structure) 5 | - [Examples](#examples) 6 | 7 | This directory contains bindings for the D-Bus API of BlueChi. The [API description](./../../data/) of BlueChi is used to 8 | generate basic client stub code that provides the complete set of functionality. Based on the generated code, custom 9 | functions are written to simplify recurring tasks. 10 | 11 | ## Directory structure 12 | 13 | - [bindings/generator](./generator/): small python project used to generate client code for the D-Bus API 14 | - [bindinds/python](./python/): python client for bluechi 15 | 16 | ## Examples 17 | 18 | - [See our documentation page](../../doc/bluechi-examples/) for fully and working examples. 19 | -------------------------------------------------------------------------------- /src/bindings/generator/README.md: -------------------------------------------------------------------------------- 1 | # D-Bus API client generator 2 | 3 | The D-Bus API client generator uses the XML specification for D-Bus interfaces (see 4 | [DTD describing it](http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd)), extracts the contained information 5 | and passes a data dictionary to Jinja2 for rendering. 6 | 7 | ![structure](./img/structure.png) 8 | 9 | ## Usage 10 | 11 | First install the required packages via: 12 | 13 | ```bash 14 | pip install -r requirements.txt 15 | ``` 16 | 17 | Then the generator can be called with the following parameters: 18 | 19 | ```bash 20 | # data-dir: Directory containing the D-Bus API description (.xml) files 21 | # template-dir: Directory containing the Jinja2 templates 22 | # output-file-path: Path (incl. file name) for the output 23 | python generator.py 24 | ``` 25 | 26 | The `template-dir` needs to contain a `api.tmpl` file, which will be used by the generator as a "root file" - including 27 | all other templates if necessary. 28 | -------------------------------------------------------------------------------- /src/bindings/generator/img/structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-bluechi/bluechi/671aec61aac61727a5981a5cd16190456e4de5aa/src/bindings/generator/img/structure.png -------------------------------------------------------------------------------- /src/bindings/generator/requirements.txt: -------------------------------------------------------------------------------- 1 | Jinja2 >= 3.1.2 2 | dasbus >= 1.7 3 | -------------------------------------------------------------------------------- /src/bindings/generator/src/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | -------------------------------------------------------------------------------- /src/bindings/generator/test/test_dbus_typing.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | # 6 | # todo: write proper tests using those cases 7 | # if __name__ == "__main__": 8 | # # success cases 9 | # print(map_input_param_to_pytype("ss")) 10 | # print(map_input_param_to_pytype("ss(xi)")) 11 | # print(map_input_param_to_pytype("ssa{xi}")) 12 | # print(map_input_param_to_pytype("sas")) 13 | # print(map_input_param_to_pytype("(ss)")) 14 | # print(map_input_param_to_pytype("(ss(is)i)")) 15 | # print(map_input_param_to_pytype("(ss(i(ss)s)i)")) 16 | # print(map_input_param_to_pytype("(ssasi)")) 17 | # print(map_input_param_to_pytype("(ssa{xs}i)")) 18 | # print(map_input_param_to_pytype("(ssa{x(ss)}i)")) 19 | # print(map_input_param_to_pytype("a{ss}")) 20 | # print(map_input_param_to_pytype("a{sv}")) 21 | # print(map_input_param_to_pytype("a{sas}")) 22 | # print(map_input_param_to_pytype("a{sas}")) 23 | # print(map_input_param_to_pytype("a{sa{is}}")) 24 | # print(map_input_param_to_pytype("a{sa{ia{s(xxx)}}}")) 25 | # 26 | # # failure cases 27 | # 28 | -------------------------------------------------------------------------------- /src/bindings/python/README.md: -------------------------------------------------------------------------------- 1 | # BlueChi Python bindings 2 | 3 | The BlueChi Python bindings provides a Python module to interact with the D-Bus API of BlueChi. It consists of the 4 | following subpackages: 5 | 6 | - `api`: auto-generated code based the BlueChi D-BUS API description 7 | - `ext`: custom written code to simplify common tasks 8 | 9 | ## Installation 10 | 11 | Using `pip3`: 12 | 13 | ```sh 14 | # from PyPi 15 | pip3 install bluechi 16 | # or from cloned git repo 17 | pip3 install --force dist/bluechi--py3-none-any.whl 18 | ``` 19 | 20 | ## Examples 21 | 22 | Listing all connected nodes and their current state: 23 | 24 | ```python 25 | from bluechi.api import Controller 26 | 27 | for node in Controller().list_nodes(): 28 | # node[name, obj_path, status] 29 | print(f"Node: {node[0]}, State: {node[3]}") 30 | ``` 31 | 32 | Starting and stopping of a systemd unit on a specific node using the `Unit` class from the `ext` subpackage to 33 | implicitly wait for the job to finish: 34 | 35 | ```python 36 | from bluechi.ext import Unit 37 | 38 | hu = Unit("my-node-name") 39 | 40 | result = hu.start_unit("chronyd.service") 41 | print(result) 42 | 43 | result = hu.stop_unit("chronyd.service") 44 | print(result) 45 | ``` 46 | -------------------------------------------------------------------------------- /src/bindings/python/bluechi/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | -------------------------------------------------------------------------------- /src/bindings/python/requirements.txt: -------------------------------------------------------------------------------- 1 | dasbus>=1.7 2 | -------------------------------------------------------------------------------- /src/bindings/python/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description_file = README.md 3 | 4 | [flake8] 5 | max-line-length = 120 6 | exclude = venv, .venv 7 | ignore = F401 8 | 9 | [mypy] 10 | python_version = 3.9 11 | disallow_subclassing_any = True 12 | no_implicit_optional = True 13 | show_error_codes = True 14 | strict_equality = True 15 | warn_incomplete_stub = True 16 | warn_redundant_casts = True 17 | warn_unreachable = True 18 | warn_unused_configs = True 19 | warn_unused_ignores = True 20 | -------------------------------------------------------------------------------- /src/bindings/python/setup.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | from setuptools import setup, find_packages 6 | 7 | 8 | def readme(): 9 | with open("README.md") as desc: 10 | return desc.read() 11 | 12 | 13 | setup( 14 | name="bluechi", 15 | version="1.1.0", 16 | description="Python bindings for BlueChi's D-Bus API", 17 | long_description=readme(), 18 | long_description_content_type="text/markdown", 19 | author="BlueChi developers", 20 | url="https://github.com/eclipse-bluechi/bluechi/", 21 | license="LGPL-2.1-or-later", 22 | install_requires=[ 23 | "dasbus", 24 | ], 25 | packages=find_packages(), 26 | include_package_data=True, 27 | package_data={"bluechi": ["py.typed"]}, 28 | zip_safe=True, 29 | keywords=['bluechi', 'python', 'D-Bus', 'systemd'], 30 | classifiers=[ 31 | "Programming Language :: Python", 32 | "Programming Language :: Python :: 3", 33 | ], 34 | python_requires='>=3.9', 35 | ) 36 | -------------------------------------------------------------------------------- /src/bindings/python/setup.py.in: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | from setuptools import setup, find_packages 6 | 7 | 8 | def readme(): 9 | with open("README.md") as desc: 10 | return desc.read() 11 | 12 | 13 | setup( 14 | name="bluechi", 15 | version="@VERSION@", 16 | description="Python bindings for BlueChi's D-Bus API", 17 | long_description=readme(), 18 | long_description_content_type="text/markdown", 19 | author="BlueChi developers", 20 | url="https://github.com/eclipse-bluechi/bluechi/", 21 | license="LGPL-2.1-or-later", 22 | install_requires=[ 23 | "dasbus", 24 | ], 25 | packages=find_packages(), 26 | include_package_data=True, 27 | package_data={"bluechi": ["py.typed"]}, 28 | zip_safe=True, 29 | keywords=['bluechi', 'python', 'D-Bus', 'systemd'], 30 | classifiers=[ 31 | "Programming Language :: Python", 32 | "Programming Language :: Python :: 3", 33 | ], 34 | python_requires='>=3.9', 35 | ) 36 | -------------------------------------------------------------------------------- /src/bindings/python/templates/agent.tmpl: -------------------------------------------------------------------------------- 1 | 2 | class Agent(ApiBase): 3 | """ 4 | {{ iface_doc }} 5 | """ 6 | def __init__(self, bus: MessageBus = None, use_systembus=True) -> None: 7 | super().__init__(BC_AGENT_DBUS_INTERFACE, BC_OBJECT_PATH, bus, use_systembus) 8 | 9 | {%- include 'skeleton_method.tmpl' -%} 10 | {%- include 'skeleton_signal.tmpl' -%} 11 | {%- include 'skeleton_property.tmpl' %} 12 | -------------------------------------------------------------------------------- /src/bindings/python/templates/api.tmpl: -------------------------------------------------------------------------------- 1 | {% include 'license.tmpl' %} 2 | # 3 | # Generated file. DO NOT EDIT! 4 | # 5 | 6 | {% include 'block_imports.tmpl' %} 7 | 8 | {% include 'consts.tmpl' %} 9 | 10 | {% include 'apibase.tmpl' %} 11 | 12 | {% for interface in interfaces -%} 13 | {% with iface_doc=interface.inline_doc, methods=interface.methods, signals=interface.signals, properties=interface.properties %} 14 | {% include interface.name.lower() + ".tmpl" %} 15 | {% endwith %} 16 | {% endfor %} 17 | -------------------------------------------------------------------------------- /src/bindings/python/templates/block_imports.tmpl: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Callable, Tuple, Dict, List, Any 4 | from dasbus.typing import Bool, Double, Str, Int, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, ObjPath, Structure 5 | 6 | # File has been renamed to UnixFD in following PR included in v1.7 7 | # https://github.com/rhinstaller/dasbus/pull/70 8 | try: 9 | from dasbus.typing import File 10 | except ImportError: 11 | from dasbus.typing import UnixFD 12 | 13 | from dasbus.client.proxy import InterfaceProxy, ObjectProxy 14 | from dasbus.connection import MessageBus, SystemMessageBus, SessionMessageBus 15 | 16 | import gi 17 | gi.require_version("GLib", "2.0") 18 | from gi.repository.GLib import Variant # noqa: E402 19 | -------------------------------------------------------------------------------- /src/bindings/python/templates/consts.tmpl: -------------------------------------------------------------------------------- 1 | 2 | BC_DEFAULT_PORT = 842 3 | BC_DEFAULT_HOST = "127.0.0.1" 4 | 5 | BC_DBUS_INTERFACE = "org.eclipse.bluechi" 6 | BC_OBJECT_PATH = "/org/eclipse/bluechi" 7 | BC_AGENT_DBUS_INTERFACE = "org.eclipse.bluechi.Agent" 8 | BC_METRICS_OBJECT_PATH = "/org/eclipse/bluechi/metrics" 9 | 10 | DBUS_PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties" 11 | -------------------------------------------------------------------------------- /src/bindings/python/templates/controller.tmpl: -------------------------------------------------------------------------------- 1 | 2 | class Controller(ApiBase): 3 | """ 4 | {{ iface_doc }} 5 | """ 6 | 7 | def __init__(self, bus: MessageBus = None, use_systembus=True) -> None: 8 | super().__init__(BC_DBUS_INTERFACE, BC_OBJECT_PATH, bus, use_systembus) 9 | 10 | {% include 'skeleton_method.tmpl' %} 11 | {% include 'skeleton_signal.tmpl' %} 12 | {% include 'skeleton_property.tmpl' %} 13 | -------------------------------------------------------------------------------- /src/bindings/python/templates/job.tmpl: -------------------------------------------------------------------------------- 1 | 2 | class Job(ApiBase): 3 | """ 4 | {{ iface_doc }} 5 | """ 6 | 7 | def __init__(self, job_path: ObjPath, bus: MessageBus = None, use_systembus=True) -> None: 8 | super().__init__(BC_DBUS_INTERFACE, job_path, bus, use_systembus) 9 | 10 | self.job_path = job_path 11 | 12 | {%- include 'skeleton_method.tmpl' %} 13 | {%- include 'skeleton_signal.tmpl' %} 14 | {%- include 'skeleton_property.tmpl' %} 15 | -------------------------------------------------------------------------------- /src/bindings/python/templates/license.tmpl: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | -------------------------------------------------------------------------------- /src/bindings/python/templates/metrics.tmpl: -------------------------------------------------------------------------------- 1 | 2 | class Metrics(ApiBase): 3 | """ 4 | {{ iface_doc }} 5 | """ 6 | 7 | def __init__(self, bus: MessageBus = None, use_systembus=True) -> None: 8 | super().__init__(BC_DBUS_INTERFACE, BC_METRICS_OBJECT_PATH, bus, use_systembus) 9 | 10 | {%- include 'skeleton_method.tmpl' %} 11 | {%- include 'skeleton_signal.tmpl' %} 12 | {%- include 'skeleton_property.tmpl' %} 13 | -------------------------------------------------------------------------------- /src/bindings/python/templates/monitor.tmpl: -------------------------------------------------------------------------------- 1 | 2 | class Monitor(ApiBase): 3 | """ 4 | {{ iface_doc }} 5 | """ 6 | 7 | def __init__(self, monitor_path: ObjPath, bus: MessageBus = None, use_systembus=True) -> None: 8 | super().__init__(BC_DBUS_INTERFACE, monitor_path, bus, use_systembus) 9 | 10 | self.monitor_path = monitor_path 11 | 12 | {%- include 'skeleton_method.tmpl' %} 13 | {%- include 'skeleton_signal.tmpl' %} 14 | {%- include 'skeleton_property.tmpl' %} 15 | -------------------------------------------------------------------------------- /src/bindings/python/templates/node.tmpl: -------------------------------------------------------------------------------- 1 | 2 | class Node(ApiBase): 3 | """ 4 | {{ iface_doc }} 5 | """ 6 | 7 | def __init__(self, node_name: str, bus: MessageBus = None, use_systembus=True) -> None: 8 | # set empty node path temporary, needs to be resolved after the bus has been set 9 | super().__init__(BC_DBUS_INTERFACE, "", bus, use_systembus) 10 | 11 | controller = self.bus.get_proxy( 12 | BC_DBUS_INTERFACE, 13 | BC_OBJECT_PATH 14 | ) 15 | self.object_path = controller.GetNode(node_name) 16 | 17 | self.node_name = node_name 18 | 19 | {%- include 'skeleton_method.tmpl' %} 20 | {%- include 'skeleton_signal.tmpl' %} 21 | {%- include 'skeleton_property.tmpl' %} 22 | -------------------------------------------------------------------------------- /src/bindings/python/templates/skeleton_method.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% for method in methods -%} 4 | def {{ method.pyname }}(self 5 | {%- for arg in method.args -%} 6 | , {{ arg.name }} 7 | {%- if arg.pytype != "" -%} 8 | : {{ arg.pytype }} 9 | {%- endif -%} 10 | {%- endfor -%} 11 | ) -> {# comment to enforce whitespace #} 12 | {%- if method.rets|length <= 0 -%} 13 | None 14 | {%- elif method.rets|length == 1 -%} 15 | {{ method.rets[0].pytype }} 16 | {%- else -%} 17 | Tuple[ 18 | {%- for ret in method.rets -%} 19 | {{ ret.pytype }}, 20 | {%- endfor -%} 21 | ] 22 | {%- endif -%}: 23 | """ 24 | {{ method.inline_doc }} 25 | """ 26 | {% if method.rets|length > 0 -%} 27 | return {# comment to enforce whitespace #} 28 | {%- endif -%} 29 | self.get_proxy().{{ method.name }}( 30 | 31 | {%- for arg in method.args -%} 32 | {{ arg.name }}, 33 | {%- endfor -%} 34 | ) 35 | 36 | {% endfor %} 37 | -------------------------------------------------------------------------------- /src/bindings/python/templates/skeleton_property.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% for property in properties -%} 4 | {%- for access in property.access -%} 5 | {%- if access == "read" -%} 6 | @property 7 | def {{ property.pyname }}(self) -> {{ property.pytype }}: 8 | """ 9 | {{ property.inline_doc }} 10 | """ 11 | return self.get_proxy().{{ property.name }} 12 | {%- endif -%} 13 | {% endfor %} 14 | 15 | {% if property.emits_change %} 16 | def on_{{ property.pyname }}_changed(self, callback: Callable[[Variant], None]): 17 | """ 18 | {{ property.inline_doc }} 19 | """ 20 | 21 | def on_properties_changed(interface: str, changed_props: Dict[str, Variant], invalidated_props: Dict[str, Variant]) -> None: 22 | value = changed_props.get("{{ property.name }}") 23 | if value is not None: 24 | callback(value) 25 | 26 | self.get_properties_proxy().PropertiesChanged.connect(on_properties_changed) 27 | {{ name }} 28 | {% endif %} 29 | {% endfor %} 30 | -------------------------------------------------------------------------------- /src/bindings/python/templates/skeleton_signal.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% for signal in signals -%} 4 | def on_{{ signal.pyname }}(self, callback: Callable[[ 5 | {%- for arg in signal.args -%} 6 | {%- if arg.pytype != "" -%} 7 | {{ arg.pytype }}, {# comment to enforce whitespace #} 8 | {%- endif -%} 9 | {%- endfor -%} 10 | ], None]) -> None: 11 | """ 12 | {{ signal.inline_doc }} 13 | """ 14 | self.get_proxy().{{ signal.name }}.connect(callback) 15 | 16 | {% endfor %} 17 | -------------------------------------------------------------------------------- /src/client/client.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/bus/utils.h" 9 | #include "libbluechi/common/common.h" 10 | 11 | #include "types.h" 12 | 13 | struct Client { 14 | int ref_count; 15 | 16 | sd_bus *api_bus; 17 | char *object_path; 18 | 19 | char *pending_job_name; 20 | sd_bus_message *pending_job_result; 21 | }; 22 | 23 | Client *new_client(); 24 | void client_unref(Client *client); 25 | 26 | int client_open_sd_bus(Client *client); 27 | 28 | sd_bus_message *client_wait_for_job(Client *client, char *object_path); 29 | int match_job_removed_signal(sd_bus_message *m, void *userdata, sd_bus_error *error); 30 | 31 | DEFINE_CLEANUP_FUNC(Client, client_unref) 32 | #define _cleanup_client_ _cleanup_(client_unrefp) 33 | 34 | int client_create_message_new_method_call( 35 | Client *client, const char *node_name, const char *member, sd_bus_message **new_message); 36 | 37 | int client_start_event_loop(Client *client); 38 | -------------------------------------------------------------------------------- /src/client/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | # client build configuration 7 | 8 | client_src = [ 9 | 'main.c', 10 | 'client.c', 11 | 'method-help.c', 12 | 'method-is-enabled.c', 13 | 'method-loglevel.c', 14 | 'method-list-unit-files.c', 15 | 'method-list-units.c', 16 | 'method-metrics.c', 17 | 'method-monitor.c', 18 | 'method-unit-lifecycle.c', 19 | 'method-status.c', 20 | 'method-kill.c', 21 | 'method-freeze-thaw.c', 22 | 'method-enable-disable.c', 23 | 'method-reset-failed.c', 24 | 'method-daemon-reload.c', 25 | 'method-default-target.c', 26 | 'usage.c', 27 | ] 28 | 29 | executable( 30 | 'bluechictl', 31 | client_src, 32 | dependencies: [ 33 | systemd_dep, 34 | ], 35 | link_with: [ 36 | bluechi_lib, 37 | ], 38 | c_args: common_cflags, 39 | install: true, 40 | include_directories: include_directories('..') 41 | ) 42 | -------------------------------------------------------------------------------- /src/client/method-daemon-reload.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_daemon_reload(Command *command, void *userdata); 11 | void usage_method_daemon_reload(); 12 | -------------------------------------------------------------------------------- /src/client/method-default-target.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_get_default_target(Command *command, void *userdata); 11 | void usage_method_get_default_target(); 12 | int method_set_default_target(Command *command, void *userdata); 13 | void usage_method_set_default_target(); 14 | -------------------------------------------------------------------------------- /src/client/method-enable-disable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_enable(Command *command, void *userdata); 11 | void usage_method_enable(); 12 | 13 | int method_disable(Command *command, void *userdata); 14 | void usage_method_disable(); 15 | -------------------------------------------------------------------------------- /src/client/method-freeze-thaw.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_freeze(Command *command, void *userdata); 11 | void usage_method_freeze(); 12 | 13 | int method_thaw(Command *command, void *userdata); 14 | void usage_method_thaw(); 15 | -------------------------------------------------------------------------------- /src/client/method-help.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_help(Command *command, void *userdata); 11 | void usage_bluechi(); 12 | -------------------------------------------------------------------------------- /src/client/method-is-enabled.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include 9 | 10 | #include "libbluechi/cli/command.h" 11 | 12 | int method_is_enabled(Command *command, void *userdata); 13 | void usage_method_is_enabled(); 14 | -------------------------------------------------------------------------------- /src/client/method-kill.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_kill(Command *command, void *userdata); 11 | void usage_method_kill(); 12 | -------------------------------------------------------------------------------- /src/client/method-list-unit-files.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_list_unit_files(Command *command, void *userdata); 11 | void usage_method_list_unit_files(); 12 | -------------------------------------------------------------------------------- /src/client/method-list-units.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_list_units(Command *command, void *userdata); 11 | void usage_method_list_units(); 12 | -------------------------------------------------------------------------------- /src/client/method-loglevel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_set_loglevel(Command *command, void *userdata); 11 | void usage_method_set_loglevel(); 12 | -------------------------------------------------------------------------------- /src/client/method-metrics.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_metrics(Command *command, void *userdata); 11 | void usage_method_metrics(); 12 | -------------------------------------------------------------------------------- /src/client/method-monitor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include 9 | 10 | #include "libbluechi/cli/command.h" 11 | 12 | int method_monitor(Command *command, void *userdata); 13 | void usage_method_monitor(); 14 | -------------------------------------------------------------------------------- /src/client/method-reset-failed.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_reset_failed(Command *command, void *userdata); 11 | void usage_method_reset_failed(); 12 | -------------------------------------------------------------------------------- /src/client/method-status.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include 9 | 10 | #include "libbluechi/cli/command.h" 11 | 12 | int method_status(Command *command, void *userdata); 13 | void usage_method_status(); 14 | -------------------------------------------------------------------------------- /src/client/method-unit-lifecycle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_start(Command *command, void *userdata); 11 | int method_stop(Command *command, void *userdata); 12 | int method_restart(Command *command, void *userdata); 13 | int method_reload(Command *command, void *userdata); 14 | void usage_method_lifecycle(); 15 | -------------------------------------------------------------------------------- /src/client/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | typedef struct Client Client; 9 | typedef struct UnitList UnitList; 10 | typedef struct UnitFileList UnitFileList; 11 | -------------------------------------------------------------------------------- /src/client/usage.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #include 7 | 8 | void usage_print_header() { 9 | printf("bluechictl is a convenience CLI tool to interact with bluechi\n"); 10 | printf("\n"); 11 | } 12 | 13 | void usage_print_description(const char *description) { 14 | printf("Description: \n"); 15 | printf(" %s\n", description); 16 | printf("\n"); 17 | } 18 | 19 | void usage_print_usage(const char *usage) { 20 | printf("Usage: \n"); 21 | printf(" %s\n", usage); 22 | printf("\n"); 23 | } 24 | -------------------------------------------------------------------------------- /src/client/usage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | void usage_print_header(); 9 | void usage_print_description(const char *description); 10 | void usage_print_usage(const char *usage); 11 | -------------------------------------------------------------------------------- /src/controller/job.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/common/common.h" 9 | 10 | #include "types.h" 11 | 12 | struct Job { 13 | int ref_count; 14 | 15 | Node *node; /* weak ref */ 16 | 17 | JobState state; 18 | 19 | uint32_t id; 20 | char *object_path; 21 | char *type; 22 | char *unit; 23 | 24 | sd_bus_slot *export_slot; 25 | 26 | uint64_t job_start_micros; 27 | uint64_t job_end_micros; 28 | 29 | LIST_FIELDS(Job, jobs); 30 | }; 31 | 32 | 33 | Job *job_new(Node *node, const char *unit, const char *type); 34 | Job *job_ref(Job *job); 35 | void job_unref(Job *job); 36 | 37 | void job_set_state(Job *job, JobState state); 38 | 39 | bool job_export(Job *job); 40 | 41 | DEFINE_CLEANUP_FUNC(Job, job_unref) 42 | #define _cleanup_job_ _cleanup_(job_unrefp) 43 | -------------------------------------------------------------------------------- /src/controller/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | # controller build configuration 7 | 8 | ctrl_src = [ 9 | 'controller.h', 10 | 'controller.c', 11 | 'node.h', 12 | 'node.c', 13 | 'job.h', 14 | 'job.c', 15 | 'metrics.c', 16 | 'metrics.h', 17 | 'monitor.h', 18 | 'monitor.c', 19 | 'proxy_monitor.c', 20 | 'proxy_monitor.h', 21 | 'main.c', 22 | ] 23 | 24 | controller_deps = [ 25 | systemd_dep, 26 | inih_dep, 27 | hashmapc_dep, 28 | ] 29 | 30 | if with_selinux 31 | controller_deps += [ selinux_dep, ] 32 | endif 33 | 34 | executable( 35 | 'bluechi-controller', 36 | ctrl_src, 37 | dependencies: controller_deps, 38 | link_with: [ 39 | bluechi_lib, 40 | ], 41 | install: true, 42 | install_dir: join_paths(prefixdir, get_option('libexecdir')), 43 | c_args: common_cflags, 44 | include_directories: include_directories('..') 45 | ) 46 | 47 | # build test binaries 48 | subdir('test') 49 | -------------------------------------------------------------------------------- /src/controller/metrics.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include 9 | 10 | #include "types.h" 11 | 12 | int metrics_export(Controller *controller); 13 | bool metrics_node_signal_matching_register(Node *node); 14 | void metrics_produce_job_report(Job *job); 15 | -------------------------------------------------------------------------------- /src/controller/test/controller/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | controller_src = [ 7 | 'controller_apply_config_test', 8 | ] 9 | 10 | # setup controller test src files to include in compilation 11 | controller_test_src = [] 12 | foreach src : ctrl_src 13 | # skip main to avoid duplicate main function error 14 | if src == 'main.c' 15 | continue 16 | endif 17 | controller_test_src += '../../' + src 18 | endforeach 19 | 20 | foreach src : controller_src 21 | exec_test = executable(src, 22 | controller_test_src + [src + '.c'], 23 | dependencies: controller_deps, 24 | link_with: [ 25 | bluechi_lib, 26 | ], 27 | c_args: common_cflags, 28 | include_directories: include_directories('../../..'), 29 | ) 30 | test(src, exec_test) 31 | endforeach 32 | -------------------------------------------------------------------------------- /src/controller/test/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | subdir('controller') 7 | -------------------------------------------------------------------------------- /src/controller/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | typedef struct Controller Controller; 9 | typedef struct Node Node; 10 | typedef struct AgentRequest AgentRequest; 11 | typedef struct Job Job; 12 | typedef struct Monitor Monitor; 13 | typedef struct ProxyMonitor ProxyMonitor; 14 | typedef struct Subscription Subscription; 15 | typedef struct SubscribedUnit SubscribedUnit; 16 | typedef struct MonitorPeer MonitorPeer; 17 | typedef struct ProxyDependency ProxyDependency; 18 | typedef struct ProxyTarget ProxyTarget; 19 | -------------------------------------------------------------------------------- /src/is-online/help.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_help(Command *command, void *userdata); 11 | void usage(); 12 | -------------------------------------------------------------------------------- /src/is-online/is-online.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include "libbluechi/cli/command.h" 9 | 10 | int method_is_online_agent(Command *command, void *userdata); 11 | int method_is_online_node(Command *command, void *userdata); 12 | int method_is_online_system(Command *command, void *userdata); 13 | -------------------------------------------------------------------------------- /src/is-online/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | is_online_src = [ 7 | 'main.c', 8 | 'help.c', 9 | 'is-online.c', 10 | ] 11 | 12 | executable( 13 | 'bluechi-is-online', 14 | is_online_src, 15 | dependencies: [ 16 | systemd_dep, 17 | ], 18 | link_with: [ 19 | bluechi_lib, 20 | ], 21 | c_args: common_cflags, 22 | install: true, 23 | include_directories: include_directories('..') 24 | ) 25 | 26 | # build test binaries 27 | # subdir('test') 28 | -------------------------------------------------------------------------------- /src/is-online/opt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #define OPT_NONE 0u 9 | #define OPT_HELP 1u << 0u 10 | #define OPT_MONITOR 1u << 1u 11 | #define OPT_WAIT 1u << 2u 12 | #define OPT_SWITCH_CTRL_TIMEOUT 1u << 3u 13 | 14 | #define ARG_MONITOR "monitor" 15 | #define ARG_MONITOR_SHORT 1000 16 | 17 | #define ARG_WAIT "wait" 18 | #define ARG_WAIT_SHORT 1001 19 | 20 | #define ARG_SWITCH_CTRL_TIMEOUT "switch-timeout" 21 | #define ARG_SWITCH_CTRL_TIMEOUT_SHORT 1002 22 | -------------------------------------------------------------------------------- /src/libbluechi/bus/bus.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | sd_bus *peer_bus_open(sd_event *event, const char *dbus_description, const char *dbus_server_addr); 15 | int peer_bus_close(sd_bus *peer_dbus); 16 | sd_bus *peer_bus_open_server(sd_event *event, const char *dbus_description, const char *sender, int fd); 17 | sd_bus *system_bus_open(sd_event *event); 18 | sd_bus *systemd_bus_open(sd_event *event); 19 | sd_bus *user_bus_open(sd_event *event); 20 | 21 | int get_peer_ip_address(sd_bus *bus, char **ret_address, uint16_t *ret_port); 22 | -------------------------------------------------------------------------------- /src/libbluechi/common/event-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | // These functions are essentially copied from 12 | // systemd/src/libsystemd/sd-event/event-util.c. 13 | 14 | int event_reset_time_relative( 15 | sd_event *e, 16 | sd_event_source **s, 17 | clockid_t clock, 18 | uint64_t usec, 19 | uint64_t accuracy, 20 | sd_event_time_handler_t callback, 21 | void *userdata, 22 | int64_t priority, 23 | const char *description, 24 | bool force_reset); 25 | -------------------------------------------------------------------------------- /src/libbluechi/common/math-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #include "math-util.h" 7 | 8 | unsigned long umaxl(unsigned long x, unsigned long y) { 9 | if (x > y) { 10 | return x; 11 | } 12 | return y; 13 | } 14 | -------------------------------------------------------------------------------- /src/libbluechi/common/math-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | unsigned long umaxl(unsigned long x, unsigned long y); 9 | -------------------------------------------------------------------------------- /src/libbluechi/common/network.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "libbluechi/common/common.h" 17 | #include "libbluechi/log/log.h" 18 | 19 | bool is_ipv4(const char *domain); 20 | bool is_ipv6(const char *domain); 21 | 22 | char *get_hostname(); 23 | 24 | char *typesafe_inet_ntop4(const struct sockaddr_in *addr); 25 | char *typesafe_inet_ntop6(const struct sockaddr_in6 *addr); 26 | 27 | char *assemble_tcp_address(const struct sockaddr_in *addr); 28 | char *assemble_tcp_address_v6(const struct sockaddr_in6 *addr); 29 | 30 | typedef int (*getaddrinfo_func)( 31 | const char * restrict node, 32 | const char * restrict service, 33 | const struct addrinfo * restrict hints, 34 | struct addrinfo ** restrict res); 35 | int get_address(const char *domain, char **ip_address, getaddrinfo_func resolve_addr); 36 | -------------------------------------------------------------------------------- /src/libbluechi/common/parse-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | bool parse_long(const char *in, long *ret); 12 | bool parse_port(const char *in, uint16_t *ret); 13 | 14 | #define MIN_SIGNAL_VALUE 1 15 | #define MAX_SIGNAL_VALUE 31 16 | 17 | bool parse_linux_signal(const char *in, uint32_t *ret); 18 | char *parse_selinux_type(const char *context); 19 | -------------------------------------------------------------------------------- /src/libbluechi/common/time-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define USEC_INFINITY UINT64_MAX 13 | #define USEC_PER_SEC 1000000 14 | #define USEC_PER_MSEC 1000 15 | #define NSEC_PER_USEC 1000 16 | 17 | static const uint64_t sec_to_microsec_multiplier = 1000000; 18 | static const double microsec_to_millisec_multiplier = 1e-3; 19 | static const double nanosec_to_microsec_multiplier = 1e-3; 20 | static const double nanosec_to_millisec_multiplier = 1e-6; 21 | static const uint64_t millis_in_second = 1000; 22 | 23 | uint64_t get_time_micros(); 24 | uint64_t get_time_micros_monotonic(); 25 | uint64_t finalize_time_interval_micros(int64_t start_time_micros); 26 | double micros_to_millis(uint64_t time_micros); 27 | uint64_t timespec_to_micros(const struct timespec *ts); 28 | char *get_formatted_log_timestamp(); 29 | char *get_formatted_log_timestamp_for_timespec(struct timespec time, bool is_gmt); 30 | -------------------------------------------------------------------------------- /src/libbluechi/service/shutdown.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | typedef void (*ShutdownHookFn)(void *userdata); 12 | 13 | typedef struct ShutdownHook { 14 | ShutdownHookFn shutdown; 15 | void *userdata; 16 | } ShutdownHook; 17 | 18 | int shutdown_event_loop(sd_event *event_loop); 19 | int event_loop_add_shutdown_signals(sd_event *event, ShutdownHook *hook); 20 | -------------------------------------------------------------------------------- /src/libbluechi/socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | int create_tcp_socket(uint16_t port); 12 | int create_uds_socket(const char *path); 13 | int accept_connection_request(int fd); 14 | 15 | int fd_check_peercred(int fd); 16 | bool fd_is_socket_tcp(int fd); 17 | 18 | 19 | typedef struct SocketOptions SocketOptions; 20 | 21 | SocketOptions *socket_options_new(); 22 | int socket_options_set_tcp_keepidle(SocketOptions *opts, const char *keepidle_s); 23 | int socket_options_set_tcp_keepintvl(SocketOptions *opts, const char *keepintvl_s); 24 | int socket_options_set_tcp_keepcnt(SocketOptions *opts, const char *keepcnt_s); 25 | int socket_options_set_ip_recverr(SocketOptions *opts, bool recverr); 26 | 27 | int socket_set_options(int fd, SocketOptions *opts); 28 | -------------------------------------------------------------------------------- /src/libbluechi/test/bus/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | subdir('utils') 7 | -------------------------------------------------------------------------------- /src/libbluechi/test/bus/utils/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | bus_src = [ 7 | 'bus_id_is_valid_test', 8 | ] 9 | 10 | foreach src : bus_src 11 | exec_test = executable(src, src + '.c', 12 | link_with: [ 13 | bluechi_lib, 14 | ], 15 | include_directories: include_directories('../../../..'), 16 | ) 17 | test(src, exec_test) 18 | endforeach 19 | -------------------------------------------------------------------------------- /src/libbluechi/test/cli/command/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | command_src = [ 7 | 'command_add_option_test', 8 | 'command_flag_exists_test', 9 | 'command_get_option_test', 10 | 'command_get_option_long_test', 11 | 'get_option_type_test', 12 | 'command_execute_test', 13 | 'methods_get_method_test', 14 | ] 15 | 16 | foreach src : command_src 17 | exec_test = executable(src, src + '.c', 18 | link_with: [ 19 | bluechi_lib, 20 | ], 21 | include_directories: include_directories('../../../..'), 22 | ) 23 | test(src, exec_test) 24 | endforeach 25 | -------------------------------------------------------------------------------- /src/libbluechi/test/cli/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | subdir('command') 7 | -------------------------------------------------------------------------------- /src/libbluechi/test/common/cfg/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | cfg_src = [ 7 | 'cfg_def_conf_test', 8 | 'cfg_get_set_test', 9 | 'cfg_load_complete_configuration_test', 10 | 'cfg_load_from_env_test', 11 | 'cfg_load_from_file_test', 12 | ] 13 | 14 | foreach src : cfg_src 15 | exec_test = executable(src, src + '.c', 16 | link_with: [ 17 | bluechi_lib, 18 | ], 19 | include_directories: include_directories('../../../..'), 20 | ) 21 | test(src, exec_test) 22 | endforeach 23 | -------------------------------------------------------------------------------- /src/libbluechi/test/common/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | common_src = [ 7 | 'list_test', 8 | 'parse-util_test', 9 | 'time-util_test' 10 | ] 11 | 12 | foreach src : common_src 13 | exec_test = executable(src, src + '.c', 14 | link_with: [ 15 | bluechi_lib, 16 | ], 17 | include_directories: include_directories('../../..'), 18 | ) 19 | test(src, exec_test) 20 | endforeach 21 | 22 | subdir('cfg') 23 | subdir('network') 24 | subdir('string-util') 25 | subdir('time-util') 26 | -------------------------------------------------------------------------------- /src/libbluechi/test/common/network/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | network_src = [ 7 | 'is_ipv4_test', 8 | 'is_ipv6_test', 9 | 'get_address_test', 10 | 'assemble_tcp_address', 11 | ] 12 | 13 | foreach src : network_src 14 | exec_test = executable(src, src + '.c', 15 | link_with: [ 16 | bluechi_lib, 17 | ], 18 | include_directories: include_directories('../../../..'), 19 | ) 20 | test(src, exec_test) 21 | endforeach 22 | -------------------------------------------------------------------------------- /src/libbluechi/test/common/string-util/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | string_util_src = [ 7 | 'string_builder_test', 8 | 'match_glob_test', 9 | 'ends_with_test', 10 | ] 11 | 12 | foreach src : string_util_src 13 | exec_test = executable(src, src + '.c', 14 | link_with: [ 15 | bluechi_lib, 16 | ], 17 | include_directories: include_directories('../../../..'), 18 | ) 19 | test(src, exec_test) 20 | endforeach 21 | -------------------------------------------------------------------------------- /src/libbluechi/test/common/time-util/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | network_src = [ 7 | 'get_log_timestamp', 8 | 'micros_to_millis_test', 9 | 'timespec_to_micros_test', 10 | ] 11 | 12 | foreach src : network_src 13 | exec_test = executable(src, src + '.c', 14 | link_with: [ 15 | bluechi_lib, 16 | ], 17 | include_directories: include_directories('../../../..'), 18 | ) 19 | test(src, exec_test) 20 | endforeach 21 | -------------------------------------------------------------------------------- /src/libbluechi/test/common/time-util/micros_to_millis_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Contributors to the Eclipse BlueChi project 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | #include 7 | #include 8 | 9 | #include "libbluechi/common/time-util.h" 10 | 11 | 12 | int main() { 13 | assert(micros_to_millis(0) == 0); 14 | assert(micros_to_millis(12) == 0.012); 15 | assert(micros_to_millis(UINT64_MAX) == 18446744073709552); 16 | return EXIT_SUCCESS; 17 | } 18 | -------------------------------------------------------------------------------- /src/libbluechi/test/log/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | common_src = [ 7 | 'bc_log_init_test', 8 | 'bc_log_to_stderr_full_test', 9 | 'bc_log_to_stderr_test', 10 | 'log_level_to_string_test', 11 | 'log_target_to_str_test', 12 | 'string_to_log_level_test', 13 | ] 14 | 15 | foreach src : common_src 16 | exec_test = executable(src, src + '.c', 17 | link_with: [ 18 | bluechi_lib, 19 | ], 20 | include_directories: include_directories('../../..'), 21 | ) 22 | test(src, exec_test) 23 | endforeach 24 | -------------------------------------------------------------------------------- /src/libbluechi/test/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | subdir('bus') 7 | subdir('cli') 8 | subdir('common') 9 | subdir('log') 10 | subdir('socket') 11 | -------------------------------------------------------------------------------- /src/libbluechi/test/socket/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | socket_src = [ 7 | 'socket_option_test', 8 | 'socket_set_options_test', 9 | ] 10 | 11 | foreach src : socket_src 12 | exec_test = executable(src, src + '.c', 13 | link_with: [ 14 | bluechi_lib, 15 | ], 16 | include_directories: include_directories('../../..'), 17 | ) 18 | test(src, exec_test) 19 | endforeach 20 | -------------------------------------------------------------------------------- /src/proxy/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | # proxy build configuration 7 | 8 | proxy_src = [ 9 | 'main.c', 10 | ] 11 | 12 | executable( 13 | 'bluechi-proxy', 14 | proxy_src, 15 | dependencies: [ 16 | systemd_dep, 17 | ], 18 | link_with: [ 19 | bluechi_lib, 20 | ], 21 | c_args: common_cflags, 22 | include_directories: include_directories('..'), 23 | install: true, 24 | install_dir: join_paths(prefixdir, get_option('libexecdir')) 25 | ) 26 | -------------------------------------------------------------------------------- /systemd-units/bluechi-agent-user.service: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # 3 | # This file is part of bluechi-agent. 4 | # 5 | [Unit] 6 | Description=BlueChi systemd service controller agent daemon 7 | Documentation=man:bluechi-agent(1) man:bluechi-agent.conf(5) 8 | After=network.target 9 | 10 | [Service] 11 | Type=simple 12 | ExecStart=/usr/libexec/bluechi-agent --user 13 | -------------------------------------------------------------------------------- /systemd-units/bluechi-agent.service: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # 3 | # This file is part of bluechi-agent. 4 | # 5 | [Unit] 6 | Description=BlueChi systemd service controller agent daemon 7 | Documentation=man:bluechi-agent(1) man:bluechi-agent.conf(5) 8 | After=network.target 9 | 10 | [Service] 11 | Type=simple 12 | ExecStart=/usr/libexec/bluechi-agent 13 | Restart=on-failure 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /systemd-units/bluechi-controller.service: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # 3 | # This file is part of bluechi. 4 | # 5 | [Unit] 6 | Description=BlueChi Controller systemd service 7 | Documentation=man:bluechi-controller(1) man:bluechi-controller.conf(5) 8 | After=network.target 9 | 10 | [Service] 11 | Type=simple 12 | ExecStart=/usr/libexec/bluechi-controller 13 | Restart=on-failure 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /systemd-units/bluechi-controller.socket.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=BlueChi Controller Socket 3 | Documentation=man:bluechi-controller(1) 4 | 5 | [Socket] 6 | ListenStream=@unix_domain_socket_path@ 7 | SocketMode=0666 8 | 9 | [Install] 10 | WantedBy=sockets.target 11 | -------------------------------------------------------------------------------- /systemd-units/bluechi-dep@.service: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # 3 | # This file is part of bluechi-agent. 4 | # 5 | [Unit] 6 | Description=BlueChi proxy dependency service 7 | Documentation=man:bluechi-proxy(1) 8 | BindsTo=%i.service 9 | After=%i.service 10 | 11 | [Service] 12 | Type=oneshot 13 | 14 | # Use of ExecStop= here instead of ExecStart= since there is a 15 | # potential race condition for ExecStart= that results in the 16 | # bluechi-dep@.service to transition in a failed state. 17 | # This can happen when the target service transitioned to a failed 18 | # state and the command in ExecStart= is still running. Then 19 | # systemd will send a SIGTERM, failing the dep service as well. 20 | ExecStop=true 21 | RemainAfterExit=yes 22 | -------------------------------------------------------------------------------- /systemd-units/bluechi-proxy-user@.service: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # 3 | # This file is part of bluechi-agent. 4 | # 5 | [Unit] 6 | Description=BlueChi proxy service 7 | Documentation=man:bluechi-proxy(1) 8 | StopWhenUnneeded=yes 9 | 10 | [Service] 11 | ExecStart=/usr/libexec/bluechi-proxy --user create %i.service 12 | ExecStop=/usr/libexec/bluechi-proxy --user remove %i.service 13 | RemainAfterExit=yes 14 | Type=oneshot 15 | KillMode=mixed 16 | -------------------------------------------------------------------------------- /systemd-units/bluechi-proxy@.service: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # 3 | # This file is part of bluechi-agent. 4 | # 5 | [Unit] 6 | Description=BlueChi proxy service 7 | Documentation=man:bluechi-proxy(1) 8 | StopWhenUnneeded=yes 9 | 10 | [Service] 11 | ExecStart=/usr/libexec/bluechi-proxy create %i.service 12 | ExecStop=/usr/libexec/bluechi-proxy remove %i.service 13 | RemainAfterExit=yes 14 | Type=oneshot 15 | KillMode=mixed 16 | 17 | # Accept SIGTERM as successful exit status since there is a 18 | # potential race condition for ExecStart= when a stop signal 19 | # is sent and the ExecStart= command is still running. This 20 | # leads systemd to send a SIGTERM to the bluechi-proxy@.service. 21 | # This is acceptable and should not result the service transitioning 22 | # into a failed state. 23 | SuccessExitStatus=SIGTERM 24 | -------------------------------------------------------------------------------- /tests/.fmf/version: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /tests/bluechi_test/constants.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | NODE_CTRL_NAME = "node-ctrl" 7 | -------------------------------------------------------------------------------- /tests/bluechi_test/container_scripts/cmd-on-port.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | # The script takes only one parameter, which should be the port number 7 | if [ -z "$1" ]; then 8 | exit 1 9 | fi 10 | 11 | PID="$(lsof -i:$1 -t)" 12 | 13 | if [ -z "$PID" ]; then 14 | # No process listens on the specified port 15 | exit 2 16 | fi 17 | 18 | # Return the full command line of the process listening on the specified port/protocol 19 | ps -hww -o args -p ${PID} 20 | -------------------------------------------------------------------------------- /tests/bluechi_test/container_scripts/create_monitor.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import sys 7 | 8 | from dasbus.loop import EventLoop 9 | 10 | from bluechi.api import Controller, Monitor 11 | 12 | if len(sys.argv) != 3: 13 | print("Usage: python create_monitor.py ") 14 | exit(1) 15 | 16 | node = sys.argv[1] 17 | service = sys.argv[2] 18 | 19 | loop = EventLoop() 20 | mgr = Controller() 21 | monitor_path = mgr.create_monitor() 22 | monitor = Monitor(monitor_path) 23 | monitor.subscribe(node, service) 24 | 25 | print(monitor_path, flush=True) 26 | 27 | loop.run() 28 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | pytest_plugins = ["bluechi_test.fixtures"] 7 | -------------------------------------------------------------------------------- /tests/containers/integration-test-local: -------------------------------------------------------------------------------- 1 | FROM quay.io/bluechi/integration-test-base:latest 2 | 3 | RUN mkdir -p /tmp/bluechi-rpms 4 | 5 | COPY ./bluechi-rpms /tmp/bluechi-rpms 6 | 7 | RUN dnf install --repo bluechi-rpms \ 8 | --repofrompath bluechi-rpms,file:///tmp/bluechi-rpms/ \ 9 | --nogpgcheck \ 10 | --nodocs \ 11 | bluechi-controller \ 12 | bluechi-controller-debuginfo \ 13 | bluechi-agent \ 14 | bluechi-agent-debuginfo \ 15 | bluechi-ctl \ 16 | bluechi-is-online \ 17 | bluechi-ctl-debuginfo \ 18 | bluechi-selinux \ 19 | python3-bluechi \ 20 | -y 21 | 22 | RUN dnf -y clean all 23 | 24 | CMD [ "/sbin/init" ] 25 | -------------------------------------------------------------------------------- /tests/containers/integration-test-snapshot: -------------------------------------------------------------------------------- 1 | FROM quay.io/bluechi/integration-test-base:latest 2 | 3 | ARG copr_repo 4 | 5 | RUN dnf install -y dnf-plugin-config-manager 6 | 7 | RUN dnf copr enable -y $copr_repo 8 | 9 | RUN dnf install \ 10 | --nogpgcheck \ 11 | --nodocs \ 12 | bluechi-controller \ 13 | bluechi-controller-debuginfo \ 14 | bluechi-agent \ 15 | bluechi-agent-debuginfo \ 16 | bluechi-ctl \ 17 | bluechi-is-online \ 18 | bluechi-ctl-debuginfo \ 19 | bluechi-selinux \ 20 | python3-bluechi \ 21 | -y 22 | 23 | RUN dnf -y clean all 24 | 25 | CMD [ "/sbin/init" ] 26 | -------------------------------------------------------------------------------- /tests/plans/container.fmf: -------------------------------------------------------------------------------- 1 | summary: Running Integration Tests with containers 2 | discover: 3 | how: fmf 4 | filter: tier:0 5 | provision: 6 | how: local 7 | environment: 8 | BLUECHI_CTRL_HOST_PORT: 8420 9 | BLUECHI_CTRL_SVC_PORT: 8420 10 | BLUECHI_IMAGE_NAME: bluechi-image 11 | CONTAINER_USED: integration-test-snapshot 12 | INSTALL_DEPS: no 13 | LOG_LEVEL: INFO 14 | WITH_COVERAGE: 0 15 | WITH_VALGRIND: 0 16 | prepare: 17 | - name: Prepare containers setup 18 | how: shell 19 | script: | 20 | ./scripts/tests-setup.sh setup_container_test 21 | execute: 22 | how: tmt 23 | report: 24 | how: junit 25 | finish: 26 | - name: Create coverage report 27 | how: shell 28 | script: | 29 | pytest -svv \ 30 | --confcutdir . \ 31 | --log-cli-level=${LOG_LEVEL} \ 32 | --log-cli-date-format="%Y-%m-%d %H:%M:%S%z" \ 33 | --log-cli-format="%(asctime)s,%(msecs)03d %(levelname)-7s [%(name)s] %(message)s (%(module)s:%(lineno)d)" \ 34 | scripts/create_coverage_report.py 35 | -------------------------------------------------------------------------------- /tests/plans/multihost.fmf: -------------------------------------------------------------------------------- 1 | summary: Running Integration Tests with multiple hosts 2 | provision: 3 | - name: test-executor 4 | role: executor 5 | - name: bluechi-controller 6 | role: controller 7 | - name: bluechi-agent-1 8 | role: agent 9 | - name: bluechi-agent-2 10 | role: agent 11 | environment: 12 | BLUECHI_CTRL_SVC_PORT: 8420 13 | 14 | INSTALL_EXECUTOR_DEPS: yes 15 | INSTALL_WORKER_DEPS: yes 16 | 17 | SETUP_SSH: yes 18 | SSH_USER: root 19 | SSH_PASSWORD: root 20 | 21 | LOG_LEVEL: DEBUG 22 | WITH_COVERAGE: 0 23 | WITH_VALGRIND: 0 24 | discover: 25 | how: fmf 26 | filter: tag:multihost 27 | where: executor 28 | prepare: 29 | - name: Prepare executor setup 30 | how: shell 31 | script: | 32 | ./scripts/tests-setup.sh setup_multihost_test setup_executor 33 | where: executor 34 | - name: Prepare worker setup 35 | how: shell 36 | script: | 37 | ./scripts/tests-setup.sh setup_multihost_test setup_worker 38 | where: 39 | - controller 40 | - agent 41 | execute: 42 | how: tmt 43 | report: 44 | how: junit 45 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | flake8 >= 6.0.0 2 | junit-xml >= 1.9 3 | pytest >= 7.3.1 4 | podman >= 4.5.0 5 | strato-skipper >= 2.0.2 6 | tmt == 1.46 7 | paramiko >= 3.5.0 8 | -------------------------------------------------------------------------------- /tests/scripts/gather-code-coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | 8 | # First parameter is the name of the generated info file 9 | INFO_FILE=${1:-coverage.info} 10 | 11 | source $(dirname "$(readlink -f "$0")")/setup-src-dir-for-coverage.sh 12 | 13 | # Move each .gcda file into the respective project directory containing the .gcno 14 | for file in ${GCDA_DIR}/*.gcda ; do 15 | # Remove encoded directories up to src 16 | tmp_f="src${file##*src}" 17 | # Convert encoded directory to proper path 18 | tmp_f="${tmp_f//\#/\/}" 19 | mv -v $file ${GCDA_DIR}/${tmp_f} 20 | done 21 | 22 | # Generate info file 23 | geninfo ${GCDA_DIR} -b ${GCDA_DIR}/src -o ${INFO_FILE} 24 | -------------------------------------------------------------------------------- /tests/scripts/setup-src-dir-for-coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | # 3 | # Copyright Contributors to the Eclipse BlueChi project 4 | # 5 | # SPDX-License-Identifier: LGPL-2.1-or-later 6 | 7 | GCNO_DIR="/usr/share/bluechi-coverage" 8 | GCDA_DIR="/var/tmp/bluechi-coverage" 9 | 10 | BC_VRA="$(rpm -q --qf '%{VERSION}-%{RELEASE}.%{ARCH}' bluechi-agent 2>/dev/null)" 11 | SRC_DIR="/usr/src/debug/bluechi-${BC_VRA}" 12 | 13 | # Copy .gcno files to code coverage temporary directory 14 | cp -r ${GCNO_DIR}/. ${GCDA_DIR} 15 | 16 | # Copy source files from bluechi-debugsource package into GCDA_DIR, because unit test source files are not included 17 | # in debugsource package, so we needed to add them to bluechi-coverage package 18 | ( cd $SRC_DIR ; cp -r src ${GCDA_DIR} ) 19 | -------------------------------------------------------------------------------- /tests/tests/main.fmf: -------------------------------------------------------------------------------- 1 | component: bluechi 2 | tag: [multihost, testing-farm-container] 3 | test: | 4 | pytest -svv \ 5 | --confcutdir=../../../ \ 6 | --log-cli-level=${LOG_LEVEL} \ 7 | --log-cli-date-format="%Y-%m-%d %H:%M:%S%z" \ 8 | --log-cli-format="%(asctime)s,%(msecs)03d %(levelname)-7s [%(name)s] %(message)s (%(module)s:%(lineno)d)" 9 | 10 | # Require the whole tree (no pruning) 11 | require: 12 | - type: file 13 | pattern: 14 | - / 15 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-cmd-line-c-invalid-config/config-files/invalid.conf: -------------------------------------------------------------------------------- 1 | [bluechi-agent] 2 | ControllerPort8420 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-cmd-line-c-invalid-config/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test agent cmd -c option with invalid config file 2 | id: ff35f056-c1d4-449e-92c4-42c9c719d5db 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-cmd-options/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test agent cmd options 2 | id: b9156608-631b-492c-9c3c-520ba715ea28 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-cmd-options/python/is_node_connected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Node 9 | 10 | 11 | class TestNodeIsConnected(unittest.TestCase): 12 | def test_node_is_connected(self): 13 | n = Node("node-foo") 14 | assert n.status == "online" 15 | 16 | 17 | if __name__ == "__main__": 18 | unittest.main() 19 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-cmd-options/python/verify_heartbeat.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import time 7 | import unittest 8 | 9 | from bluechi.api import Node 10 | 11 | 12 | class TestNodeHeartbeat(unittest.TestCase): 13 | def test_node_heartbeat(self): 14 | n = Node("node-foo") 15 | assert n.status == "online" 16 | 17 | # verify that heartbeat occurs at least once in 2 seconds 18 | # since last_seen_timestamp is epoch, i.e. in seconds value 19 | # we check every 2 seconds twice to be sure 20 | timestamp1 = n.last_seen_timestamp 21 | time.sleep(2) 22 | timestamp2 = n.last_seen_timestamp 23 | time.sleep(2) 24 | timestamp3 = n.last_seen_timestamp 25 | print(f"timestamp1={timestamp1}") 26 | print(f"timestamp2={timestamp2}") 27 | print(f"timestamp3={timestamp3}") 28 | assert timestamp2 > timestamp1 29 | assert timestamp3 > timestamp2 30 | 31 | 32 | if __name__ == "__main__": 33 | unittest.main() 34 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-connect-via-controller-address/config/Invalid-ControllerAddress.conf: -------------------------------------------------------------------------------- 1 | [bluechi-agent] 2 | ControllerAddress=tcp:host=127.0.0.1,port=80000 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-connect-via-controller-address/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi-agent connects with ControllerAddress option 2 | id: 96aa0e17-5e23-4cc3-bc34-88368b8cc07b 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-get-logtarget/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test get logtarget from agent 2 | id: 8ba6d729-ccb6-43b8-ab00-95975d93c9a7 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-get-logtarget/python/agent_has_logtarget.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Agent 9 | 10 | expected_logtarget = "stderr-full" 11 | 12 | 13 | class TestHasLogTarget(unittest.TestCase): 14 | def test_agent_has_logtarget(self): 15 | agent = Agent() 16 | assert agent.log_target == expected_logtarget 17 | 18 | 19 | if __name__ == "__main__": 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-invalid-port-configuration/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi agent can handle invalid port in the configuration file 2 | id: 5645dcdf-acaa-4a04-8c0d-d478c8a6f2a3 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-logisquiet/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi agent can handle different types of values for LogIsQuiet 2 | in the configuration 3 | tag: 4 | - testing-farm-container 5 | id: 18da5e2a-6c79-490d-99dc-166df3307c2c 6 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-loglevel/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi agent can handle different types of values for LogLevel in the configuration 2 | id: f3dda8c1-ceb7-446c-9d65-2aa8ca798099 3 | tag: [testing-farm-container] 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-logtarget/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi agent can handle different types of values for LogTarget in the configuration 2 | id: 5cf92c54-e073-475c-970f-b8e090ec4da2 3 | tag: [testing-farm-container] 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-resolve-fqdn/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a local bluechi-agent on the same node as the controller can connect via the localhost name 2 | id: 48a9f92e-19f4-4f1b-ae34-a0d05f8ed16e 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-set-loglevel-invalid/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test setting an invalid log level on agent is rejected and doesn't cause disconnect 2 | id: 19fe3317-f153-4810-8ffc-cdc16a4d3527 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-set-loglevel-invalid/test_bluechi_agent_set_loglevel_invalid.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | from typing import Dict 6 | 7 | from bluechi_test.config import BluechiAgentConfig, BluechiControllerConfig 8 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 9 | from bluechi_test.test import BluechiTest 10 | 11 | NODE_FOO = "node-foo" 12 | 13 | 14 | def exec(ctrl: BluechiControllerMachine, _: Dict[str, BluechiAgentMachine]): 15 | 16 | _, output = ctrl.bluechictl.set_log_level_on_node( 17 | NODE_FOO, "INF", check_result=False 18 | ) 19 | print(output) 20 | assert b"Disconnect" not in output 21 | 22 | 23 | def test_bluechi_agent_set_loglevel_invalid( 24 | bluechi_test: BluechiTest, 25 | bluechi_ctrl_default_config: BluechiControllerConfig, 26 | bluechi_node_default_config: BluechiAgentConfig, 27 | ): 28 | 29 | bluechi_node_default_config.node_name = NODE_FOO 30 | bluechi_ctrl_default_config.allowed_node_names = [NODE_FOO] 31 | 32 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 33 | bluechi_test.add_bluechi_agent_config(bluechi_node_default_config) 34 | 35 | bluechi_test.run(exec) 36 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-set-loglevel/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test setting log level for agent 2 | id: abd22012-dc0c-4230-b623-2fe76fa67f76 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-started-and-connected/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi-agent on node foo started successfully and is connected to bluechi controller 2 | id: 15f5ced1-dcb4-4575-b649-1b12152c7fe7 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-switch-controller/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the agent switches the controller successfully 2 | id: e07b7169-cf69-4e58-a50a-2fbc66db99f3 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-switch-controller/python/switch_controller.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from dasbus.loop import EventLoop 9 | from dasbus.typing import Variant 10 | 11 | from bluechi.api import Agent 12 | 13 | 14 | class TestSwitchController(unittest.TestCase): 15 | def setUp(self) -> None: 16 | super().setUp() 17 | 18 | self.controller_address = None 19 | 20 | def test_switch_controller(self): 21 | loop = EventLoop() 22 | 23 | def on_controller_address_change(controller_address: Variant): 24 | self.controller_address = controller_address.get_string() 25 | loop.quit() 26 | 27 | agent = Agent() 28 | agent.on_controller_address_changed(on_controller_address_change) 29 | agent.switch_controller("tcp:host=127.0.0.1,port=8420") 30 | 31 | loop.run() 32 | 33 | assert agent.controller_address == "tcp:host=127.0.0.1,port=8420" 34 | assert self.controller_address == "tcp:host=127.0.0.1,port=8420" 35 | 36 | 37 | if __name__ == "__main__": 38 | unittest.main() 39 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-user-bus/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test agent connecting to user bus 2 | id: 6886e7c8-7548-4cf7-8dd4-d2d46b125fd3 3 | enabled: false 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-agent-user-bus/python/start_agent_as_user.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import time 7 | import unittest 8 | 9 | from bluechi_machine_lib.util import run_command 10 | 11 | service = "org.eclipse.bluechi.Agent" 12 | object = "/org/eclipse/bluechi" 13 | interface = "org.eclipse.bluechi.Agent" 14 | 15 | 16 | class TestAgentStartAsUser(unittest.TestCase): 17 | 18 | def test_agent_start_as_user(self): 19 | result, _, _ = run_command("systemctl --user start bluechi-agent") 20 | assert result == 0 21 | 22 | while True: 23 | result, output, _ = run_command( 24 | f"busctl --user get-property {service} {object} {interface} Status" 25 | ) 26 | if output == 's "offline"': 27 | break 28 | time.sleep(0.5) 29 | 30 | result, _, _ = run_command("systemctl --user stop bluechi-agent") 31 | assert result == 0 32 | 33 | 34 | if __name__ == "__main__": 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-and-agent-on-same-machine/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a bluechi-agent can run alongside bluechi controller on the same machine 2 | id: d5f4a7d4-7019-423a-9ad6-2d7d3ecb7512 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-and-agent-on-same-machine/python/is_node_connected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import os 7 | import unittest 8 | 9 | from bluechi.api import Node 10 | 11 | NODE_CTRL_NAME = os.getenv("NODE_CTRL_NAME", "node-ctrl") 12 | 13 | 14 | class TestNodeIsConnected(unittest.TestCase): 15 | def test_node_is_connected(self): 16 | n = Node(NODE_CTRL_NAME) 17 | assert n.status == "online" 18 | assert n.name == NODE_CTRL_NAME 19 | 20 | 21 | if __name__ == "__main__": 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-and-agent-on-same-machine/test_bluechi_and_agent_on_same_machine.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import os 7 | from typing import Dict 8 | 9 | from bluechi_test.config import BluechiControllerConfig 10 | from bluechi_test.constants import NODE_CTRL_NAME 11 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 12 | from bluechi_test.test import BluechiTest 13 | 14 | 15 | def exec(ctrl: BluechiControllerMachine, nodes: Dict[str, BluechiAgentMachine]): 16 | 17 | assert ctrl.wait_for_unit_state_to_be("bluechi-controller", "active") 18 | # local bluechi-agent is running, check if it is connected 19 | os.environ["NODE_CTRL_NAME"] = NODE_CTRL_NAME 20 | result, output = ctrl.run_python(os.path.join("python", "is_node_connected.py")) 21 | if result != 0: 22 | raise Exception(output) 23 | 24 | 25 | def test_bluechi_and_agent_on_same_machine( 26 | bluechi_test: BluechiTest, bluechi_ctrl_default_config: BluechiControllerConfig 27 | ): 28 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 29 | bluechi_test.run(exec) 30 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-anonymous-node/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a node with name not in the allowed list is rejected and can not connect 2 | id: 254b1fa2-7c9f-481c-85ac-c6e42c0226c8 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-anonymous-node/python/node_foo_not_connected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Controller 9 | 10 | 11 | class TestNodeFooNotConnected(unittest.TestCase): 12 | def test_node_foo_not_connected(self): 13 | mgr = Controller() 14 | 15 | nodes = mgr.list_nodes() 16 | assert len(nodes) == 1 17 | assert nodes[0][0] == "everyone-but-foo" 18 | assert nodes[0][2] == "offline" 19 | assert nodes[0][3] == "" 20 | 21 | 22 | if __name__ == "__main__": 23 | unittest.main() 24 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-change-port-with-c-cmd-option/config-files/agent_port_8421.conf: -------------------------------------------------------------------------------- 1 | [bluechi-agent] 2 | ControllerPort=8421 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-change-port-with-c-cmd-option/config-files/ctrl_port_8421.conf: -------------------------------------------------------------------------------- 1 | [bluechi-controller] 2 | ControllerPort=8421 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-change-port-with-c-cmd-option/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi agent/controller accepts changing port using a custom configuration 2 | file passed by command line option -c. 3 | id: c7b861a7-5b2f-4627-b450-9b7c8b9552af 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-change-port-with-c-cmd-option/python/is_node_connected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Node 9 | 10 | 11 | class TestNodeIsConnected(unittest.TestCase): 12 | def test_node_is_connected(self): 13 | n = Node("node-foo") 14 | assert n.status == "online" 15 | assert n.name == "node-foo" 16 | 17 | 18 | if __name__ == "__main__": 19 | unittest.main() 20 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-change-port-with-p-cmd-option/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi agent/controller accepts changing port by passing command 2 | line argument `-p`/`--port` 3 | id: 01e3fd62-51b7-46e9-9db4-cc3f9c4008ee 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-change-port-with-p-cmd-option/python/is_node_connected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Node 9 | 10 | 11 | class TestNodeIsConnected(unittest.TestCase): 12 | 13 | def test_node_is_connected(self): 14 | n = Node("node-foo") 15 | assert n.status == "online" 16 | 17 | 18 | if __name__ == "__main__": 19 | unittest.main() 20 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-cmd-line-c-invalid-config/config-files/invalid.conf: -------------------------------------------------------------------------------- 1 | [bluechi-controller] 2 | ControllerPort8420 -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-cmd-line-c-invalid-config/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test controller cmd -c option with invalid config file 2 | id: 51549ef2-0e3f-4bfc-bbbf-b4ff9c0c2505 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-disable-tcp-enable-uds/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test that bluechi-controller will add only connection handler for Unix Domain 2 | Socket and disables TCP handler 3 | id: 4ebe60af-8eb7-4bb8-b95f-c6810369efb7 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-disable-tcp/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test disabling TCP for bluechi-controller so no connection requests are accepted 2 | id: 234b0af5-9e78-4119-8023-5598eb91100b 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-disable-tcp/python/is_node_connected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import time 7 | import unittest 8 | 9 | from bluechi_machine_lib.util import Timeout 10 | 11 | from bluechi.api import Node 12 | 13 | NODE_NAME = "node-foo" 14 | 15 | 16 | class TestNodeIsConnected(unittest.TestCase): 17 | def test_node_is_connected(self): 18 | n = Node(NODE_NAME) 19 | 20 | with Timeout(5, f"Timeout while waiting for agent '{NODE_NAME}' to be online"): 21 | while n.status != "online": 22 | time.sleep(0.5) 23 | 24 | 25 | if __name__ == "__main__": 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-get-logtarget/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test get logtarget from controller 2 | id: e0b5b0de-829d-4031-a436-6e99ed983065 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-get-logtarget/python/controller_has_logtarget.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Controller 9 | 10 | expected_logtarget = "stderr-full" 11 | 12 | 13 | class TestHasLogTarget(unittest.TestCase): 14 | def test_controller_has_logtarget(self): 15 | controller = Controller() 16 | assert controller.log_target == expected_logtarget 17 | 18 | 19 | if __name__ == "__main__": 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-get-logtarget/test_bluechi_agent_get_logtarget.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import os 7 | from typing import Dict 8 | 9 | from bluechi_test.config import BluechiControllerConfig 10 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 11 | from bluechi_test.test import BluechiTest 12 | 13 | expected_logtarget = "stderr-full" 14 | 15 | 16 | def exec(ctrl: BluechiControllerMachine, nodes: Dict[str, BluechiAgentMachine]): 17 | result, output = ctrl.run_python( 18 | os.path.join("python", "controller_has_logtarget.py") 19 | ) 20 | if result != 0: 21 | raise Exception( 22 | f"Controller did not have expected log target '{expected_logtarget}: {output}" 23 | ) 24 | 25 | 26 | def test_bluechi_agent_get_logtarget( 27 | bluechi_test: BluechiTest, bluechi_ctrl_default_config: BluechiControllerConfig 28 | ): 29 | 30 | bluechi_ctrl_default_config.allowed_node_names = [] 31 | bluechi_ctrl_default_config.log_target = expected_logtarget 32 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 33 | 34 | bluechi_test.run(exec) 35 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-runs-tcp-and-socket-activation-parallel/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test that the systemd socket unit for bluechi-controller will start the service 2 | and it listens on the Unix Domain Socket passed to it as well as on TCP 3 | id: 62705aa9-a422-4280-9d93-bfa03ea749a4 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-runs-uds-and-socket-activation-parallel/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test that the systemd socket unit for bluechi-controller will start the service, 2 | listens on the Unix Domain Socket passed to it and handles the collision 3 | id: 9c27c73d-9bd7-4253-aedd-58401d907d46 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-set-loglevel-invalid/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test setting an invalid log level on controller is rejected 2 | id: 9d0e41c4-2c9a-4613-ba66-23394ef13a46 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-set-loglevel-invalid/test_bluechi_controller_set_loglevel_invalid.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | from typing import Dict 7 | 8 | from bluechi_test.config import BluechiControllerConfig 9 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 10 | from bluechi_test.test import BluechiTest 11 | 12 | 13 | def exec(ctrl: BluechiControllerMachine, _: Dict[str, BluechiAgentMachine]): 14 | 15 | result, _ = ctrl.bluechictl.set_log_level_on_controller("INF", check_result=False) 16 | # call to set invalid loglevel should fail 17 | assert result != 0 18 | 19 | 20 | def test_bluechi_controller_set_loglevel_invalid( 21 | bluechi_test: BluechiTest, bluechi_ctrl_default_config: BluechiControllerConfig 22 | ): 23 | 24 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 25 | bluechi_test.run(exec) 26 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-set-loglevel/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test setting log level for controller 2 | id: eaee4c18-64a3-4d98-b6e4-be40a1d2789f 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-start-transient-unit/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test starting a transient unit 2 | id: c683d707-9e11-49e2-8b87-d759ae676f52 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-controller-start-transient-unit/test_bluechi_controller_start_transient_unit.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import os 7 | from typing import Dict 8 | 9 | from bluechi_test.config import BluechiAgentConfig, BluechiControllerConfig 10 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 11 | from bluechi_test.test import BluechiTest 12 | 13 | 14 | def exec(ctrl: BluechiControllerMachine, _: Dict[str, BluechiAgentMachine]): 15 | result, output = ctrl.run_python(os.path.join("python", "start_transient.py")) 16 | if result != 0: 17 | raise Exception(output) 18 | 19 | 20 | def test_bluechi_controller_start_transient_unit( 21 | bluechi_test: BluechiTest, 22 | bluechi_ctrl_default_config: BluechiControllerConfig, 23 | bluechi_node_default_config: BluechiAgentConfig, 24 | ): 25 | node_foo_cfg = bluechi_node_default_config.deep_copy() 26 | node_foo_cfg.node_name = "node-foo" 27 | 28 | bluechi_ctrl_default_config.allowed_node_names = ["node-foo"] 29 | 30 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 31 | bluechi_test.add_bluechi_agent_config(node_foo_cfg) 32 | 33 | bluechi_test.run(exec) 34 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-daemon-reload/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test bluechictl daemon-reload. This test will send an unrunble test will 2 | fail at start but then will be change and update with daemon-reload 3 | id: bd48467d-3c47-491e-ace0-39d146b23ec1 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-enable-disable-service/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a disabled systemd service can be enabled and then disabled again using bluechictl 2 | id: e3ec3cb3-1010-4205-9b99-507233c6a8f1 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-freeze-and-thaw-service/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a systemd service can be frozen and thawed using bluechictl 2 | id: 0744f5b6-cc47-4f1a-bdb2-cb3bcbca0439 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-heartbeat-agent-disconnected/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the agent gets disconnected when did not receive heartbeat since 2 | threshold from controller 3 | id: 9ea390ed-9ba9-4961-838b-ad44cbe9f0b1 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-heartbeat-agent-disconnected/python/is_agent_disconnected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import time 7 | import unittest 8 | 9 | from dasbus.loop import EventLoop 10 | from dasbus.typing import Variant 11 | 12 | from bluechi.api import Agent 13 | 14 | 15 | class TestAgentIsDisconnected(unittest.TestCase): 16 | 17 | state = None 18 | timestamp = None 19 | 20 | def test_agent_is_disconnected(self): 21 | loop = EventLoop() 22 | 23 | def on_state_change(state: Variant): 24 | self.timestamp = round(time.time() * 1000000) 25 | self.state = state.get_string() 26 | loop.quit() 27 | 28 | agent = Agent() 29 | assert agent.status == "online" 30 | 31 | agent.on_status_changed(on_state_change) 32 | timestamp = agent.last_seen_timestamp 33 | 34 | loop.run() 35 | 36 | # verify that the agent is disconnected after more than 37 | # ControllerHeartbeatThreshold seconds have elapsed 38 | assert self.timestamp - timestamp > 6000000 39 | assert self.state == "offline" 40 | 41 | 42 | if __name__ == "__main__": 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-heartbeat-disabled/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if default configuration of controller disables periodic heartbeat of 2 | the controller 3 | id: a04517f6-8be1-468b-8dc0-f9674690f73f 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-heartbeat-disabled/python/is_node_connected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import time 7 | import unittest 8 | 9 | from dasbus.typing import Variant 10 | 11 | from bluechi.api import Node 12 | 13 | 14 | class TestNodeIsConnected(unittest.TestCase): 15 | def test_node_is_connected(self): 16 | 17 | def on_state_change(state: Variant): 18 | assert False 19 | 20 | n = Node("node-foo") 21 | assert n.status == "online" 22 | 23 | n.on_status_changed(on_state_change) 24 | timestamp = n.last_seen_timestamp 25 | 26 | # verify that the node remains connected and LastSeenTimespamp is not 27 | # updated after more than NodeHeartbeatThreshold seconds have elapsed 28 | time.sleep(10) 29 | 30 | assert n.status == "online" 31 | assert n.last_seen_timestamp == timestamp 32 | 33 | 34 | if __name__ == "__main__": 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-heartbeat-node-disconnected/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the node gets disconnected when did not receive heartbeat since 2 | threshold from node 3 | id: 0b087ba3-25fc-46b0-9c01-31bc2edf5209 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-heartbeat-node-disconnected/python/is_node_disconnected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import time 7 | import unittest 8 | 9 | from dasbus.loop import EventLoop 10 | from dasbus.typing import Variant 11 | 12 | from bluechi.api import Node 13 | 14 | 15 | class TestNodeIsDisconnected(unittest.TestCase): 16 | 17 | node_state = None 18 | timestamp = None 19 | 20 | def test_node_is_disconnected(self): 21 | loop = EventLoop() 22 | 23 | def on_state_change(state: Variant): 24 | self.timestamp = round(time.time() * 1000000) 25 | self.node_state = state.get_string() 26 | loop.quit() 27 | 28 | n = Node("node-foo") 29 | assert n.status == "online" 30 | 31 | n.on_status_changed(on_state_change) 32 | timestamp = n.last_seen_timestamp 33 | 34 | loop.run() 35 | 36 | # verify that the node is disconnected after more than 37 | # NodeHeartbeatThreshold seconds have elapsed 38 | assert self.timestamp - timestamp > 6000000 39 | assert self.node_state == "offline" 40 | 41 | 42 | if __name__ == "__main__": 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-help-option-provided/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi-controller, bluechi-agent and bluechictl provides --help option 2 | id: 16b85131-9616-43e3-8c90-905671a953a3 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-internal-hello/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test internal peer dbus hello method on controller 2 | id: eafc86bc-e69c-47a4-9ca9-907f7a6201fa 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-internal-hello/python/call_internal_hello.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from dasbus.connection import AddressedMessageBus 9 | 10 | node = "node-foo" 11 | 12 | 13 | class TestListenerAddedAsPeer(unittest.TestCase): 14 | def test_call_internal_hello(self): 15 | 16 | port = "" 17 | with open("/tmp/port", "r") as f: 18 | port = f.read().strip() 19 | assert port is not None 20 | 21 | # connect to controller locally 22 | peer_bus = AddressedMessageBus(f"tcp:host=127.0.0.1,port={port}") 23 | peer_proxy = peer_bus.get_proxy( 24 | service_name="org.eclipse.bluechi", 25 | object_path="/org/freedesktop/DBus", 26 | interface_name="org.freedesktop.DBus", 27 | ) 28 | resp = peer_proxy.Hello() 29 | assert resp == ":1.0" 30 | 31 | 32 | if __name__ == "__main__": 33 | unittest.main() 34 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-internal-hello/test_bluechi_internal_hello.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import os 7 | from typing import Dict 8 | 9 | from bluechi_test.config import BluechiControllerConfig 10 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 11 | from bluechi_test.test import BluechiTest 12 | 13 | NODE_FOO = "node-foo" 14 | 15 | 16 | def exec(ctrl: BluechiControllerMachine, nodes: Dict[str, BluechiAgentMachine]): 17 | 18 | # pass port information to machine 19 | ctrl.create_file(os.path.join("/", "tmp"), "port", ctrl.config.port) 20 | 21 | result, output = ctrl.run_python(os.path.join("python", "call_internal_hello.py")) 22 | if result != 0: 23 | raise Exception(output) 24 | 25 | 26 | def test_bluechi_internal_hello( 27 | bluechi_test: BluechiTest, bluechi_ctrl_default_config: BluechiControllerConfig 28 | ): 29 | 30 | bluechi_ctrl_default_config.allowed_node_names = [NODE_FOO] 31 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 32 | 33 | bluechi_test.run(exec) 34 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-invalid-port/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi can handle invalid values for the port in the configuration properly 2 | id: f72ec296-bb6a-4f34-b9ef-5317fb097bdf 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-is-online-agent-monitor/main.fmf: -------------------------------------------------------------------------------- 1 | summary: --monitor keeps monitoring as long as agent is online and exits if it detects an offline state. 2 | id: f35a0bb4-3788-45e2-bab1-2ee96d396da9 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-is-online-agent-wait/main.fmf: -------------------------------------------------------------------------------- 1 | summary: test bluechi-is-online agent --wait command 2 | id: afde18db-d923-4596-8a2f-c0eb8fab2a15 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-is-online-agent/main.fmf: -------------------------------------------------------------------------------- 1 | summary: On the agent machine test the connection of the agent to the controller 2 | id: 4af7b1da-39e7-46d5-bf00-586a8df17f1b 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-is-online-node-monitor/main.fmf: -------------------------------------------------------------------------------- 1 | summary: --monitor keeps monitoring as long as node is online and exits if it detects an offline state. 2 | id: 929f11ba-00ab-4c4f-8614-e1aebcbaa96d 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-is-online-node-wait/main.fmf: -------------------------------------------------------------------------------- 1 | summary: test bluechi-is-online node --wait command 2 | id: 0fcb263e-8e6b-493d-91c7-e02da39737f0 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-is-online-node/main.fmf: -------------------------------------------------------------------------------- 1 | summary: on the controller machine test the connection of the given node to the controller 2 | id: fa5a2ff8-fbea-4a0c-8106-a8cb2c295581 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-is-online-system-monitor/main.fmf: -------------------------------------------------------------------------------- 1 | summary: --monitor keeps monitoring as long as system is online and exits if it detects an offline state. 2 | id: 3136865b-c3c1-40aa-a555-de75c6038707 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-is-online-system-wait/main.fmf: -------------------------------------------------------------------------------- 1 | summary: test bluechi-is-online system --wait command 2 | id: e41346d9-b8c0-4ac1-81ce-3dfc135e6549 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-is-online-system/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test that the system check of bluechi-is-online works as expected for connections of all nodes to the controller 2 | id: 353da9bd-1a92-431a-8f32-e4940b8aa3e2 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-job-cancel/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a job can be canceled 2 | id: 46f90231-3b9f-4a00-b58d-44092495d600 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-kill-unit/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test killing processes of (i.e. sending a signal to) a units on a node. 2 | id: 0051e95c-7bdf-4171-af91-d9e1fd16e90f 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-list-unit-files-on-a-node/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi list-unit-files returns the same list of unit files from 2 | a specific node which can be gathered by running systemctl on the node 3 | id: e055857b-a90c-4d0a-80b2-437f62fdf7c2 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-list-unit-files-on-all-nodes/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi list-unit-files returns the same list of unit files from all 2 | nodes which can be gathered by running systemctl on each node 3 | id: f3b40b8e-756b-4508-9d37-f21a1fac59ee 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-list-units-on-a-node/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi list-nodes returns the same list of units from a specific 2 | node which can be gathered by running systemctl on the node 3 | id: 62225c45-9654-4f19-8175-c6de1a0a70e0 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-list-units-on-all-nodes/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi list-nodes returns the same list of units from all 2 | nodes which can be gathered by running systemctl on each node 3 | id: efbf2397-de69-4f67-a8a8-b2c10bc68c13 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-long-multiline-config-setting/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi can properly parse a very long setting value spread across multiple lines, e.g. for the allowed node names 2 | id: 9a157fb9-71b0-4293-99b2-fd7a4f21b4ba 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-long-multiline-config-setting/test_long_multiline_config_setting.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | from typing import Dict 7 | 8 | from bluechi_test.config import BluechiControllerConfig 9 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 10 | from bluechi_test.test import BluechiTest 11 | 12 | 13 | def startup_verify(ctrl: BluechiControllerMachine, _: Dict[str, BluechiAgentMachine]): 14 | ctrl.wait_for_unit_state_to_be("bluechi-controller", "active") 15 | 16 | 17 | def test_long_multiline_config_setting( 18 | bluechi_test: BluechiTest, bluechi_ctrl_default_config: BluechiControllerConfig 19 | ): 20 | config = bluechi_ctrl_default_config.deep_copy() 21 | for i in range(150): 22 | config.allowed_node_names.append(f"node-{i}") 23 | 24 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 25 | 26 | bluechi_test.run(startup_verify) 27 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-monitor-service/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a restarted service is properly monitored by bluechictl monitor 2 | id: 9d347466-3cf8-462a-b71e-9d4ec9d391ec 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-no-param-provided/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechictl without any parameters shows help message and then exits 2 | with error 3 | id: 1c40b19a-0e1c-47b0-97af-dfb74f26fde8 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-no-param-provided/test_no_param_provided.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | from typing import Dict 7 | 8 | from bluechi_test.config import BluechiControllerConfig 9 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 10 | from bluechi_test.test import BluechiTest 11 | 12 | 13 | def check_help_option( 14 | ctrl: BluechiControllerMachine, _: Dict[str, BluechiAgentMachine] 15 | ): 16 | result, out = ctrl.exec_run("/usr/bin/bluechictl") 17 | assert result != 0 18 | assert "Usage" in out 19 | 20 | 21 | def test_help_option_provided( 22 | bluechi_test: BluechiTest, bluechi_ctrl_default_config: BluechiControllerConfig 23 | ): 24 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 25 | 26 | bluechi_test.run(check_help_option) 27 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-node-property-peer-ip/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if node peer ip is set correctly for a connected and disconnected node 2 | id: 34d54fa9-c5fe-40f5-8623-d98254d47d98 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-node-property-peer-ip/python/has_node_ip.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Node 9 | 10 | 11 | class TestNodeHasPeerIP(unittest.TestCase): 12 | def test_node_has_peer_ip(self): 13 | n = Node("node-foo") 14 | assert n.peer_ip != "" 15 | 16 | 17 | if __name__ == "__main__": 18 | unittest.main() 19 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-node-property-peer-ip/python/is_node_connected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import time 7 | import unittest 8 | 9 | from bluechi.api import Node 10 | 11 | 12 | class TestNodeIsConnected(unittest.TestCase): 13 | def test_node_is_connected(self): 14 | n = Node("node-foo") 15 | assert n.status == "online" 16 | 17 | # verify that the last seen timestamp is updated with each heartbeat 18 | timestamp = n.last_seen_timestamp 19 | time.sleep(2.5) 20 | assert n.last_seen_timestamp > timestamp 21 | 22 | 23 | if __name__ == "__main__": 24 | unittest.main() 25 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-node-status/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if node status is reported correctly using bluechictl 2 | id: 881263d3-b71b-4cce-a5d8-05fb61eac726 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-nodes-statuses/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if nodes statuses are reported correctly using bluechictl 2 | id: 44b0d11e-fcad-4523-acf7-ff0c0421501e 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-reload-unit/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test reload service 2 | id: bd996ecc-c7f8-40ac-a5fc-4adf0e714934 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-request-cancel/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if shutting down BlueChi also cancels all pending requests like start 2 | units 3 | id: 69e0b0d8-df11-4d67-8b14-ab2e8fa187e0 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-reset-failed-node/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test resetting the failed state of all units on a node via D-Bus API call. 2 | id: fc5db6a7-1367-450b-b674-35b9541d4f3e 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-reset-failed-units/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test resetting the failed state of a specific on a node via D-Bus API call. 2 | id: 6c67e96d-db4b-4a54-980c-287e33450abf 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-reset-failed/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test resetting the failed state of all units on a node via D-Bus API call. 2 | id: baaf096a-ad2e-45c5-b2d5-530c0b5fdce0 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-restart-unit/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a service on a node is restarted using bluechictl restart 2 | id: c34ac2d4-abe3-43df-8e54-44c82b79bb45 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-service-startup/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi service started successfully 2 | id: bd3fd928-b5d8-4bb2-9df4-f59824316c19 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-service-startup/test_service_startup.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | from typing import Dict 7 | 8 | from bluechi_test.config import BluechiControllerConfig 9 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 10 | from bluechi_test.test import BluechiTest 11 | 12 | 13 | def startup_verify(ctrl: BluechiControllerMachine, _: Dict[str, BluechiAgentMachine]): 14 | ctrl.wait_for_unit_state_to_be("bluechi-controller", "active") 15 | 16 | 17 | def test_controller_startup( 18 | bluechi_test: BluechiTest, bluechi_ctrl_default_config: BluechiControllerConfig 19 | ): 20 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 21 | 22 | bluechi_test.run(startup_verify) 23 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-unsupported-option-error/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi-controller, bluechi-agent, bluechi-proxy and 2 | bluechictl show help and return error when unsupported command line 3 | option is provided 4 | id: e07fc44e-2bf8-4798-a24e-cba796c10e10 5 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechi-version-option-provided/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechi-controller, bluechi-agent and bluechictl provides --version option 2 | id: e5a0fc8f-7254-4e57-a312-f3ce811d8086 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechictl-is-enabled/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if bluechictl is-enabled returns the same enablement status of a specific 2 | node as running systemctl is-enabled on the node for all unit files 3 | id: 387cdca2-fa98-4c35-8bd0-352572a7e206 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechictl-metrics/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test bluechictl metrics functionality 2 | id: 1683b338-e649-46b3-9888-e04c8aaa06cd 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechictl-monitor-unit-created-removed/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test that bluechictl monitor can receive UnitCreated and UnitRemoved signals 2 | id: 1becd1cf-6f07-4bbb-9b16-ec438bbb6c22 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechictl-set-get-default-target/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test bluechictl get-default and set-default commands 2 | id: 6cfa53b6-7429-43fd-a9b5-ff59e98b7408 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechictl-status-watch-service/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test client watch option by running in the controller container "bluechictl status" of a spasific node in the agent container and watching the status change when the service is down and up 2 | id: bb9d4394-bd53-4d36-b8ba-ee91697c4810 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/bluechictl-status-watch/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test bluechictl status watch functionality 2 | id: f65270d9-bd94-4519-9dc2-4d345afa6df7 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/main.fmf: -------------------------------------------------------------------------------- 1 | tier: 0 2 | -------------------------------------------------------------------------------- /tests/tests/tier0/metrics-enable-and-disable/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if metrics reporting is enabled and disabled correctly 2 | id: ed71f395-b5f9-44a2-abfb-738c77e0539c 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/metrics-start-unit/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if start unit metric signals are emitted when metrics are enabled and 2 | a unit is started 3 | id: dd1d3f60-b313-41a0-b9cf-2ba223ee792f 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-agent-loses-connection/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the bluechi agent emits a status changed signal when it disconnects from the controller, e.g. when the controller goes down 2 | id: 7b5c59d0-f40e-4b29-b7c9-4fdeef9d079d 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-agent-loses-connection/python/is_agent_connected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Agent 9 | 10 | # Test to verify that the agent on the node is connected to the controller 11 | # and the properties for status and disconnected timestamp are set 12 | 13 | 14 | class TestAgentIsConnected(unittest.TestCase): 15 | def test_agent_is_connected(self): 16 | agent = Agent() 17 | assert agent.status == "online" 18 | assert agent.disconnect_timestamp == 0 19 | 20 | 21 | if __name__ == "__main__": 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-listener-added-as-peer/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a listener on a monitor does receive signals from it when added as peer 2 | id: 624ba8ae-cf8e-4b17-a8c5-bb09a47ae507 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-listener-added-more-than-once/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a listener on a monitor can only be added once added 2 | id: 5e694ded-ca05-48f9-94d4-c801e9595f5e 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-listener-not-added-as-peer/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a listener on a monitor does not receive signals from it when not 2 | added 3 | id: 7c84300a-4cd7-4184-8b75-5b574b8c3037 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-listener-owner-added-as-peer/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the listener to add on a monitor is the owner will be rejected added 2 | id: d5bb97f6-8832-44b8-977b-7bb3089b36ed 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-listener-owner-added-as-peer/python/added_owner_as_peer.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from dasbus.error import DBusError 9 | 10 | from bluechi.api import Controller, Monitor 11 | 12 | node = "node-foo" 13 | service = "simple.service" 14 | 15 | 16 | class TestListenerAddedIsOwner(unittest.TestCase): 17 | def test_listener_added_is_owner(self): 18 | 19 | mgr = Controller() 20 | monitor_path = mgr.create_monitor() 21 | monitor = Monitor(monitor_path) 22 | 23 | with self.assertRaises(DBusError): 24 | monitor.add_peer(mgr.bus.connection.get_unique_name()) 25 | 26 | 27 | if __name__ == "__main__": 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-listener-removed-as-peer/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a listener on a monitor does receive remove signal, but no other signals after removing it as peer 2 | id: b7b061ec-7a6b-495b-aef7-b791fb9eb251 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-multiple-nodes-and-units/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a montor with a subscription to a list of units on a single node receives the relevant signals, but none from a different node with the same unit 2 | id: 0d86b4bb-8e92-488a-8a17-bef9cfe1d2ce 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-node-disconnect/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the bluechi controller emits a message when a bluechi-agent disconnects 2 | id: 5f7b55f6-3b12-48e7-8462-dddc1e8af598 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-node-reconnect/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the bluechi-agent automatically reconnects on a successful heartbeat after the controller has been stopped and restarted 2 | id: 7db7738e-b1bf-458d-896a-5633b005d4dd 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-node-reconnect/python/is_node_connected.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import time 7 | import unittest 8 | 9 | from bluechi.api import Node 10 | 11 | 12 | class TestNodeIsConnected(unittest.TestCase): 13 | def test_node_is_connected(self): 14 | n = Node("node-foo") 15 | assert n.status == "online" 16 | 17 | # verify that the last seen timestamp is updated with each heartbeat 18 | timestamp = n.last_seen_timestamp 19 | time.sleep(2) 20 | assert n.last_seen_timestamp > timestamp 21 | 22 | 23 | if __name__ == "__main__": 24 | unittest.main() 25 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-open-close/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a monitor can be created and closed successfully 2 | id: 0df54792-aee3-4b66-8809-1a4b2b6d70b4 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-open-close/python/monitor.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from dasbus.error import DBusError 9 | 10 | from bluechi.api import Controller, Monitor 11 | 12 | # Subscribing to a closed monitor should result in a DBusError since the monitor has removed. 13 | # In this test we first subscribe to an open monitor to verify everything works, then close 14 | # the monitor and expect an DBusError when subscribing on a closed monitor. 15 | 16 | 17 | class TestOpenClose(unittest.TestCase): 18 | def test_open_close(self): 19 | mgr = Controller() 20 | monitor_path = mgr.create_monitor() 21 | monitor = Monitor(monitor_path=monitor_path) 22 | monitor.subscribe("not-important-node", "not-important-unit") 23 | monitor.close() 24 | with self.assertRaises(DBusError): 25 | monitor.subscribe("not-important-node-2", "not-important-unit-2") 26 | 27 | 28 | if __name__ == "__main__": 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-open-close/test_monitor_open_close.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import os 7 | from typing import Dict 8 | 9 | from bluechi_test.config import BluechiAgentConfig, BluechiControllerConfig 10 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 11 | from bluechi_test.test import BluechiTest 12 | 13 | 14 | def exec(ctrl: BluechiControllerMachine, nodes: Dict[str, BluechiAgentMachine]): 15 | result, output = ctrl.run_python(os.path.join("python", "monitor.py")) 16 | 17 | if result != 0: 18 | raise Exception(output) 19 | 20 | 21 | def test_monitor_open_close( 22 | bluechi_test: BluechiTest, 23 | bluechi_ctrl_default_config: BluechiControllerConfig, 24 | bluechi_node_default_config: BluechiAgentConfig, 25 | ): 26 | 27 | bluechi_node_default_config.node_name = "node-foo" 28 | bluechi_ctrl_default_config.allowed_node_names = [ 29 | bluechi_node_default_config.node_name 30 | ] 31 | 32 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 33 | bluechi_test.add_bluechi_agent_config(bluechi_node_default_config) 34 | 35 | bluechi_test.run(exec) 36 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-specific-node-and-unit/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if all signals for a subscription on a specific node and unit are emitted 2 | id: 4fb7abd3-fa4a-47ad-9c9e-a59c39da7f6c 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-system-status-ctrl-stop/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the system status changed signal is being emitted when the controller 2 | is stopped 3 | id: accfdfc5-31c7-4fda-b549-e3c43da0b9dc 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-system-status-ctrl-stop/python/system-monitor.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import signal 7 | import sys 8 | 9 | from dasbus.loop import EventLoop 10 | from dasbus.typing import Variant 11 | 12 | from bluechi.api import Controller 13 | 14 | 15 | def sig_handler(_signo, _stack_frame): 16 | sys.exit(0) 17 | 18 | 19 | signal.signal(signal.SIGTERM, sig_handler) 20 | signal.signal(signal.SIGINT, sig_handler) 21 | 22 | try: 23 | f = open("/tmp/events", "w") 24 | 25 | def on_system_status_changed(status: Variant): 26 | con_status = status.get_string() 27 | f.write(f"{con_status},") 28 | f.flush() 29 | print(con_status) 30 | 31 | loop = EventLoop() 32 | 33 | mgr = Controller() 34 | mgr.on_status_changed(on_system_status_changed) 35 | 36 | loop.run() 37 | finally: 38 | f.close() 39 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-system-status/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the system status changed signal is being emitted when nodes disconnect 2 | and reconnect 3 | id: 96615a39-229f-4083-8c7d-cb0c540ca598 4 | tag: [testing-farm-container] 5 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-system-status/python/system-monitor.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import signal 7 | import sys 8 | 9 | from dasbus.loop import EventLoop 10 | from dasbus.typing import Variant 11 | 12 | from bluechi.api import Controller 13 | 14 | 15 | def sig_handler(_signo, _stack_frame): 16 | sys.exit(0) 17 | 18 | 19 | signal.signal(signal.SIGTERM, sig_handler) 20 | signal.signal(signal.SIGINT, sig_handler) 21 | 22 | try: 23 | f = open("/tmp/events", "w") 24 | 25 | def on_system_status_changed(status: Variant): 26 | con_status = status.get_string() 27 | f.write(f"{con_status},") 28 | f.flush() 29 | print(con_status) 30 | 31 | loop = EventLoop() 32 | 33 | mgr = Controller() 34 | mgr.on_status_changed(on_system_status_changed) 35 | 36 | loop.run() 37 | finally: 38 | f.close() 39 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-unsubscribe/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a subscription on a monitor can be created and closed successfully 2 | id: 219ae7cf-7be1-4f93-bd1f-6844e464e273 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-wildcard-node-reconnect/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the proper virtual signals are emitted when a monitor with wildcard subscription is active and a node disconnects and reconnects again 2 | id: 071d8a13-aee6-4dc0-9a91-0fb9a2e38a93 3 | tag: [testing-farm-container] 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/monitor-wildcard-unit-changes/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the proper signals are emitted when a monitor with wildcard subscription is active 2 | id: a6f2cc45-731f-467d-abb0-52c4147963fb 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/properties-get/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if the properties for a systemd unit can be retrieved 2 | id: 0157e8aa-56bc-46ca-8971-41b00adf0877 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/properties-get/python/get_properties.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Node 9 | 10 | 11 | class TestGetProperties(unittest.TestCase): 12 | def test_get_properties(self): 13 | node_foo = Node("node-foo") 14 | props = node_foo.get_unit_properties( 15 | "bluechi-agent.service", 16 | "org.freedesktop.systemd1.Service", 17 | ) 18 | 19 | assert len(props) > 0 20 | # check some properties as example 21 | assert props["Type"].get_string() == "simple" 22 | assert not props["RemainAfterExit"].get_boolean() 23 | 24 | 25 | if __name__ == "__main__": 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /tests/tests/tier0/properties-get/test_properties_get.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import os 7 | from typing import Dict 8 | 9 | from bluechi_test.config import BluechiAgentConfig, BluechiControllerConfig 10 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 11 | from bluechi_test.test import BluechiTest 12 | 13 | 14 | def exec(ctrl: BluechiControllerMachine, nodes: Dict[str, BluechiAgentMachine]): 15 | result, output = ctrl.run_python(os.path.join("python", "get_properties.py")) 16 | if result != 0: 17 | raise Exception(output) 18 | 19 | 20 | def test_properties_get( 21 | bluechi_test: BluechiTest, 22 | bluechi_ctrl_default_config: BluechiControllerConfig, 23 | bluechi_node_default_config: BluechiAgentConfig, 24 | ): 25 | 26 | bluechi_node_default_config.node_name = "node-foo" 27 | bluechi_ctrl_default_config.allowed_node_names = [ 28 | bluechi_node_default_config.node_name 29 | ] 30 | 31 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 32 | bluechi_test.add_bluechi_agent_config(bluechi_node_default_config) 33 | 34 | bluechi_test.run(exec) 35 | -------------------------------------------------------------------------------- /tests/tests/tier0/property-get/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a property value for a systemd unit can be retrieved 2 | id: 1e3ce729-8e6e-4263-8644-b0375e79f1bd 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/property-get/python/get_property.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Node 9 | 10 | 11 | class TestGetProperty(unittest.TestCase): 12 | def test_get_property(self): 13 | node_foo = Node("node-foo") 14 | cpu_weight = node_foo.get_unit_property( 15 | "bluechi-agent.service", "org.freedesktop.systemd1.Service", "CPUWeight" 16 | ) 17 | 18 | assert cpu_weight.get_uint64() > 0 19 | 20 | 21 | if __name__ == "__main__": 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /tests/tests/tier0/property-get/test_property_get.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import os 7 | from typing import Dict 8 | 9 | from bluechi_test.config import BluechiAgentConfig, BluechiControllerConfig 10 | from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine 11 | from bluechi_test.test import BluechiTest 12 | 13 | 14 | def exec(ctrl: BluechiControllerMachine, nodes: Dict[str, BluechiAgentMachine]): 15 | result, output = ctrl.run_python(os.path.join("python", "get_property.py")) 16 | if result != 0: 17 | raise Exception(output) 18 | 19 | 20 | def test_property_get( 21 | bluechi_test: BluechiTest, 22 | bluechi_ctrl_default_config: BluechiControllerConfig, 23 | bluechi_node_default_config: BluechiAgentConfig, 24 | ): 25 | 26 | bluechi_node_default_config.node_name = "node-foo" 27 | bluechi_ctrl_default_config.allowed_node_names = [ 28 | bluechi_node_default_config.node_name 29 | ] 30 | 31 | bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) 32 | bluechi_test.add_bluechi_agent_config(bluechi_node_default_config) 33 | 34 | bluechi_test.run(exec) 35 | -------------------------------------------------------------------------------- /tests/tests/tier0/property-set/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if a property value for a systemd unit can be set 2 | id: 47ad938f-5f3b-467e-997d-ebf9d028b81d 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/property-set/python/set_property.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Contributors to the Eclipse BlueChi project 3 | # 4 | # SPDX-License-Identifier: LGPL-2.1-or-later 5 | 6 | import unittest 7 | 8 | from bluechi.api import Node, Variant 9 | 10 | 11 | class TestSetProperty(unittest.TestCase): 12 | def test_set_property(self): 13 | node_foo = Node("node-foo") 14 | 15 | unit_description = node_foo.get_unit_property( 16 | "simple.service", "org.freedesktop.systemd1.Unit", "Description" 17 | ) 18 | assert unit_description.get_string() == "Just being true once" 19 | 20 | v = Variant("s", "I changed") 21 | node_foo.set_unit_properties("simple.service", False, [("Description", v)]) 22 | new_unit_description = node_foo.get_unit_property( 23 | "simple.service", "org.freedesktop.systemd1.Unit", "Description" 24 | ) 25 | 26 | assert new_unit_description.get_string() == "I changed" 27 | 28 | 29 | if __name__ == "__main__": 30 | unittest.main() 31 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-denied-by-default/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if proxy services from one node to another are denied by default 2 | id: a52188d1-02dd-4430-801d-e29eaec217cd 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-fails-on-execstart/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if proxy service fails on failure of ExecStart of dependency service 2 | id: 4ef7c787-e59e-4ac1-8d55-20b9c4017036 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-fails-on-non-existent-node/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if proxy service fails on requesting dependency service on non-existent 2 | node 3 | id: 6cb0f785-92f3-4aab-9632-b9a0d8c1aa23 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-fails-on-non-existent-service/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if proxy service fails on requesting non-existent dependency service 2 | id: 20a2e52d-b09a-49ea-ad22-18168ed06614 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-fails-on-typo-in-file/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if proxy service fails if dependency service can't be loaded due to typo 2 | id: 240fcd55-a436-4301-97c6-f4d6426811a9 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-multiple-services-multiple-nodes/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test proper lifetimes of all services when multiple services on multiple nodes request the same service on the same node 2 | id: 4b5a0d32-4b85-404d-9a02-f58531bf1957 3 | tag: [testing-farm-container] 4 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-multiple-services-one-node/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test proper lifetimes of all services when multiple services on the same node request the same service on the same node 2 | id: b5db1d85-811e-497a-8dd5-c698051839c4 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-propagate-target-service-failure/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test Propagating the failure of the requested service by adding requested service to node-bar and the requesting to node-foo. 2 | id: bb9d4394-bd53-4d36-b8ba-ee91697c4850 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-start/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if requesting.service's dependency on simple.service from node bar can be resolved 2 | id: cad16b0d-ed2a-42bd-b6e7-d6cd7a00ae23 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-stop-bluechi-dep/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if stopping the bluechi-dep service results in a stopped bluechi-proxy service, but both actual services are still running 2 | id: cb13e1ed-d692-4466-9ff8-389c90c29454 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-stop-requesting-with-unneeded/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if stopping the requesting service results in a stopped dependency service if its marked with StopWhenUnneeded 2 | id: 18cca4fa-953c-4436-a22c-85ed51122fab 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-stop-requesting/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if stopping the requesting service results in a stopped bluechi-proxy and bluechi-dep service, but dependency service is still running 2 | id: 6ebd2116-eb64-43b8-b346-8eb632122549 3 | -------------------------------------------------------------------------------- /tests/tests/tier0/proxy-service-stop-target/main.fmf: -------------------------------------------------------------------------------- 1 | summary: Test if stopping the dependency service results in a stopped bluechi-dep and bluechi-proxy service, but the requesting service is still running 2 | id: b005b0fd-4a8e-492b-b916-300c5bae1d02 3 | -------------------------------------------------------------------------------- /tests/tools/FFI/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is **BlueChi Tester**, and its purpose is to create tests that can disrupt or diminish the functionality of the BlueChi controller using DBus interface. 4 | 5 | Prior to employing the BlueChi Tester, ensure that the BlueChi controller contains a specific node name for the intended test in the AllowedNodeNames list. 6 | 7 | In the controller, utilize journald or stderr to keep track of the actions performed by this tool. 8 | 9 | Example of usage: 10 | 11 | ``` bash 12 | ./bluechi-tester \ 13 | --url="tcp:host=10.90.0.2,port=842" \ 14 | --nodename=control \ 15 | --signal="JobDone" \ 16 | --numbersignals=500 17 | ``` 18 | --------------------------------------------------------------------------------